// screens-home.jsx function Home({ navigate }) { const { RECORDERS, JOBS, ASSETS, NODES } = window.ZAMPP_DATA; // Live (current-state) data from the boot-time data load const liveRecorders = RECORDERS.filter(r => r.status === 'recording').slice(0, 4); const runningJobs = JOBS.filter(j => j.status === 'running' || j.status === 'queued'); const recentAssets = [...ASSETS].sort((a, b) => new Date(b.created_at) - new Date(a.created_at)).slice(0, 6); // Real historic sparklines from /metrics/home — buckets the last 24h. const [metrics, setMetrics] = React.useState(null); React.useEffect(() => { let cancelled = false; const load = () => { window.ZAMPP_API.fetch('/metrics/home?hours=24') .then(d => { if (!cancelled) setMetrics(d); }) .catch(() => {}); }; load(); const t = setInterval(load, 30_000); return () => { cancelled = true; clearInterval(t); }; }, []); const cards = metrics?.cards || {}; const vals = (s) => Array.isArray(s) ? s.map(p => p.v) : []; // Card values come from /metrics so that "Library" reflects what's in the // DB right now, not whatever ZAMPP_DATA happens to be cached as on first load. const assetsTotal = cards.assets?.total ?? ASSETS.length; const liveCount = cards.recorders?.live ?? liveRecorders.length; const totalRecs = cards.recorders?.total ?? RECORDERS.length; const runningCount = cards.jobs?.running ?? runningJobs.length; const doneCount = cards.jobs?.done_total ?? JOBS.filter(j => j.status === 'done').length; const failedCount = cards.jobs?.failed_total ?? JOBS.filter(j => j.status === 'failed').length; const nodesOnline = cards.cluster?.online ?? NODES.filter(n => n.status === 'online' || n.online === true).length; const nodesTotal = cards.cluster?.total ?? NODES.length; // Sum the most recent hour of each bucketed series for the delta line so // the "+N this hour" hint always reflects the latest bucket. const lastBucket = (series) => (Array.isArray(series) && series.length ? series[series.length - 1].v : 0); const sumWindow = (series) => (Array.isArray(series) ? series.reduce((a, p) => a + p.v, 0) : 0); return (
{liveCount > 0 ? liveCount + ' live · ' : ''} {runningCount > 0 ? runningCount + ' job' + (runningCount > 1 ? 's running' : ' running') + ' · ' : ''} {assetsTotal.toLocaleString()} assets