58 lines
2.6 KiB
JavaScript
58 lines
2.6 KiB
JavaScript
// Shared dashboard render + format helpers.
|
|
//
|
|
// Small pure utilities used across most dashboard tabs (the container
|
|
// tree, the rebuild queue, questions / approvals, schedules + reminders):
|
|
// an atomic-swap render helper and a handful of relative-time / duration
|
|
// formatters. They live here — a dashboard-internal module — rather than
|
|
// in the cross-page `common.js`, because they're specific to the
|
|
// dashboard's render style and not needed by the stand-alone pages.
|
|
//
|
|
// All pure: no DOM/module state captured, so any tab module can import
|
|
// them freely without ordering concerns.
|
|
|
|
// Atomic-swap render: build into an off-DOM DocumentFragment, then commit
|
|
// with a single `replaceChildren`. Avoids an intermediate empty-state
|
|
// flash on poll cycles even when the builder allocates a lot of nodes.
|
|
export function paintAtomic(liveRoot, build) {
|
|
const buf = document.createDocumentFragment();
|
|
build(buf);
|
|
liveRoot.replaceChildren(buf);
|
|
}
|
|
|
|
// Epoch seconds from an API timestamp. The hive-c0re dashboard API
|
|
// ships timestamps as RFC 3339 strings; a few feeds (rebuild queue,
|
|
// meta inputs, turn stats) still carry unix-second numbers, so
|
|
// numbers pass through unchanged.
|
|
export function epochSec(ts) {
|
|
return typeof ts === 'number' ? ts : Math.floor(Date.parse(ts) / 1000);
|
|
}
|
|
|
|
// Relative age of a timestamp (RFC 3339 string or unix seconds),
|
|
// coarsened to one unit ("5m ago").
|
|
export function fmtAgo(ts) {
|
|
const ageSec = Math.max(0, Math.floor(Date.now() / 1000 - epochSec(ts)));
|
|
if (ageSec < 60) return ageSec + 's ago';
|
|
if (ageSec < 3600) return Math.floor(ageSec / 60) + 'm ago';
|
|
if (ageSec < 86400) return Math.floor(ageSec / 3600) + 'h ago';
|
|
return Math.floor(ageSec / 86400) + 'd ago';
|
|
}
|
|
|
|
// Truncate a string to `n` chars, appending an ellipsis when clipped.
|
|
export function truncate(s, n) {
|
|
return s.length <= n ? s : s.slice(0, n - 1) + '…';
|
|
}
|
|
|
|
// Running-duration label for in-flight items ("3m 12s running").
|
|
export function fmtElapsed(secs) {
|
|
if (secs < 60) return secs + 's running';
|
|
if (secs < 3600) return Math.floor(secs / 60) + 'm ' + (secs % 60) + 's running';
|
|
return Math.floor(secs / 3600) + 'h ' + Math.floor((secs % 3600) / 60) + 'm running';
|
|
}
|
|
|
|
// Compact duration label, two units deep ("1h 5m", "2d 3h").
|
|
export function fmtDuration(secs) {
|
|
if (secs < 60) return secs + 's';
|
|
if (secs < 3600) return Math.floor(secs / 60) + 'm ' + (secs % 60) + 's';
|
|
if (secs < 86400) return Math.floor(secs / 3600) + 'h ' + Math.floor((secs % 3600) / 60) + 'm';
|
|
return Math.floor(secs / 86400) + 'd ' + Math.floor((secs % 86400) / 3600) + 'h';
|
|
}
|