dashboard: tick question TTL chip every second
The `⏳ MM:SS` chip on an asked-with-timeout question was rendered once and then frozen — the operator saw stale info (e.g. 48s sitting unchanged for the whole TTL window) (issue #335). Stamp the deadline onto the chip as `data-deadline` and run a single page-wide setInterval that refreshes every `.q-ttl[data- deadline]`'s textContent each second. No re-render of the questions section; no new state on the client. No-op when no chips are on screen. Also pulls the bucketed seconds-to-string logic into a `formatTtl` helper so the renderer and the ticker share one source of truth. Closes #335.
This commit is contained in:
parent
5887111327
commit
6f3b56ad84
1 changed files with 40 additions and 9 deletions
|
|
@ -1028,15 +1028,17 @@
|
|||
el('span', { class: 'msg-sep' }, 'asks:'),
|
||||
);
|
||||
if (q.deadline_at) {
|
||||
const remaining = q.deadline_at - Math.floor(Date.now() / 1000);
|
||||
let txt;
|
||||
if (remaining <= 0) txt = 'expiring…';
|
||||
else if (remaining < 60) txt = '⏳ ' + remaining + 's';
|
||||
else if (remaining < 3600) txt = '⏳ ' + Math.floor(remaining / 60) + 'm '
|
||||
+ (remaining % 60) + 's';
|
||||
else txt = '⏳ ' + Math.floor(remaining / 3600) + 'h '
|
||||
+ Math.floor((remaining % 3600) / 60) + 'm';
|
||||
head.append(' ', el('span', { class: 'q-ttl' }, txt));
|
||||
// Tag the chip with its deadline so the global 1s ticker
|
||||
// (set up just below this function) can refresh the text
|
||||
// without re-rendering the whole questions section
|
||||
// (issue #335).
|
||||
const ttlEl = el('span', {
|
||||
class: 'q-ttl', 'data-deadline': String(q.deadline_at),
|
||||
});
|
||||
ttlEl.textContent = formatTtl(
|
||||
q.deadline_at - Math.floor(Date.now() / 1000),
|
||||
);
|
||||
head.append(' ', ttlEl);
|
||||
}
|
||||
const qBody = el('div', { class: 'q-body' });
|
||||
appendLinkified(qBody, q.question, q.question_refs);
|
||||
|
|
@ -1156,6 +1158,35 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Format a remaining-seconds count as the `⏳ …` TTL chip text on a
|
||||
// question card. Bucketed at minutes / hours so a long deadline stays
|
||||
// readable; "expiring…" once the deadline has passed (the host-side
|
||||
// ttl-watchdog will fire shortly).
|
||||
function formatTtl(remaining) {
|
||||
if (remaining <= 0) return 'expiring…';
|
||||
if (remaining < 60) return '⏳ ' + remaining + 's';
|
||||
if (remaining < 3600) {
|
||||
return '⏳ ' + Math.floor(remaining / 60) + 'm '
|
||||
+ (remaining % 60) + 's';
|
||||
}
|
||||
return '⏳ ' + Math.floor(remaining / 3600) + 'h '
|
||||
+ Math.floor((remaining % 3600) / 60) + 'm';
|
||||
}
|
||||
|
||||
// Single page-wide ticker that refreshes every TTL chip in place
|
||||
// each second (issue #335). Renderers stamp `data-deadline` on the
|
||||
// chip; this just updates `textContent`, no re-render of the
|
||||
// questions section. No-op when no chips are on screen, so the
|
||||
// cost is negligible.
|
||||
setInterval(() => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
document.querySelectorAll('.q-ttl[data-deadline]').forEach((node) => {
|
||||
const deadline = Number(node.getAttribute('data-deadline'));
|
||||
if (!Number.isFinite(deadline)) return;
|
||||
node.textContent = formatTtl(deadline - now);
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
// ─── operator inbox (derived from the broker message stream) ───────────
|
||||
// No longer shipped on `/api/state.operator_inbox`. The dashboard
|
||||
// terminal's HiveTerminal feeds this via `onAnyEvent` — backfill from
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue