hyperhive/frontend/packages/dashboard/src/util.js
atlas 39b95c2ede treefmt: apply prettier
Pure `nix fmt` output from the commit before this one — no hand edits.
203 files: 52 md, 42 tsx, 32 js, 32 css, 21 ts, 13 html, 8 json, 3 mjs.

Reproduce with `nix develop -c nix fmt` on the parent commit; the result
should be byte-identical to this tree.

None of the 13 `.prettierignore` entries appears here — verified by
intersecting the changed-file list against the ignore file, with a
control proving the intersection finds a match when one exists.
2026-09-02 15:25:07 +02:00

69 lines
2.6 KiB
JavaScript

// Shared dashboard render + format helpers.
//
// Small pure utilities used across most dashboard tabs (the container
// tree, the rebuild queue, 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"
);
}