{/* Header */}
{node.node_name}
{node.zone || '—'}
{/* Error banner */}
{!node.online && (
{node.error ?? 'offline'}
)}
{node.online && (
<>
{/* Storage bars */}
{node.filesystem && (
)}
{node.hot && node.hot.max_bytes > 0 && (
)}
{/* One-liner facts */}
mount
{node.mount?.active ? (
✓ mounted
) : (
not mounted
)}
cache hit rate
{node.cache && node.cache.hits + node.cache.misses > 0
? `${Math.round(node.cache.hit_rate * 100)}%`
: idle}
next scheduled job
{nextTimer(node)}
>
)}
);
}
function healthOf(n: NodeStatusV2): 'ok' | 'warn' | 'err' | 'idle' {
if (!n.online) return 'err';
const fsPct = n.filesystem
? n.filesystem.used_bytes / Math.max(n.filesystem.total_bytes, 1)
: 0;
const anyFailed = n.timers.some(
(t) => t.last_result && t.last_result !== 'success'
);
if (fsPct > 0.9 || anyFailed) return 'err';
if (fsPct > 0.75) return 'warn';
if (n.mount && !n.mount.active) return 'warn';
return 'ok';
}
function nextTimer(n: NodeStatusV2): React.ReactNode {
const next = n.timers
.filter((t) => t.next_fire_unix)
.sort((a, b) => (a.next_fire_unix ?? 0) - (b.next_fire_unix ?? 0))[0];
if (!next?.next_fire_unix) return