// ─── Dashboard Page ────────────────────────────────────────────────────────── const { useState: uDS, useEffect: uDE, useRef: uDR } = React; function useMetricsHistory(key, interval = 3000) { const [history, setHistory] = uDS(Array(60).fill(0)); const metrics = usePolling('/api/system/metrics', interval); uDE(() => { if (!metrics) return; const val = key === 'cpu' ? metrics.cpu_pct : metrics.ram_pct; setHistory(prev => [...prev.slice(-59), val]); }, [metrics]); return [history, metrics]; } function useNetHistory(interval = 3000) { const [prevCounters, setPrev] = uDS(null); const [inHistory, setIn] = uDS(Array(60).fill(0)); const [outHistory, setOut] = uDS(Array(60).fill(0)); const net = usePolling('/api/system/network', interval); uDE(() => { if (!net) return; if (prevCounters) { const inMBps = Math.max(0, (net.bytes_recv - prevCounters.bytes_recv) / 1e6 / (interval / 1000)); const outMBps = Math.max(0, (net.bytes_sent - prevCounters.bytes_sent) / 1e6 / (interval / 1000)); setIn(prev => [...prev.slice(-59), +inMBps.toFixed(2)]); setOut(prev => [...prev.slice(-59), +outMBps.toFixed(2)]); } setPrev(net); }, [net]); return [inHistory, outHistory]; } function formatUptime(seconds) { const d = Math.floor(seconds / 86400); const h = Math.floor((seconds % 86400) / 3600); const m = Math.floor((seconds % 3600) / 60); return [String(d).padStart(2,'0'), String(h).padStart(2,'0'), String(m).padStart(2,'0')]; } function DashboardPage() { const [cpuHistory, metrics] = useMetricsHistory('cpu', 3000); const [ramHistory] = useMetricsHistory('ram', 3000); const [netInHistory, netOutHistory] = useNetHistory(3000); const disks = usePolling('/api/system/disks', 10000); const processes = usePolling('/api/system/processes', 5000); const cpu = metrics ? metrics.cpu_pct : 0; const ram = metrics ? metrics.ram_pct : 0; const ramUsed = metrics ? metrics.ram_used_gb : 0; const ramTotal = metrics ? metrics.ram_total_gb : 0; const uptimeParts = metrics ? formatUptime(metrics.uptime_seconds) : ['--','--','--']; const loadAvg = metrics ? metrics.load_avg.map(v => v.toFixed(2)).join(' / ') : '—'; const kernel = metrics ? metrics.kernel : '—'; const os_name = metrics ? metrics.os : '—'; const hostname = metrics ? metrics.hostname : '—'; const diskRows = disks || []; const procRows = (processes || []).slice(0, 6).map(p => ({ ...p, cpu: p.cpu_pct, mem: p.mem_pct })); const netIn = netInHistory[netInHistory.length - 1] || 0; const netOut = netOutHistory[netOutHistory.length - 1] || 0; return (