dashboard: live cache-age indicator
The web server's dashboardStats now reports how stale its shared cache
snapshot is — data.cache = { enabled, ttlMs, ageMs }, using the age of the
oldest dataset feeding the view (OLT-STATE, plus ONU-STATE under detailed
scan). cache.js gains ageOf(key).
The dashboard renders a live-ticking badge from it (renderCacheBadge):
- within TTL -> "◷ cached Ns ago" (info)
- past TTL -> same, warn-coloured (next load will refetch)
- no cache -> "● live" (Electron app, or PFW_CACHE_TTL_SECONDS=0)
The Dashboard Refresh button now sends fresh:true to bypass the cache and
reset the age; the detailed-stats toggle and auto-loads use the cache.
Shared renderer change, so the Electron app shows "live" (it sends no cache
field). Verified offscreen over HTTP: cached / stale / live states render
with the right text + colour.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
6ee1d37a79
commit
c2206ad5a7
6 changed files with 84 additions and 5 deletions
|
|
@ -1551,8 +1551,10 @@ $('#btn-olt-execute').addEventListener('click', async () => {
|
|||
|
||||
// -------- Dashboard: network telemetry --------
|
||||
|
||||
$('#dash-refresh').addEventListener('click', loadDashboard);
|
||||
$('#dash-extra').addEventListener('change', loadDashboard);
|
||||
// Refresh forces a fresh server fetch (bypasses the cache); the toggle and
|
||||
// auto-loads use the cache. Wrap so the DOM event isn't passed as `force`.
|
||||
$('#dash-refresh').addEventListener('click', () => loadDashboard(true));
|
||||
$('#dash-extra').addEventListener('change', () => loadDashboard());
|
||||
|
||||
// Bit-rate formatter, ported from the iOS app's Format.bps.
|
||||
function fmtBps(v) {
|
||||
|
|
@ -1578,6 +1580,44 @@ function fmtDbm(n) {
|
|||
return typeof n === 'number' ? n.toFixed(1) : '—';
|
||||
}
|
||||
|
||||
function fmtAge(ms) {
|
||||
const s = Math.max(0, Math.round(ms / 1000));
|
||||
if (s < 90) return `${s}s`;
|
||||
const m = Math.floor(s / 60);
|
||||
if (m < 60) return `${m}m ${s % 60}s`;
|
||||
return `${Math.floor(m / 60)}h ${m % 60}m`;
|
||||
}
|
||||
|
||||
// Cache-age badge. The web server reports how old its shared cache snapshot
|
||||
// is (`d.cache`); the Electron app sends no cache info → "live". The badge
|
||||
// ticks every second so the operator can see the data going stale.
|
||||
let dashCacheTimer = null;
|
||||
function renderCacheBadge(cache) {
|
||||
const el = $('#dash-cache');
|
||||
if (!el) return;
|
||||
if (dashCacheTimer) { clearInterval(dashCacheTimer); dashCacheTimer = null; }
|
||||
if (!cache || !cache.enabled) {
|
||||
el.className = 'dash-cache status-ok';
|
||||
el.textContent = '● live';
|
||||
el.title = 'Fetched directly from MCMS (no server-side cache).';
|
||||
return;
|
||||
}
|
||||
const ttl = cache.ttlMs || 0;
|
||||
const baseAge = cache.ageMs || 0;
|
||||
const receivedAt = Date.now();
|
||||
const paint = () => {
|
||||
const age = baseAge + (Date.now() - receivedAt);
|
||||
const stale = ttl > 0 && age > ttl;
|
||||
el.className = 'dash-cache ' + (stale ? 'status-warn' : 'status-info');
|
||||
el.textContent = `◷ cached ${fmtAge(age)} ago`;
|
||||
el.title = stale
|
||||
? `Shared server cache is past its ${Math.round(ttl / 1000)}s TTL — the next load refetches from MCMS.`
|
||||
: `Shared server cache (TTL ${Math.round(ttl / 1000)}s) — collapses repeated MCMS requests across operators. Refresh to force-refetch.`;
|
||||
};
|
||||
paint();
|
||||
dashCacheTimer = setInterval(paint, 1000);
|
||||
}
|
||||
|
||||
function dashHealthRow(title, detail, count, drillKey) {
|
||||
const cls = count > 0 ? 'status-warn' : 'status-ok';
|
||||
const tappable = drillKey && count > 0;
|
||||
|
|
@ -1613,13 +1653,13 @@ function showListModal(title, items) {
|
|||
overlay.querySelector('.modal-ok').focus();
|
||||
}
|
||||
|
||||
async function loadDashboard() {
|
||||
async function loadDashboard(force) {
|
||||
const extra = $('#dash-extra').checked;
|
||||
$('#dash-status').textContent = extra
|
||||
? 'Loading network + per-ONU Rx/FEC scan… (this fetches every ONU-STATE)'
|
||||
: 'Loading network overview…';
|
||||
$('#dash-refresh').disabled = true;
|
||||
const res = await window.api.dashboardStats({ extraStats: extra });
|
||||
const res = await window.api.dashboardStats({ extraStats: extra, fresh: !!force });
|
||||
$('#dash-refresh').disabled = false;
|
||||
if (!res.ok) {
|
||||
$('#dash-status').textContent = `Error: ${res.error?.message || 'unknown'}`;
|
||||
|
|
@ -1741,4 +1781,6 @@ function renderDashboard(d) {
|
|||
const stamp = d.sampledAt ? new Date(d.sampledAt).toLocaleTimeString() : '';
|
||||
$('#dash-status').textContent =
|
||||
`${d.onuTotal} ONUs · ${d.oltCount} OLTs${d.extraStats ? ' · detailed scan' : ''}${stamp ? ' · ' + stamp : ''}`;
|
||||
|
||||
renderCacheBadge(d.cache);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue