// screens-resources.jsx // Live CPU/RAM/GPU gauges for Dashboard. Polls /api/v1/cluster/metrics every 5s. // Falls back to mock data when endpoint unavailable. const RESOURCE_MOCK={nodes:[ {hostname:"zampp1",cpu_util_pct:42,ram_used_mb:14336,ram_total_mb:32768, gpus:[{name:"RTX 3060",util_pct:67,memory_used_mb:5120,memory_total_mb:12288}]}, {hostname:"zampp2",cpu_util_pct:18,ram_used_mb:8192,ram_total_mb:32768, gpus:[{name:"RTX 3060",util_pct:12,memory_used_mb:1024,memory_total_mb:12288}]}, ]}; function useClusterMetrics(){ const [data,setData]=React.useState(null); const [usingMock,setUsingMock]=React.useState(false); React.useEffect(()=>{ let cancelled=false; const load=()=>{ window.ZAMPP_API.fetch('/cluster/metrics') .then(d=>{ if(cancelled)return; if(d&&Array.isArray(d.nodes)&&d.nodes.length>0){ setData(d);setUsingMock(false); }else{setData(RESOURCE_MOCK);setUsingMock(true);} }) .catch(()=>{if(!cancelled){setData(RESOURCE_MOCK);setUsingMock(true);}}); }; load(); const t=setInterval(load,5000); return ()=>{cancelled=true;clearInterval(t);}; },[]); return {data,usingMock}; } function ResBar({pct,color}){ const p=Math.min(100,Math.max(0,Math.round(pct||0))); const c=color||(p>85?'var(--warning)':p>60?'var(--accent)':'var(--success)'); return (