diff --git a/public/analytics.js b/public/analytics.js index 743139bc..19a899a7 100644 --- a/public/analytics.js +++ b/public/analytics.js @@ -4521,12 +4521,15 @@ function destroy() { _stopRolesRefresh(); _stopScopesRefresh(); _stopForeignTraf '
' + '
' + '
Loading scope stats…
' + - '' + - '' + - '' + - '
RegionMessages% of Scoped
' + - '
' + - '
' + + '
' + + 'Region Breakdown & Trend' + + '' + + '' + + '' + + '
RegionMessages% of Scoped
' + + '
' + + '
' + + '
' + '' + '
' + '
' + @@ -4571,6 +4574,18 @@ function destroy() { _stopRolesRefresh(); _stopScopesRefresh(); _stopForeignTraf return (n / total * 100).toFixed(1) + '%'; } + // Collapsed-by-default
wrapper for a scope-tab subsection — + // title can include a dynamic count ("Nodes Not Using Any Scope + // (1423 of 1491)") since it's built at render time with the real data + // already in hand, unlike a static skeleton-level heading would be. + function detailsSection(title, description, bodyHtml) { + return '
' + + '' + title + '' + + (description ? '

' + description + '

' : '') + + '
' + bodyHtml + '
' + + '
'; + } + async function load(w) { var loadingEl = document.getElementById('scopes-loading'); if (loadingEl) loadingEl.style.display = ''; @@ -4670,12 +4685,11 @@ function destroy() { _stopRolesRefresh(); _stopScopesRefresh(); _stopForeignTraf } else { adoptBody = '

No channel messages in this window.

'; } - adoptEl.innerHTML = - '

Scope Adoption by Channel

' + - '

' + - 'Which channels actually use region scoping vs which never do. Top 30 by message volume.' + - '

' + - adoptBody; + adoptEl.innerHTML = detailsSection( + 'Scope Adoption by Channel (' + adoption.length.toLocaleString() + ')', + 'Which channels actually use region scoping vs which never do. Top 30 by message volume.', + adoptBody + ); } // Per-region table @@ -4771,20 +4785,17 @@ function destroy() { _stopRolesRefresh(); _stopScopesRefresh(); _stopForeignTraf '
' + cells + '
' + '
'; }).join(''); - hourlyEl.innerHTML = - '

Activity by Hour of Day

' + - '

' + - 'When during a typical day (UTC) each region is active, aggregated across every day in the window above. Reads best on 7d — color is normalized per region, so quiet and busy regions are both visible.' + - '

' + + hourlyEl.innerHTML = detailsSection( + 'Activity by Hour of Day (' + hourly.length.toLocaleString() + ' region' + (hourly.length === 1 ? '' : 's') + ')', + 'When during a typical day (UTC) each region is active, aggregated across every day in the window above. Reads best on 7d — color is normalized per region, so quiet and busy regions are both visible.', '
' + '
' + '
' + hourLabels + '
' + '
' + - hourlyRows; + hourlyRows + ); } else { - hourlyEl.innerHTML = - '

Activity by Hour of Day

' + - '

No scoped messages in this window to chart by hour of day.

'; + hourlyEl.innerHTML = detailsSection('Activity by Hour of Day', 'No scoped messages in this window to chart by hour of day.', ''); } } @@ -4800,11 +4811,9 @@ function destroy() { _stopRolesRefresh(); _stopScopesRefresh(); _stopForeignTraf var usedCount = configured - unused.length; var unusedPct = (unused.length / configured * 100).toFixed(1); var listHtml = unused.map(function(name) { return esc(name); }).join(', '); - utilEl.innerHTML = - '

Region Utilization

' + - '

' + - 'All-time, not limited to the window above — has this configured region ever matched a message still in retention?' + - '

' + + utilEl.innerHTML = detailsSection( + 'Region Utilization (' + usedCount.toLocaleString() + ' of ' + configured.toLocaleString() + ' used)', + 'All-time, not limited to the window above — has this configured region ever matched a message still in retention?', '

' + '' + usedCount.toLocaleString() + ' of ' + configured.toLocaleString() + ' configured regions have matched at least once' + (unused.length > 0 ? ' — ' + unused.length.toLocaleString() + ' (' + unusedPct + '%) have never matched anything.' : '.') + @@ -4812,7 +4821,8 @@ function destroy() { _stopRolesRefresh(); _stopScopesRefresh(); _stopForeignTraf (unused.length > 0 ? '

Show ' + unused.length.toLocaleString() + ' unused region' + (unused.length === 1 ? '' : 's') + '' + '
' + listHtml + '
' - : ''); + : '') + ); } else { utilEl.innerHTML = ''; } @@ -4842,10 +4852,12 @@ function destroy() { _stopRolesRefresh(); _stopScopesRefresh(); _stopForeignTraf ''; }).join('') : '

No data yet — path resolution catches up gradually as traffic flows; check back in a few minutes.

'; - el.innerHTML = - '

' + esc(title) + '

' + - '

' + esc(description) + '

' + - body; + var count = groups ? groups.length : 0; + el.innerHTML = detailsSection( + esc(title) + ' (' + count.toLocaleString() + ' region' + (count === 1 ? '' : 's') + ')', + esc(description), + body + ); } renderRegionNodeGroups('scopes-repeaters', 'Repeaters by Region', @@ -4877,12 +4889,11 @@ function destroy() { _stopRolesRefresh(); _stopScopesRefresh(); _stopForeignTraf // empty longer, especially right after a restart. bridgeBody = '

No bridge repeaters found yet — this needs a repeater confirmed in 2+ different regions, which takes longer to accumulate than the single-region data above.

'; } - bridgeEl.innerHTML = - '

Bridge Repeaters

' + - '

' + - 'All-time — repeaters that have relayed traffic for more than one region. These connect otherwise-separate regional communities; losing one can split the mesh\'s regional coverage.' + - '

' + - bridgeBody; + bridgeEl.innerHTML = detailsSection( + 'Bridge Repeaters (' + bridges.length.toLocaleString() + ')', + 'All-time — repeaters that have relayed traffic for more than one region. These connect otherwise-separate regional communities; losing one can split the mesh\'s regional coverage.', + bridgeBody + ); } renderRegionNodeGroups('scopes-origin-nodes', 'Nodes Running This Region', @@ -4917,15 +4928,14 @@ function destroy() { _stopRolesRefresh(); _stopScopesRefresh(); _stopForeignTraf noScopeBody = '

Every known node has a configured scope.

'; } - noScopeEl.innerHTML = - '

Nodes Not Using Any Scope (' + noScope.total.toLocaleString() + ' of ' + allNodes.length.toLocaleString() + ')

' + - '

' + - 'Nodes with no default_scope at all — never configured a hashRegions region for themselves. By role: ' + (roleSummary || 'none') + '. ' + - 'Sorted by most-recently-active first' + (noScope.truncated ? ' (showing the ' + noScope.sortedCapped.length + ' most recent)' : '') + '.' + - '

' + - noScopeBody; + noScopeEl.innerHTML = detailsSection( + 'Nodes Not Using Any Scope (' + noScope.total.toLocaleString() + ' of ' + allNodes.length.toLocaleString() + ')', + 'Nodes with no default_scope at all — never configured a hashRegions region for themselves. By role: ' + (roleSummary || 'none') + '. ' + + 'Sorted by most-recently-active first' + (noScope.truncated ? ' (showing the ' + noScope.sortedCapped.length + ' most recent)' : '') + '.', + noScopeBody + ); } catch (e) { - noScopeEl.innerHTML = '

Nodes Not Using Any Scope

Failed to load.

'; + noScopeEl.innerHTML = detailsSection('Nodes Not Using Any Scope', null, '

Failed to load.

'); } } @@ -4954,15 +4964,14 @@ function destroy() { _stopRolesRefresh(); _stopScopesRefresh(); _stopForeignTraf } else { neverRelayBody = '

Every known repeater/room has relayed at least one region-scoped packet.

'; } - neverRelayEl.innerHTML = - '

Repeaters Never Relaying Any Scope (' + neverRelay.total.toLocaleString() + ')

' + - '

' + - 'Repeater/room nodes that have never carried a single region-scoped (TRANSPORT_FLOOD/DIRECT) packet, ever — not the same set as "no default_scope" above: a repeater\'s hashRegions config can let it relay for others even when its own adverts never carry a matching transport code. ' + - 'Sorted by current relay volume — the busiest ones are the most consequential to configure first' + (neverRelay.truncated ? ' (showing the top ' + neverRelay.sortedCapped.length + ')' : '') + '.' + - '

' + - neverRelayBody; + neverRelayEl.innerHTML = detailsSection( + 'Repeaters Never Relaying Any Scope (' + neverRelay.total.toLocaleString() + ')', + 'Repeater/room nodes that have never carried a single region-scoped (TRANSPORT_FLOOD/DIRECT) packet, ever — not the same set as "no default_scope" above: a repeater\'s hashRegions config can let it relay for others even when its own adverts never carry a matching transport code. ' + + 'Sorted by current relay volume — the busiest ones are the most consequential to configure first' + (neverRelay.truncated ? ' (showing the top ' + neverRelay.sortedCapped.length + ')' : '') + '.', + neverRelayBody + ); } catch (e) { - neverRelayEl.innerHTML = '

Repeaters Never Relaying Any Scope

Failed to load.

'; + neverRelayEl.innerHTML = detailsSection('Repeaters Never Relaying Any Scope', null, '

Failed to load.

'); } } }