fffiloni commited on
Commit
b3c9281
·
verified ·
1 Parent(s): ff4f0e7

refactor: deduplicate section logic and simplify activity flows

Browse files
Files changed (1) hide show
  1. app.py +330 -576
app.py CHANGED
@@ -937,7 +937,7 @@ def classify_paper_event(event: dict):
937
 
938
 
939
  # ============================================================
940
- # Upvotes activity fetch
941
  # ============================================================
942
  def empty_upvotes_state(selected_year: int):
943
  return empty_bucketed_activity_state(
@@ -972,9 +972,6 @@ def fetch_all_upvotes_activity(username: str, selected_year: int):
972
  )
973
 
974
 
975
- # ============================================================
976
- # Likes activity fetch
977
- # ============================================================
978
  def empty_likes_state(selected_year: int):
979
  return empty_bucketed_activity_state(
980
  selected_year=selected_year,
@@ -1008,9 +1005,6 @@ def fetch_all_likes_activity(username: str, selected_year: int):
1008
  )
1009
 
1010
 
1011
- # ============================================================
1012
- # Papers activity fetch
1013
- # ============================================================
1014
  def empty_papers_state(selected_year: int):
1015
  return empty_bucketed_activity_state(
1016
  selected_year=selected_year,
@@ -1183,100 +1177,24 @@ def render_metric_cards(
1183
  """
1184
 
1185
 
1186
- def render_idle_context_banner(
1187
- username: str,
1188
- profile: gr.OAuthProfile | None,
1189
- ):
1190
- username = (username or "").strip()
1191
  viewer = getattr(profile, "username", None) if profile else None
1192
-
1193
  if viewer:
1194
- if not username or username.lower() == viewer.lower():
1195
- return render_status_badge(
1196
- f"Logged in as <b>{html.escape(viewer)}</b> · Fetch your activity or enter another username"
1197
- )
1198
- return render_status_badge(
1199
- f"Logged in as <b>{html.escape(viewer)}</b> · Ready to fetch <b>{html.escape(username)}</b> · Public repos only"
1200
- )
1201
 
1202
- if username:
1203
- return render_status_badge(
1204
- f"Not logged in · Ready to fetch <b>{html.escape(username)}</b> · Public repos only"
1205
- )
1206
 
1207
- return render_status_badge("Not logged in · Enter a username to get started")
1208
-
1209
-
1210
- def render_invalid_username_banner(username: str, error_text: str | None = None):
1211
  username = (username or "").strip()
1212
  message = error_text or f"Username or org '{username}' was not found."
1213
  return render_status_badge(html.escape(message))
1214
 
1215
 
1216
- def render_context_banner(app_state: dict | None, profile: gr.OAuthProfile | None):
1217
- if not app_state or not app_state.get("username"):
1218
- return render_idle_context_banner("", profile)
1219
-
1220
- username = app_state["username"]
1221
- selected_year = int(app_state["selected_year"])
1222
- is_own = bool(app_state.get("is_own_profile", False))
1223
- can_toggle = bool(app_state.get("can_toggle_visibility", False))
1224
- viewer = getattr(profile, "username", None) if profile else None
1225
-
1226
- parts = []
1227
-
1228
- if viewer:
1229
- parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1230
- else:
1231
- parts.append("Not logged in")
1232
-
1233
- if viewer and username.lower() == viewer.lower():
1234
- parts.append("Viewing <b>your activity</b>")
1235
- else:
1236
- parts.append(f"Viewing <b>{html.escape(username)}</b>")
1237
-
1238
- parts.append(str(selected_year))
1239
-
1240
- if is_own and can_toggle:
1241
- parts.append("Private repos available")
1242
- else:
1243
- parts.append("Public repos only")
1244
-
1245
- return render_status_badge(" · ".join(parts))
1246
-
1247
-
1248
- def render_fetching_context_banner(
1249
- username,
1250
- selected_year,
1251
- profile: gr.OAuthProfile | None,
1252
- ):
1253
- username = (username or "").strip()
1254
- selected_year = int(selected_year)
1255
- viewer = getattr(profile, "username", None) if profile else None
1256
-
1257
- if not username:
1258
- return render_idle_context_banner("", profile)
1259
-
1260
- parts = []
1261
-
1262
- if viewer:
1263
- parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1264
- else:
1265
- parts.append("Not logged in")
1266
-
1267
- if viewer and username.lower() == viewer.lower():
1268
- parts.append("Fetching <b>your activity</b>")
1269
- parts.append(str(selected_year))
1270
- parts.append("Checking public and private repos")
1271
- else:
1272
- parts.append(f"Fetching <b>{html.escape(username)}</b>")
1273
- parts.append(str(selected_year))
1274
- parts.append("Checking public repos")
1275
-
1276
- return render_status_badge(" · ".join(parts))
1277
-
1278
-
1279
- def render_community_idle_banner(
1280
  username,
1281
  selected_year,
1282
  profile: gr.OAuthProfile | None,
@@ -1285,33 +1203,23 @@ def render_community_idle_banner(
1285
  selected_year = int(selected_year)
1286
  viewer = getattr(profile, "username", None) if profile else None
1287
 
1288
- parts = []
1289
- if viewer:
1290
- parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1291
- else:
1292
- parts.append("Not logged in")
1293
 
1294
  if not username:
1295
- parts.append("Enter a username to fetch community activity")
1296
  return render_status_badge(" · ".join(parts))
1297
 
1298
  if viewer and username.lower() == viewer.lower():
1299
- parts.append("Fetch your community activity or enter another username")
1300
- parts.append(str(selected_year))
1301
  else:
1302
- parts.append(f"Ready to fetch community activity for <b>{html.escape(username)}</b>")
1303
- parts.append(str(selected_year))
1304
 
 
1305
  return render_status_badge(" · ".join(parts))
1306
 
1307
 
1308
- def render_community_invalid_banner(username: str, error_text: str | None = None):
1309
- username = (username or "").strip()
1310
- message = error_text or f"Username or org '{username}' was not found."
1311
- return render_status_badge(html.escape(message))
1312
-
1313
-
1314
- def render_community_fetching_banner(
1315
  username,
1316
  selected_year,
1317
  profile: gr.OAuthProfile | None,
@@ -1321,140 +1229,107 @@ def render_community_fetching_banner(
1321
  viewer = getattr(profile, "username", None) if profile else None
1322
 
1323
  if not username:
1324
- return render_community_idle_banner("", selected_year, profile)
1325
 
1326
- parts = []
1327
- if viewer:
1328
- parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1329
- else:
1330
- parts.append("Not logged in")
1331
 
1332
  if viewer and username.lower() == viewer.lower():
1333
- parts.append("Fetching <b>your community activity</b>")
1334
  else:
1335
- parts.append(f"Fetching community activity for <b>{html.escape(username)}</b>")
1336
 
1337
  parts.append(str(selected_year))
1338
  return render_status_badge(" · ".join(parts))
1339
 
1340
 
1341
- def render_community_loaded_banner(
1342
- community_state: dict | None,
 
1343
  profile: gr.OAuthProfile | None,
1344
  ):
1345
- if not community_state or not community_state.get("username"):
1346
- year = community_state.get("selected_year", datetime.now().year) if community_state else datetime.now().year
1347
- return render_community_idle_banner("", year, profile)
1348
 
1349
- username = community_state["username"]
1350
- selected_year = int(community_state["selected_year"])
1351
  viewer = getattr(profile, "username", None) if profile else None
1352
 
1353
- parts = []
1354
- if viewer:
1355
- parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1356
- else:
1357
- parts.append("Not logged in")
1358
 
1359
  if viewer and username.lower() == viewer.lower():
1360
- parts.append("Viewing <b>your community activity</b>")
1361
  else:
1362
- parts.append(f"Viewing community activity for <b>{html.escape(username)}</b>")
1363
 
1364
  parts.append(str(selected_year))
1365
  return render_status_badge(" · ".join(parts))
1366
 
1367
 
1368
- def render_upvotes_idle_banner(
1369
- username,
1370
- selected_year,
 
 
1371
  profile: gr.OAuthProfile | None,
1372
  ):
1373
  username = (username or "").strip()
1374
- selected_year = int(selected_year)
1375
  viewer = getattr(profile, "username", None) if profile else None
1376
 
1377
- parts = []
1378
  if viewer:
1379
- parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1380
- else:
1381
- parts.append("Not logged in")
 
 
 
 
1382
 
1383
- if not username:
1384
- parts.append("Enter a username to fetch upvotes activity")
1385
- return render_status_badge(" · ".join(parts))
 
1386
 
1387
- if viewer and username.lower() == viewer.lower():
1388
- parts.append("Fetch your upvotes activity or enter another username")
1389
- parts.append(str(selected_year))
1390
- else:
1391
- parts.append(f"Ready to fetch upvotes activity for <b>{html.escape(username)}</b>")
1392
- parts.append(str(selected_year))
1393
 
1394
- return render_status_badge(" · ".join(parts))
1395
 
 
 
1396
 
1397
- def render_upvotes_invalid_banner(username: str, error_text: str | None = None):
1398
- username = (username or "").strip()
1399
- message = error_text or f"Username or org '{username}' was not found."
1400
- return render_status_badge(html.escape(message))
1401
 
 
 
 
1402
 
1403
- def render_upvotes_fetching_banner(
1404
- username,
1405
- selected_year,
1406
- profile: gr.OAuthProfile | None,
1407
- ):
1408
- username = (username or "").strip()
1409
- selected_year = int(selected_year)
1410
  viewer = getattr(profile, "username", None) if profile else None
1411
 
1412
- if not username:
1413
- return render_upvotes_idle_banner("", selected_year, profile)
1414
-
1415
  parts = []
 
1416
  if viewer:
1417
  parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1418
  else:
1419
  parts.append("Not logged in")
1420
 
1421
  if viewer and username.lower() == viewer.lower():
1422
- parts.append("Fetching <b>your upvotes activity</b>")
1423
  else:
1424
- parts.append(f"Fetching upvotes activity for <b>{html.escape(username)}</b>")
1425
 
1426
  parts.append(str(selected_year))
1427
- return render_status_badge(" · ".join(parts))
1428
-
1429
 
1430
- def render_upvotes_loaded_banner(
1431
- upvotes_state: dict | None,
1432
- profile: gr.OAuthProfile | None,
1433
- ):
1434
- if not upvotes_state or not upvotes_state.get("username"):
1435
- year = upvotes_state.get("selected_year", datetime.now().year) if upvotes_state else datetime.now().year
1436
- return render_upvotes_idle_banner("", year, profile)
1437
-
1438
- username = upvotes_state["username"]
1439
- selected_year = int(upvotes_state["selected_year"])
1440
- viewer = getattr(profile, "username", None) if profile else None
1441
-
1442
- parts = []
1443
- if viewer:
1444
- parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1445
- else:
1446
- parts.append("Not logged in")
1447
-
1448
- if viewer and username.lower() == viewer.lower():
1449
- parts.append("Viewing <b>your upvotes activity</b>")
1450
  else:
1451
- parts.append(f"Viewing upvotes activity for <b>{html.escape(username)}</b>")
1452
 
1453
- parts.append(str(selected_year))
1454
  return render_status_badge(" · ".join(parts))
1455
 
1456
 
1457
- def render_likes_idle_banner(
1458
  username,
1459
  selected_year,
1460
  profile: gr.OAuthProfile | None,
@@ -1463,173 +1338,93 @@ def render_likes_idle_banner(
1463
  selected_year = int(selected_year)
1464
  viewer = getattr(profile, "username", None) if profile else None
1465
 
 
 
 
1466
  parts = []
 
1467
  if viewer:
1468
  parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1469
  else:
1470
  parts.append("Not logged in")
1471
 
1472
- if not username:
1473
- parts.append("Enter a username to fetch likes activity")
1474
- return render_status_badge(" · ".join(parts))
1475
-
1476
  if viewer and username.lower() == viewer.lower():
1477
- parts.append("Fetch your likes activity or enter another username")
1478
  parts.append(str(selected_year))
 
1479
  else:
1480
- parts.append(f"Ready to fetch likes activity for <b>{html.escape(username)}</b>")
1481
  parts.append(str(selected_year))
 
1482
 
1483
  return render_status_badge(" · ".join(parts))
1484
 
1485
 
1486
- def render_likes_invalid_banner(username: str, error_text: str | None = None):
1487
- username = (username or "").strip()
1488
- message = error_text or f"Username or org '{username}' was not found."
1489
- return render_status_badge(html.escape(message))
 
1490
 
1491
 
1492
- def render_likes_fetching_banner(
1493
- username,
1494
- selected_year,
1495
- profile: gr.OAuthProfile | None,
1496
- ):
1497
- username = (username or "").strip()
1498
- selected_year = int(selected_year)
1499
- viewer = getattr(profile, "username", None) if profile else None
1500
 
1501
- if not username:
1502
- return render_likes_idle_banner("", selected_year, profile)
1503
 
1504
- parts = []
1505
- if viewer:
1506
- parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1507
- else:
1508
- parts.append("Not logged in")
1509
 
1510
- if viewer and username.lower() == viewer.lower():
1511
- parts.append("Fetching <b>your likes activity</b>")
1512
- else:
1513
- parts.append(f"Fetching likes activity for <b>{html.escape(username)}</b>")
1514
 
1515
- parts.append(str(selected_year))
1516
- return render_status_badge(" · ".join(parts))
1517
 
1518
 
1519
- def render_likes_loaded_banner(
1520
- likes_state: dict | None,
1521
- profile: gr.OAuthProfile | None,
1522
- ):
1523
- if not likes_state or not likes_state.get("username"):
1524
- year = likes_state.get("selected_year", datetime.now().year) if likes_state else datetime.now().year
1525
- return render_likes_idle_banner("", year, profile)
1526
 
1527
- username = likes_state["username"]
1528
- selected_year = int(likes_state["selected_year"])
1529
- viewer = getattr(profile, "username", None) if profile else None
1530
 
1531
- parts = []
1532
- if viewer:
1533
- parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1534
- else:
1535
- parts.append("Not logged in")
1536
 
1537
- if viewer and username.lower() == viewer.lower():
1538
- parts.append("Viewing <b>your likes activity</b>")
1539
- else:
1540
- parts.append(f"Viewing likes activity for <b>{html.escape(username)}</b>")
1541
 
1542
- parts.append(str(selected_year))
1543
- return render_status_badge(" · ".join(parts))
1544
 
1545
 
1546
- def render_papers_idle_banner(
1547
- username,
1548
- selected_year,
1549
- profile: gr.OAuthProfile | None,
1550
- ):
1551
- username = (username or "").strip()
1552
- selected_year = int(selected_year)
1553
- viewer = getattr(profile, "username", None) if profile else None
1554
 
1555
- parts = []
1556
- if viewer:
1557
- parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1558
- else:
1559
- parts.append("Not logged in")
1560
 
1561
- if not username:
1562
- parts.append("Enter a username to fetch papers activity")
1563
- return render_status_badge(" · ".join(parts))
1564
 
1565
- if viewer and username.lower() == viewer.lower():
1566
- parts.append("Fetch your papers activity or enter another username")
1567
- parts.append(str(selected_year))
1568
- else:
1569
- parts.append(f"Ready to fetch papers activity for <b>{html.escape(username)}</b>")
1570
- parts.append(str(selected_year))
1571
 
1572
- return render_status_badge(" · ".join(parts))
 
1573
 
1574
 
1575
- def render_papers_invalid_banner(username: str, error_text: str | None = None):
1576
- username = (username or "").strip()
1577
- message = error_text or f"Username or org '{username}' was not found."
1578
- return render_status_badge(html.escape(message))
1579
 
1580
 
1581
- def render_papers_fetching_banner(
1582
- username,
1583
- selected_year,
1584
- profile: gr.OAuthProfile | None,
1585
- ):
1586
- username = (username or "").strip()
1587
- selected_year = int(selected_year)
1588
- viewer = getattr(profile, "username", None) if profile else None
1589
 
1590
- if not username:
1591
- return render_papers_idle_banner("", selected_year, profile)
1592
 
1593
- parts = []
1594
- if viewer:
1595
- parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1596
- else:
1597
- parts.append("Not logged in")
1598
 
1599
- if viewer and username.lower() == viewer.lower():
1600
- parts.append("Fetching <b>your papers activity</b>")
1601
- else:
1602
- parts.append(f"Fetching papers activity for <b>{html.escape(username)}</b>")
1603
-
1604
- parts.append(str(selected_year))
1605
- return render_status_badge(" · ".join(parts))
1606
 
 
 
1607
 
1608
- def render_papers_loaded_banner(
1609
- papers_state: dict | None,
1610
- profile: gr.OAuthProfile | None,
1611
- ):
1612
- if not papers_state or not papers_state.get("username"):
1613
- year = papers_state.get("selected_year", datetime.now().year) if papers_state else datetime.now().year
1614
- return render_papers_idle_banner("", year, profile)
1615
-
1616
- username = papers_state["username"]
1617
- selected_year = int(papers_state["selected_year"])
1618
- viewer = getattr(profile, "username", None) if profile else None
1619
 
1620
- parts = []
1621
- if viewer:
1622
- parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1623
- else:
1624
- parts.append("Not logged in")
1625
 
1626
- if viewer and username.lower() == viewer.lower():
1627
- parts.append("Viewing <b>your papers activity</b>")
1628
- else:
1629
- parts.append(f"Viewing papers activity for <b>{html.escape(username)}</b>")
1630
 
1631
- parts.append(str(selected_year))
1632
- return render_status_badge(" · ".join(parts))
1633
 
1634
 
1635
  def render_empty_chart(title: str):
@@ -2340,201 +2135,238 @@ def maybe_reset_community_section(
2340
  )
2341
 
2342
 
2343
- def maybe_reset_upvotes_section(
2344
- current_upvotes_state,
 
 
2345
  username,
2346
  selected_year,
2347
- upvotes_mode,
2348
  profile: gr.OAuthProfile | None,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2349
  ):
2350
  username = (username or "").strip()
2351
  selected_year = int(selected_year)
2352
- upvotes_mode = upvotes_mode or "all"
2353
 
2354
  identity = validate_username(username, profile) if username else empty_identity("", "No username provided.")
2355
  if username and not identity.get("exists"):
2356
- state = empty_upvotes_state(selected_year)
2357
  state["username"] = username
2358
  state["selected_year"] = selected_year
2359
  state["logs"] = identity.get("error") or f"Username or org '{username}' was not found."
2360
  return (
2361
  state,
2362
- render_upvotes_invalid_banner(username, identity.get("error")),
2363
- gr.update(value="all", visible="hidden"),
2364
- render_empty_chart("Upvotes"),
2365
  state["logs"],
2366
  )
2367
 
2368
- if not current_upvotes_state:
2369
- state = empty_upvotes_state(selected_year)
2370
  return (
2371
  state,
2372
- render_upvotes_idle_banner(username, selected_year, profile),
2373
- gr.update(value="all", visible="hidden"),
2374
- render_empty_chart("Upvotes"),
2375
- "Upvotes activity not fetched yet.",
2376
  )
2377
 
2378
- previous_username = (current_upvotes_state.get("username") or "").strip()
2379
- previous_year = int(current_upvotes_state.get("selected_year") or selected_year)
2380
 
2381
  same_username = previous_username.lower() == username.lower()
2382
  same_year = previous_year == selected_year
2383
 
2384
- if same_username and same_year and current_upvotes_state.get("fetched"):
2385
- chart = render_upvotes_chart(
2386
- current_upvotes_state,
2387
- upvotes_mode,
2388
  username=username,
2389
  year=selected_year,
2390
  )
2391
  return (
2392
- current_upvotes_state,
2393
- render_upvotes_loaded_banner(current_upvotes_state, profile),
2394
- gr.update(value=upvotes_mode, visible=True),
2395
  chart,
2396
- current_upvotes_state.get("logs", "Upvotes activity already fetched."),
2397
  )
2398
 
2399
- state = empty_upvotes_state(selected_year)
2400
  return (
2401
  state,
2402
- render_upvotes_idle_banner(username, selected_year, profile),
2403
- gr.update(value="all", visible="hidden"),
2404
- render_empty_chart("Upvotes"),
2405
- "Upvotes activity needs to be fetched for the current username/year.",
2406
  )
2407
 
2408
 
2409
- def maybe_reset_likes_section(
2410
- current_likes_state,
2411
  username,
2412
  selected_year,
2413
- likes_mode,
2414
  profile: gr.OAuthProfile | None,
 
 
 
 
 
 
 
 
2415
  ):
2416
  username = (username or "").strip()
2417
  selected_year = int(selected_year)
2418
- likes_mode = likes_mode or "all"
2419
 
2420
- identity = validate_username(username, profile) if username else empty_identity("", "No username provided.")
2421
  if username and not identity.get("exists"):
2422
- state = empty_likes_state(selected_year)
2423
- state["username"] = username
2424
- state["selected_year"] = selected_year
2425
- state["logs"] = identity.get("error") or f"Username or org '{username}' was not found."
2426
  return (
2427
- state,
2428
- render_likes_invalid_banner(username, identity.get("error")),
2429
- gr.update(value="all", visible="hidden"),
2430
- render_empty_chart("Likes"),
2431
- state["logs"],
2432
  )
2433
 
2434
- if not current_likes_state:
2435
- state = empty_likes_state(selected_year)
2436
- return (
2437
- state,
2438
- render_likes_idle_banner(username, selected_year, profile),
2439
- gr.update(value="all", visible="hidden"),
2440
- render_empty_chart("Likes"),
2441
- "Likes activity not fetched yet.",
2442
- )
2443
 
2444
- previous_username = (current_likes_state.get("username") or "").strip()
2445
- previous_year = int(current_likes_state.get("selected_year") or selected_year)
 
 
 
 
2446
 
2447
- same_username = previous_username.lower() == username.lower()
2448
- same_year = previous_year == selected_year
 
 
 
 
 
2449
 
2450
- if same_username and same_year and current_likes_state.get("fetched"):
2451
- chart = render_likes_chart(
2452
- current_likes_state,
2453
- likes_mode,
2454
- username=username,
2455
- year=selected_year,
2456
- )
2457
- return (
2458
- current_likes_state,
2459
- render_likes_loaded_banner(current_likes_state, profile),
2460
- gr.update(value=likes_mode, visible=True),
2461
- chart,
2462
- current_likes_state.get("logs", "Likes activity already fetched."),
2463
- )
2464
 
2465
- state = empty_likes_state(selected_year)
2466
- return (
 
 
 
 
 
 
 
 
 
2467
  state,
2468
- render_likes_idle_banner(username, selected_year, profile),
2469
- gr.update(value="all", visible="hidden"),
2470
- render_empty_chart("Likes"),
2471
- "Likes activity needs to be fetched for the current username/year.",
2472
  )
2473
 
2474
 
2475
- def maybe_reset_papers_section(
2476
- current_papers_state,
 
 
 
2477
  username,
2478
  selected_year,
2479
- papers_mode,
2480
  profile: gr.OAuthProfile | None,
2481
  ):
2482
- username = (username or "").strip()
2483
- selected_year = int(selected_year)
2484
- papers_mode = papers_mode or "all"
2485
-
2486
- identity = validate_username(username, profile) if username else empty_identity("", "No username provided.")
2487
- if username and not identity.get("exists"):
2488
- state = empty_papers_state(selected_year)
2489
- state["username"] = username
2490
- state["selected_year"] = selected_year
2491
- state["logs"] = identity.get("error") or f"Username or org '{username}' was not found."
2492
- return (
2493
- state,
2494
- render_papers_invalid_banner(username, identity.get("error")),
2495
- gr.update(value="all", visible="hidden"),
2496
- render_empty_chart("Papers"),
2497
- state["logs"],
2498
- )
2499
-
2500
- if not current_papers_state:
2501
- state = empty_papers_state(selected_year)
2502
- return (
2503
- state,
2504
- render_papers_idle_banner(username, selected_year, profile),
2505
- gr.update(value="all", visible="hidden"),
2506
- render_empty_chart("Papers"),
2507
- "Papers activity not fetched yet.",
2508
- )
2509
 
2510
- previous_username = (current_papers_state.get("username") or "").strip()
2511
- previous_year = int(current_papers_state.get("selected_year") or selected_year)
2512
 
2513
- same_username = previous_username.lower() == username.lower()
2514
- same_year = previous_year == selected_year
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2515
 
2516
- if same_username and same_year and current_papers_state.get("fetched"):
2517
- chart = render_papers_chart(
2518
- current_papers_state,
2519
- papers_mode,
2520
- username=username,
2521
- year=selected_year,
2522
- )
2523
- return (
2524
- current_papers_state,
2525
- render_papers_loaded_banner(current_papers_state, profile),
2526
- gr.update(value=papers_mode, visible=True),
2527
- chart,
2528
- current_papers_state.get("logs", "Papers activity already fetched."),
2529
- )
2530
 
2531
- state = empty_papers_state(selected_year)
2532
- return (
2533
- state,
2534
- render_papers_idle_banner(username, selected_year, profile),
2535
- gr.update(value="all", visible="hidden"),
2536
- render_empty_chart("Papers"),
2537
- "Papers activity needs to be fetched for the current username/year.",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2538
  )
2539
 
2540
 
@@ -2548,30 +2380,15 @@ def prepare_community_fetch_ui(username, selected_year, profile: gr.OAuthProfile
2548
 
2549
 
2550
  def prepare_upvotes_fetch_ui(username, selected_year, profile: gr.OAuthProfile | None):
2551
- username = (username or "").strip()
2552
- if username:
2553
- identity = validate_username(username, profile)
2554
- if not identity.get("exists"):
2555
- return render_upvotes_invalid_banner(username, identity.get("error"))
2556
- return render_upvotes_fetching_banner(username, selected_year, profile)
2557
 
2558
 
2559
  def prepare_likes_fetch_ui(username, selected_year, profile: gr.OAuthProfile | None):
2560
- username = (username or "").strip()
2561
- if username:
2562
- identity = validate_username(username, profile)
2563
- if not identity.get("exists"):
2564
- return render_likes_invalid_banner(username, identity.get("error"))
2565
- return render_likes_fetching_banner(username, selected_year, profile)
2566
 
2567
 
2568
  def prepare_papers_fetch_ui(username, selected_year, profile: gr.OAuthProfile | None):
2569
- username = (username or "").strip()
2570
- if username:
2571
- identity = validate_username(username, profile)
2572
- if not identity.get("exists"):
2573
- return render_papers_invalid_banner(username, identity.get("error"))
2574
- return render_papers_fetching_banner(username, selected_year, profile)
2575
 
2576
 
2577
  def fetch_and_render_community(
@@ -2637,39 +2454,19 @@ def fetch_and_render_upvotes(
2637
  upvotes_mode,
2638
  profile: gr.OAuthProfile | None,
2639
  ):
2640
- username = (username or "").strip()
2641
- selected_year = int(selected_year)
2642
- upvotes_mode = upvotes_mode or "all"
2643
-
2644
- identity = validate_username(username, profile)
2645
- if username and not identity.get("exists"):
2646
- empty_state = empty_upvotes_state(selected_year)
2647
- empty_state["username"] = username
2648
- empty_state["selected_year"] = selected_year
2649
- empty_state["logs"] = identity.get("error") or f"Username or org '{username}' was not found."
2650
- return (
2651
- empty_state,
2652
- render_upvotes_invalid_banner(username, identity.get("error")),
2653
- render_empty_chart("Upvotes"),
2654
- empty_state["logs"],
2655
- gr.update(value="all", visible="hidden"),
2656
- )
2657
-
2658
- state = fetch_all_upvotes_activity(username, selected_year)
2659
-
2660
- chart = render_upvotes_chart(
2661
- state,
2662
  upvotes_mode,
2663
- username=username,
2664
- year=selected_year,
2665
- )
2666
-
2667
- return (
2668
- state,
2669
- render_upvotes_loaded_banner(state, profile),
2670
- chart,
2671
- state["logs"],
2672
- gr.update(value=upvotes_mode, visible=True),
2673
  )
2674
 
2675
 
@@ -2680,39 +2477,19 @@ def fetch_and_render_likes(
2680
  likes_mode,
2681
  profile: gr.OAuthProfile | None,
2682
  ):
2683
- username = (username or "").strip()
2684
- selected_year = int(selected_year)
2685
- likes_mode = likes_mode or "all"
2686
-
2687
- identity = validate_username(username, profile)
2688
- if username and not identity.get("exists"):
2689
- empty_state = empty_likes_state(selected_year)
2690
- empty_state["username"] = username
2691
- empty_state["selected_year"] = selected_year
2692
- empty_state["logs"] = identity.get("error") or f"Username or org '{username}' was not found."
2693
- return (
2694
- empty_state,
2695
- render_likes_invalid_banner(username, identity.get("error")),
2696
- render_empty_chart("Likes"),
2697
- empty_state["logs"],
2698
- gr.update(value="all", visible="hidden"),
2699
- )
2700
-
2701
- state = fetch_all_likes_activity(username, selected_year)
2702
-
2703
- chart = render_likes_chart(
2704
- state,
2705
  likes_mode,
2706
- username=username,
2707
- year=selected_year,
2708
- )
2709
-
2710
- return (
2711
- state,
2712
- render_likes_loaded_banner(state, profile),
2713
- chart,
2714
- state["logs"],
2715
- gr.update(value=likes_mode, visible=True),
2716
  )
2717
 
2718
 
@@ -2723,39 +2500,19 @@ def fetch_and_render_papers(
2723
  papers_mode,
2724
  profile: gr.OAuthProfile | None,
2725
  ):
2726
- username = (username or "").strip()
2727
- selected_year = int(selected_year)
2728
- papers_mode = papers_mode or "all"
2729
-
2730
- identity = validate_username(username, profile)
2731
- if username and not identity.get("exists"):
2732
- empty_state = empty_papers_state(selected_year)
2733
- empty_state["username"] = username
2734
- empty_state["selected_year"] = selected_year
2735
- empty_state["logs"] = identity.get("error") or f"Username or org '{username}' was not found."
2736
- return (
2737
- empty_state,
2738
- render_papers_invalid_banner(username, identity.get("error")),
2739
- render_empty_chart("Papers"),
2740
- empty_state["logs"],
2741
- gr.update(value="all", visible="hidden"),
2742
- )
2743
-
2744
- state = fetch_all_papers_activity(username, selected_year)
2745
-
2746
- chart = render_papers_chart(
2747
- state,
2748
  papers_mode,
2749
- username=username,
2750
- year=selected_year,
2751
- )
2752
-
2753
- return (
2754
- state,
2755
- render_papers_loaded_banner(state, profile),
2756
- chart,
2757
- state["logs"],
2758
- gr.update(value=papers_mode, visible=True),
2759
  )
2760
 
2761
 
@@ -2782,35 +2539,32 @@ def rerender_discussions_from_state(community_state, discussion_mode):
2782
 
2783
 
2784
  def rerender_upvotes_from_state(upvotes_state, upvotes_mode):
2785
- if not upvotes_state:
2786
- return render_empty_chart("Upvotes")
2787
- return render_upvotes_chart(
2788
  upvotes_state,
2789
- upvotes_mode or "all",
2790
- username=(upvotes_state.get("username") or ""),
2791
- year=int(upvotes_state.get("selected_year") or datetime.now().year),
 
2792
  )
2793
 
2794
 
2795
  def rerender_likes_from_state(likes_state, likes_mode):
2796
- if not likes_state:
2797
- return render_empty_chart("Likes")
2798
- return render_likes_chart(
2799
  likes_state,
2800
- likes_mode or "all",
2801
- username=(likes_state.get("username") or ""),
2802
- year=int(likes_state.get("selected_year") or datetime.now().year),
 
2803
  )
2804
 
2805
 
2806
  def rerender_papers_from_state(papers_state, papers_mode):
2807
- if not papers_state:
2808
- return render_empty_chart("Papers")
2809
- return render_papers_chart(
2810
  papers_state,
2811
- papers_mode or "all",
2812
- username=(papers_state.get("username") or ""),
2813
- year=int(papers_state.get("selected_year") or datetime.now().year),
 
2814
  )
2815
 
2816
 
 
937
 
938
 
939
  # ============================================================
940
+ # Upvotes / Likes / Papers activity fetch
941
  # ============================================================
942
  def empty_upvotes_state(selected_year: int):
943
  return empty_bucketed_activity_state(
 
972
  )
973
 
974
 
 
 
 
975
  def empty_likes_state(selected_year: int):
976
  return empty_bucketed_activity_state(
977
  selected_year=selected_year,
 
1005
  )
1006
 
1007
 
 
 
 
1008
  def empty_papers_state(selected_year: int):
1009
  return empty_bucketed_activity_state(
1010
  selected_year=selected_year,
 
1177
  """
1178
 
1179
 
1180
+ # ============================================================
1181
+ # Generic banner helpers
1182
+ # ============================================================
1183
+ def viewer_banner_prefix(profile: gr.OAuthProfile | None) -> list[str]:
 
1184
  viewer = getattr(profile, "username", None) if profile else None
 
1185
  if viewer:
1186
+ return [f"Logged in as <b>{html.escape(viewer)}</b>"]
1187
+ return ["Not logged in"]
 
 
 
 
 
1188
 
 
 
 
 
1189
 
1190
+ def render_generic_invalid_banner(username: str, error_text: str | None = None):
 
 
 
1191
  username = (username or "").strip()
1192
  message = error_text or f"Username or org '{username}' was not found."
1193
  return render_status_badge(html.escape(message))
1194
 
1195
 
1196
+ def render_section_idle_banner(
1197
+ section_label: str,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1198
  username,
1199
  selected_year,
1200
  profile: gr.OAuthProfile | None,
 
1203
  selected_year = int(selected_year)
1204
  viewer = getattr(profile, "username", None) if profile else None
1205
 
1206
+ parts = viewer_banner_prefix(profile)
 
 
 
 
1207
 
1208
  if not username:
1209
+ parts.append(f"Enter a username to fetch {section_label.lower()}")
1210
  return render_status_badge(" · ".join(parts))
1211
 
1212
  if viewer and username.lower() == viewer.lower():
1213
+ parts.append(f"Fetch your {section_label.lower()} or enter another username")
 
1214
  else:
1215
+ parts.append(f"Ready to fetch {section_label.lower()} for <b>{html.escape(username)}</b>")
 
1216
 
1217
+ parts.append(str(selected_year))
1218
  return render_status_badge(" · ".join(parts))
1219
 
1220
 
1221
+ def render_section_fetching_banner(
1222
+ section_label: str,
 
 
 
 
 
1223
  username,
1224
  selected_year,
1225
  profile: gr.OAuthProfile | None,
 
1229
  viewer = getattr(profile, "username", None) if profile else None
1230
 
1231
  if not username:
1232
+ return render_section_idle_banner(section_label, "", selected_year, profile)
1233
 
1234
+ parts = viewer_banner_prefix(profile)
 
 
 
 
1235
 
1236
  if viewer and username.lower() == viewer.lower():
1237
+ parts.append(f"Fetching <b>your {section_label.lower()}</b>")
1238
  else:
1239
+ parts.append(f"Fetching {section_label.lower()} for <b>{html.escape(username)}</b>")
1240
 
1241
  parts.append(str(selected_year))
1242
  return render_status_badge(" · ".join(parts))
1243
 
1244
 
1245
+ def render_section_loaded_banner(
1246
+ section_label: str,
1247
+ state: dict | None,
1248
  profile: gr.OAuthProfile | None,
1249
  ):
1250
+ year = state.get("selected_year", datetime.now().year) if state else datetime.now().year
1251
+ if not state or not state.get("username"):
1252
+ return render_section_idle_banner(section_label, "", year, profile)
1253
 
1254
+ username = state["username"]
1255
+ selected_year = int(state["selected_year"])
1256
  viewer = getattr(profile, "username", None) if profile else None
1257
 
1258
+ parts = viewer_banner_prefix(profile)
 
 
 
 
1259
 
1260
  if viewer and username.lower() == viewer.lower():
1261
+ parts.append(f"Viewing <b>your {section_label.lower()}</b>")
1262
  else:
1263
+ parts.append(f"Viewing {section_label.lower()} for <b>{html.escape(username)}</b>")
1264
 
1265
  parts.append(str(selected_year))
1266
  return render_status_badge(" · ".join(parts))
1267
 
1268
 
1269
+ # ============================================================
1270
+ # Repo-specific banners
1271
+ # ============================================================
1272
+ def render_idle_context_banner(
1273
+ username: str,
1274
  profile: gr.OAuthProfile | None,
1275
  ):
1276
  username = (username or "").strip()
 
1277
  viewer = getattr(profile, "username", None) if profile else None
1278
 
 
1279
  if viewer:
1280
+ if not username or username.lower() == viewer.lower():
1281
+ return render_status_badge(
1282
+ f"Logged in as <b>{html.escape(viewer)}</b> · Fetch your activity or enter another username"
1283
+ )
1284
+ return render_status_badge(
1285
+ f"Logged in as <b>{html.escape(viewer)}</b> · Ready to fetch <b>{html.escape(username)}</b> · Public repos only"
1286
+ )
1287
 
1288
+ if username:
1289
+ return render_status_badge(
1290
+ f"Not logged in · Ready to fetch <b>{html.escape(username)}</b> · Public repos only"
1291
+ )
1292
 
1293
+ return render_status_badge("Not logged in · Enter a username to get started")
 
 
 
 
 
1294
 
 
1295
 
1296
+ def render_invalid_username_banner(username: str, error_text: str | None = None):
1297
+ return render_generic_invalid_banner(username, error_text)
1298
 
 
 
 
 
1299
 
1300
+ def render_context_banner(app_state: dict | None, profile: gr.OAuthProfile | None):
1301
+ if not app_state or not app_state.get("username"):
1302
+ return render_idle_context_banner("", profile)
1303
 
1304
+ username = app_state["username"]
1305
+ selected_year = int(app_state["selected_year"])
1306
+ is_own = bool(app_state.get("is_own_profile", False))
1307
+ can_toggle = bool(app_state.get("can_toggle_visibility", False))
 
 
 
1308
  viewer = getattr(profile, "username", None) if profile else None
1309
 
 
 
 
1310
  parts = []
1311
+
1312
  if viewer:
1313
  parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1314
  else:
1315
  parts.append("Not logged in")
1316
 
1317
  if viewer and username.lower() == viewer.lower():
1318
+ parts.append("Viewing <b>your activity</b>")
1319
  else:
1320
+ parts.append(f"Viewing <b>{html.escape(username)}</b>")
1321
 
1322
  parts.append(str(selected_year))
 
 
1323
 
1324
+ if is_own and can_toggle:
1325
+ parts.append("Private repos available")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1326
  else:
1327
+ parts.append("Public repos only")
1328
 
 
1329
  return render_status_badge(" · ".join(parts))
1330
 
1331
 
1332
+ def render_fetching_context_banner(
1333
  username,
1334
  selected_year,
1335
  profile: gr.OAuthProfile | None,
 
1338
  selected_year = int(selected_year)
1339
  viewer = getattr(profile, "username", None) if profile else None
1340
 
1341
+ if not username:
1342
+ return render_idle_context_banner("", profile)
1343
+
1344
  parts = []
1345
+
1346
  if viewer:
1347
  parts.append(f"Logged in as <b>{html.escape(viewer)}</b>")
1348
  else:
1349
  parts.append("Not logged in")
1350
 
 
 
 
 
1351
  if viewer and username.lower() == viewer.lower():
1352
+ parts.append("Fetching <b>your activity</b>")
1353
  parts.append(str(selected_year))
1354
+ parts.append("Checking public and private repos")
1355
  else:
1356
+ parts.append(f"Fetching <b>{html.escape(username)}</b>")
1357
  parts.append(str(selected_year))
1358
+ parts.append("Checking public repos")
1359
 
1360
  return render_status_badge(" · ".join(parts))
1361
 
1362
 
1363
+ # ============================================================
1364
+ # Section-specific banner wrappers
1365
+ # ============================================================
1366
+ def render_community_idle_banner(username, selected_year, profile: gr.OAuthProfile | None):
1367
+ return render_section_idle_banner("community activity", username, selected_year, profile)
1368
 
1369
 
1370
+ def render_community_invalid_banner(username: str, error_text: str | None = None):
1371
+ return render_generic_invalid_banner(username, error_text)
 
 
 
 
 
 
1372
 
 
 
1373
 
1374
+ def render_community_fetching_banner(username, selected_year, profile: gr.OAuthProfile | None):
1375
+ return render_section_fetching_banner("community activity", username, selected_year, profile)
 
 
 
1376
 
 
 
 
 
1377
 
1378
+ def render_community_loaded_banner(community_state: dict | None, profile: gr.OAuthProfile | None):
1379
+ return render_section_loaded_banner("community activity", community_state, profile)
1380
 
1381
 
1382
+ def render_upvotes_idle_banner(username, selected_year, profile: gr.OAuthProfile | None):
1383
+ return render_section_idle_banner("upvotes activity", username, selected_year, profile)
 
 
 
 
 
1384
 
 
 
 
1385
 
1386
+ def render_upvotes_invalid_banner(username: str, error_text: str | None = None):
1387
+ return render_generic_invalid_banner(username, error_text)
 
 
 
1388
 
 
 
 
 
1389
 
1390
+ def render_upvotes_fetching_banner(username, selected_year, profile: gr.OAuthProfile | None):
1391
+ return render_section_fetching_banner("upvotes activity", username, selected_year, profile)
1392
 
1393
 
1394
+ def render_upvotes_loaded_banner(upvotes_state: dict | None, profile: gr.OAuthProfile | None):
1395
+ return render_section_loaded_banner("upvotes activity", upvotes_state, profile)
 
 
 
 
 
 
1396
 
 
 
 
 
 
1397
 
1398
+ def render_likes_idle_banner(username, selected_year, profile: gr.OAuthProfile | None):
1399
+ return render_section_idle_banner("likes activity", username, selected_year, profile)
 
1400
 
 
 
 
 
 
 
1401
 
1402
+ def render_likes_invalid_banner(username: str, error_text: str | None = None):
1403
+ return render_generic_invalid_banner(username, error_text)
1404
 
1405
 
1406
+ def render_likes_fetching_banner(username, selected_year, profile: gr.OAuthProfile | None):
1407
+ return render_section_fetching_banner("likes activity", username, selected_year, profile)
 
 
1408
 
1409
 
1410
+ def render_likes_loaded_banner(likes_state: dict | None, profile: gr.OAuthProfile | None):
1411
+ return render_section_loaded_banner("likes activity", likes_state, profile)
 
 
 
 
 
 
1412
 
 
 
1413
 
1414
+ def render_papers_idle_banner(username, selected_year, profile: gr.OAuthProfile | None):
1415
+ return render_section_idle_banner("papers activity", username, selected_year, profile)
 
 
 
1416
 
 
 
 
 
 
 
 
1417
 
1418
+ def render_papers_invalid_banner(username: str, error_text: str | None = None):
1419
+ return render_generic_invalid_banner(username, error_text)
1420
 
 
 
 
 
 
 
 
 
 
 
 
1421
 
1422
+ def render_papers_fetching_banner(username, selected_year, profile: gr.OAuthProfile | None):
1423
+ return render_section_fetching_banner("papers activity", username, selected_year, profile)
 
 
 
1424
 
 
 
 
 
1425
 
1426
+ def render_papers_loaded_banner(papers_state: dict | None, profile: gr.OAuthProfile | None):
1427
+ return render_section_loaded_banner("papers activity", papers_state, profile)
1428
 
1429
 
1430
  def render_empty_chart(title: str):
 
2135
  )
2136
 
2137
 
2138
+ # ============================================================
2139
+ # Generic helpers for single-chart sections
2140
+ # ============================================================
2141
+ def prepare_single_section_fetch_ui(
2142
  username,
2143
  selected_year,
 
2144
  profile: gr.OAuthProfile | None,
2145
+ section_label: str,
2146
+ ):
2147
+ username = (username or "").strip()
2148
+ if username:
2149
+ identity = validate_username(username, profile)
2150
+ if not identity.get("exists"):
2151
+ return render_generic_invalid_banner(username, identity.get("error"))
2152
+ return render_section_fetching_banner(section_label, username, selected_year, profile)
2153
+
2154
+
2155
+ def maybe_reset_single_chart_section(
2156
+ current_state,
2157
+ username,
2158
+ selected_year,
2159
+ mode,
2160
+ profile: gr.OAuthProfile | None,
2161
+ *,
2162
+ section_label: str,
2163
+ empty_state_fn,
2164
+ loaded_banner_fn,
2165
+ chart_render_fn,
2166
+ empty_chart_title: str,
2167
+ not_fetched_text: str,
2168
+ needs_fetch_text: str,
2169
+ default_mode: str,
2170
  ):
2171
  username = (username or "").strip()
2172
  selected_year = int(selected_year)
2173
+ mode = mode or default_mode
2174
 
2175
  identity = validate_username(username, profile) if username else empty_identity("", "No username provided.")
2176
  if username and not identity.get("exists"):
2177
+ state = empty_state_fn(selected_year)
2178
  state["username"] = username
2179
  state["selected_year"] = selected_year
2180
  state["logs"] = identity.get("error") or f"Username or org '{username}' was not found."
2181
  return (
2182
  state,
2183
+ render_generic_invalid_banner(username, identity.get("error")),
2184
+ gr.update(value=default_mode, visible="hidden"),
2185
+ render_empty_chart(empty_chart_title),
2186
  state["logs"],
2187
  )
2188
 
2189
+ if not current_state:
2190
+ state = empty_state_fn(selected_year)
2191
  return (
2192
  state,
2193
+ render_section_idle_banner(section_label, username, selected_year, profile),
2194
+ gr.update(value=default_mode, visible="hidden"),
2195
+ render_empty_chart(empty_chart_title),
2196
+ not_fetched_text,
2197
  )
2198
 
2199
+ previous_username = (current_state.get("username") or "").strip()
2200
+ previous_year = int(current_state.get("selected_year") or selected_year)
2201
 
2202
  same_username = previous_username.lower() == username.lower()
2203
  same_year = previous_year == selected_year
2204
 
2205
+ if same_username and same_year and current_state.get("fetched"):
2206
+ chart = chart_render_fn(
2207
+ current_state,
2208
+ mode,
2209
  username=username,
2210
  year=selected_year,
2211
  )
2212
  return (
2213
+ current_state,
2214
+ loaded_banner_fn(current_state, profile),
2215
+ gr.update(value=mode, visible=True),
2216
  chart,
2217
+ current_state.get("logs", "Already fetched."),
2218
  )
2219
 
2220
+ state = empty_state_fn(selected_year)
2221
  return (
2222
  state,
2223
+ render_section_idle_banner(section_label, username, selected_year, profile),
2224
+ gr.update(value=default_mode, visible="hidden"),
2225
+ render_empty_chart(empty_chart_title),
2226
+ needs_fetch_text,
2227
  )
2228
 
2229
 
2230
+ def fetch_and_render_single_chart_section(
 
2231
  username,
2232
  selected_year,
2233
+ mode,
2234
  profile: gr.OAuthProfile | None,
2235
+ *,
2236
+ section_label: str,
2237
+ empty_state_fn,
2238
+ fetch_state_fn,
2239
+ loaded_banner_fn,
2240
+ chart_render_fn,
2241
+ empty_chart_title: str,
2242
+ default_mode: str,
2243
  ):
2244
  username = (username or "").strip()
2245
  selected_year = int(selected_year)
2246
+ mode = mode or default_mode
2247
 
2248
+ identity = validate_username(username, profile)
2249
  if username and not identity.get("exists"):
2250
+ empty_state = empty_state_fn(selected_year)
2251
+ empty_state["username"] = username
2252
+ empty_state["selected_year"] = selected_year
2253
+ empty_state["logs"] = identity.get("error") or f"Username or org '{username}' was not found."
2254
  return (
2255
+ empty_state,
2256
+ render_generic_invalid_banner(username, identity.get("error")),
2257
+ render_empty_chart(empty_chart_title),
2258
+ empty_state["logs"],
2259
+ gr.update(value=default_mode, visible="hidden"),
2260
  )
2261
 
2262
+ state = fetch_state_fn(username, selected_year)
 
 
 
 
 
 
 
 
2263
 
2264
+ chart = chart_render_fn(
2265
+ state,
2266
+ mode,
2267
+ username=username,
2268
+ year=selected_year,
2269
+ )
2270
 
2271
+ return (
2272
+ state,
2273
+ loaded_banner_fn(state, profile),
2274
+ chart,
2275
+ state["logs"],
2276
+ gr.update(value=mode, visible=True),
2277
+ )
2278
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2279
 
2280
+ def rerender_single_chart_from_state(
2281
+ state,
2282
+ mode,
2283
+ *,
2284
+ empty_title: str,
2285
+ render_fn,
2286
+ default_mode: str,
2287
+ ):
2288
+ if not state:
2289
+ return render_empty_chart(empty_title)
2290
+ return render_fn(
2291
  state,
2292
+ mode or default_mode,
2293
+ username=(state.get("username") or ""),
2294
+ year=int(state.get("selected_year") or datetime.now().year),
 
2295
  )
2296
 
2297
 
2298
+ # ============================================================
2299
+ # Section wrappers
2300
+ # ============================================================
2301
+ def maybe_reset_upvotes_section(
2302
+ current_upvotes_state,
2303
  username,
2304
  selected_year,
2305
+ upvotes_mode,
2306
  profile: gr.OAuthProfile | None,
2307
  ):
2308
+ return maybe_reset_single_chart_section(
2309
+ current_upvotes_state,
2310
+ username,
2311
+ selected_year,
2312
+ upvotes_mode,
2313
+ profile,
2314
+ section_label="upvotes activity",
2315
+ empty_state_fn=empty_upvotes_state,
2316
+ loaded_banner_fn=render_upvotes_loaded_banner,
2317
+ chart_render_fn=render_upvotes_chart,
2318
+ empty_chart_title="Upvotes",
2319
+ not_fetched_text="Upvotes activity not fetched yet.",
2320
+ needs_fetch_text="Upvotes activity needs to be fetched for the current username/year.",
2321
+ default_mode="all",
2322
+ )
 
 
 
 
 
 
 
 
 
 
 
 
2323
 
 
 
2324
 
2325
+ def maybe_reset_likes_section(
2326
+ current_likes_state,
2327
+ username,
2328
+ selected_year,
2329
+ likes_mode,
2330
+ profile: gr.OAuthProfile | None,
2331
+ ):
2332
+ return maybe_reset_single_chart_section(
2333
+ current_likes_state,
2334
+ username,
2335
+ selected_year,
2336
+ likes_mode,
2337
+ profile,
2338
+ section_label="likes activity",
2339
+ empty_state_fn=empty_likes_state,
2340
+ loaded_banner_fn=render_likes_loaded_banner,
2341
+ chart_render_fn=render_likes_chart,
2342
+ empty_chart_title="Likes",
2343
+ not_fetched_text="Likes activity not fetched yet.",
2344
+ needs_fetch_text="Likes activity needs to be fetched for the current username/year.",
2345
+ default_mode="all",
2346
+ )
2347
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2348
 
2349
+ def maybe_reset_papers_section(
2350
+ current_papers_state,
2351
+ username,
2352
+ selected_year,
2353
+ papers_mode,
2354
+ profile: gr.OAuthProfile | None,
2355
+ ):
2356
+ return maybe_reset_single_chart_section(
2357
+ current_papers_state,
2358
+ username,
2359
+ selected_year,
2360
+ papers_mode,
2361
+ profile,
2362
+ section_label="papers activity",
2363
+ empty_state_fn=empty_papers_state,
2364
+ loaded_banner_fn=render_papers_loaded_banner,
2365
+ chart_render_fn=render_papers_chart,
2366
+ empty_chart_title="Papers",
2367
+ not_fetched_text="Papers activity not fetched yet.",
2368
+ needs_fetch_text="Papers activity needs to be fetched for the current username/year.",
2369
+ default_mode="all",
2370
  )
2371
 
2372
 
 
2380
 
2381
 
2382
  def prepare_upvotes_fetch_ui(username, selected_year, profile: gr.OAuthProfile | None):
2383
+ return prepare_single_section_fetch_ui(username, selected_year, profile, "upvotes activity")
 
 
 
 
 
2384
 
2385
 
2386
  def prepare_likes_fetch_ui(username, selected_year, profile: gr.OAuthProfile | None):
2387
+ return prepare_single_section_fetch_ui(username, selected_year, profile, "likes activity")
 
 
 
 
 
2388
 
2389
 
2390
  def prepare_papers_fetch_ui(username, selected_year, profile: gr.OAuthProfile | None):
2391
+ return prepare_single_section_fetch_ui(username, selected_year, profile, "papers activity")
 
 
 
 
 
2392
 
2393
 
2394
  def fetch_and_render_community(
 
2454
  upvotes_mode,
2455
  profile: gr.OAuthProfile | None,
2456
  ):
2457
+ _ = current_state
2458
+ return fetch_and_render_single_chart_section(
2459
+ username,
2460
+ selected_year,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2461
  upvotes_mode,
2462
+ profile,
2463
+ section_label="upvotes activity",
2464
+ empty_state_fn=empty_upvotes_state,
2465
+ fetch_state_fn=fetch_all_upvotes_activity,
2466
+ loaded_banner_fn=render_upvotes_loaded_banner,
2467
+ chart_render_fn=render_upvotes_chart,
2468
+ empty_chart_title="Upvotes",
2469
+ default_mode="all",
 
 
2470
  )
2471
 
2472
 
 
2477
  likes_mode,
2478
  profile: gr.OAuthProfile | None,
2479
  ):
2480
+ _ = current_state
2481
+ return fetch_and_render_single_chart_section(
2482
+ username,
2483
+ selected_year,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2484
  likes_mode,
2485
+ profile,
2486
+ section_label="likes activity",
2487
+ empty_state_fn=empty_likes_state,
2488
+ fetch_state_fn=fetch_all_likes_activity,
2489
+ loaded_banner_fn=render_likes_loaded_banner,
2490
+ chart_render_fn=render_likes_chart,
2491
+ empty_chart_title="Likes",
2492
+ default_mode="all",
 
 
2493
  )
2494
 
2495
 
 
2500
  papers_mode,
2501
  profile: gr.OAuthProfile | None,
2502
  ):
2503
+ _ = current_state
2504
+ return fetch_and_render_single_chart_section(
2505
+ username,
2506
+ selected_year,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2507
  papers_mode,
2508
+ profile,
2509
+ section_label="papers activity",
2510
+ empty_state_fn=empty_papers_state,
2511
+ fetch_state_fn=fetch_all_papers_activity,
2512
+ loaded_banner_fn=render_papers_loaded_banner,
2513
+ chart_render_fn=render_papers_chart,
2514
+ empty_chart_title="Papers",
2515
+ default_mode="all",
 
 
2516
  )
2517
 
2518
 
 
2539
 
2540
 
2541
  def rerender_upvotes_from_state(upvotes_state, upvotes_mode):
2542
+ return rerender_single_chart_from_state(
 
 
2543
  upvotes_state,
2544
+ upvotes_mode,
2545
+ empty_title="Upvotes",
2546
+ render_fn=render_upvotes_chart,
2547
+ default_mode="all",
2548
  )
2549
 
2550
 
2551
  def rerender_likes_from_state(likes_state, likes_mode):
2552
+ return rerender_single_chart_from_state(
 
 
2553
  likes_state,
2554
+ likes_mode,
2555
+ empty_title="Likes",
2556
+ render_fn=render_likes_chart,
2557
+ default_mode="all",
2558
  )
2559
 
2560
 
2561
  def rerender_papers_from_state(papers_state, papers_mode):
2562
+ return rerender_single_chart_from_state(
 
 
2563
  papers_state,
2564
+ papers_mode,
2565
+ empty_title="Papers",
2566
+ render_fn=render_papers_chart,
2567
+ default_mode="all",
2568
  )
2569
 
2570