Code review of the static analytics dashboard template (analytics/analytics_package/analytics/static_site/template/index.html, deployed as a byte-for-byte copy to each site) surfaced six non-blocking cleanups. None cause a rendering bug with today's data; all are latent robustness/maintenance issues.
- Hardcoded access-request stat cards (~line 899): the stats grid renders exactly dbGaP/DUOS/Total cards while the
serviceName()/services-Set mechanism is generic over N services. A third or unclassified service is counted in Total but gets no card (cards visibly fail to sum). Fix: reduce into a service→count map and render one card per present service.
serviceName() fallback (~line 365): returns "" for a missing click_url and the raw URL for unknown hosts, so each distinct unknown URL counts as a separate "service" in the showService gate. Normalize to hostname or bucket unknowns.
- Case-sensitivity asymmetry (~line 366):
serviceName() matches duos.org/dbgap.ncbi.nlm.nih.gov case-sensitively while the Python generator filters click URLs case-insensitively (fetch.py str.contains(..., case=False)) — a mixed-case URL passes the generator but fails JS classification.
- Non-array guard + un-awaited render (~lines 887/419):
renderAccessRequestsTable's !data || data.length === 0 guard passes a non-array object, crashing at data.reduce; the call site is un-awaited so the rejection bypasses loadData's error UI — silent failure.
- Stat-card markup duplicated three ways:
statCard() helper (~line 472), an inline copy in renderEventCounts (~line 573), and the access-request stats block (~line 902) each hand-write the same card structure and have already diverged. A grid-class parameter and optional change-row on statCard() would absorb all three.
- Unbounded detail exports: the export ships every pageviews/outbound-links row (e.g. 1,810 pageviews rows / 232KB on AnVIL Portal for a table that renders
slice(0, 20)), costing page-load payload and thousands of diff lines per monthly regen. A top-N cap at export time fixes both.
Found during review of anvilproject/anvil-portal#4075 (the template observations apply to the shared template here, where the fix belongs — not to per-site copies).
Code review of the static analytics dashboard template (
analytics/analytics_package/analytics/static_site/template/index.html, deployed as a byte-for-byte copy to each site) surfaced six non-blocking cleanups. None cause a rendering bug with today's data; all are latent robustness/maintenance issues.serviceName()/services-Set mechanism is generic over N services. A third or unclassified service is counted in Total but gets no card (cards visibly fail to sum). Fix: reduce into a service→count map and render one card per present service.serviceName()fallback (~line 365): returns""for a missingclick_urland the raw URL for unknown hosts, so each distinct unknown URL counts as a separate "service" in theshowServicegate. Normalize to hostname or bucket unknowns.serviceName()matchesduos.org/dbgap.ncbi.nlm.nih.govcase-sensitively while the Python generator filters click URLs case-insensitively (fetch.pystr.contains(..., case=False)) — a mixed-case URL passes the generator but fails JS classification.renderAccessRequestsTable's!data || data.length === 0guard passes a non-array object, crashing atdata.reduce; the call site is un-awaited so the rejection bypassesloadData's error UI — silent failure.statCard()helper (~line 472), an inline copy inrenderEventCounts(~line 573), and the access-request stats block (~line 902) each hand-write the same card structure and have already diverged. A grid-class parameter and optional change-row onstatCard()would absorb all three.slice(0, 20)), costing page-load payload and thousands of diff lines per monthly regen. A top-N cap at export time fixes both.Found during review of anvilproject/anvil-portal#4075 (the template observations apply to the shared template here, where the fix belongs — not to per-site copies).