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 nowUnix = Math.floor(Date.now() / 1000);
|
||||||
const ageStr = ds.status_set_at != null
|
const ageStr = ds.status_set_at != null
|
||||||
? ` (set ${fmtAgeSecs(nowUnix - ds.status_set_at)} ago)` : '';
|
? ` (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', {
|
body.append(el('div', {
|
||||||
class: 'agent-status',
|
class: 'agent-status',
|
||||||
title: `agent self-reported status${ageStr}`,
|
title: `agent self-reported status${ageStr}`,
|
||||||
},
|
},
|
||||||
el('span', { class: 'status-icon' }, '◈ '),
|
el('span', { class: 'status-icon' }, '◈ '),
|
||||||
ds.status_text,
|
ds.status_text,
|
||||||
el('span', { class: 'status-age' }, ageStr),
|
el('span', ageAttrs, ageStr),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -1896,6 +1901,20 @@ window.marked = marked;
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 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';
|
const APPROVAL_TAB_KEY = 'hyperhive:approvals:tab';
|
||||||
// Derived approval state — cold-loaded from /api/state, then mutated
|
// Derived approval state — cold-loaded from /api/state, then mutated
|
||||||
// live by `approval_added` / `approval_resolved` dashboard events.
|
// live by `approval_added` / `approval_resolved` dashboard events.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue