feat(dashboard): live-tick agent status-age chip via data-set-at + 30s interval
Stamp data-set-at on .status-age spans so the '(set N ago)' label stays accurate as time passes. Previously the age was computed once when the async dashboard-state fetch completed and never updated. With the keyed container row cache, rows persist much longer between rebuilds (no more full rebuild on every SSE event), making stale status-age labels more noticeable. The 30s ticker fixes this without requiring a full row rebuild or re-fetch.
This commit is contained in:
parent
f011638b5e
commit
2a5444fdc8
1 changed files with 20 additions and 1 deletions
|
|
@ -737,13 +737,18 @@ window.marked = marked;
|
|||
const nowUnix = Math.floor(Date.now() / 1000);
|
||||
const ageStr = ds.status_set_at != null
|
||||
? ` (set ${fmtAgeSecs(nowUnix - ds.status_set_at)} ago)` : '';
|
||||
// Stamp data-set-at so the 30s ticker below keeps the age
|
||||
// label current even when the row is reused from the cache.
|
||||
const ageAttrs = ds.status_set_at != null
|
||||
? { class: 'status-age', 'data-set-at': String(ds.status_set_at) }
|
||||
: { class: 'status-age' };
|
||||
body.append(el('div', {
|
||||
class: 'agent-status',
|
||||
title: `agent self-reported status${ageStr}`,
|
||||
},
|
||||
el('span', { class: 'status-icon' }, '◈ '),
|
||||
ds.status_text,
|
||||
el('span', { class: 'status-age' }, ageStr),
|
||||
el('span', ageAttrs, ageStr),
|
||||
));
|
||||
}
|
||||
})
|
||||
|
|
@ -1896,6 +1901,20 @@ window.marked = marked;
|
|||
});
|
||||
}, 1000);
|
||||
|
||||
// 30s ticker for agent status-age chips. Renderers stamp `data-set-at`
|
||||
// (unix seconds) on the `.status-age` span. Keyed container rows persist
|
||||
// across re-renders, so without this ticker the "(set N ago)" label would
|
||||
// become stale as time passes. 30s granularity matches fmtAgeSecs precision
|
||||
// (sub-minute values round to seconds, coarser above that).
|
||||
setInterval(() => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
document.querySelectorAll('.status-age[data-set-at]').forEach((node) => {
|
||||
const setAt = Number(node.dataset.setAt);
|
||||
if (!Number.isFinite(setAt) || setAt === 0) return;
|
||||
node.textContent = ` (set ${fmtAgeSecs(now - setAt)} ago)`;
|
||||
});
|
||||
}, 30_000);
|
||||
|
||||
const APPROVAL_TAB_KEY = 'hyperhive:approvals:tab';
|
||||
// Derived approval state — cold-loaded from /api/state, then mutated
|
||||
// live by `approval_added` / `approval_resolved` dashboard events.
|
||||
|
|
|
|||
Loading…
Reference in a new issue