diff --git a/public_html/admin/index.php b/public_html/admin/index.php index bd1a80f..2ffaa0a 100644 --- a/public_html/admin/index.php +++ b/public_html/admin/index.php @@ -827,53 +827,49 @@ function scanShell(tblWrapId, headers, titleEl, scanLabel) { } // ── AGENTS ──────────────────────────────────────────────────────────────────── +const miniBar = (pct, warn=70, crit=85) => { + if (pct == null) return '—'; + const c = pct>=crit?'var(--red)':pct>=warn?'var(--yellow)':'var(--green)'; + return `${Math.round(pct)}%`; +}; + async function loadAgents() { - const tbl = document.getElementById('agents-tbl'); + const tbl = document.getElementById('agents-tbl'); const title = document.getElementById('agents-title'); - // Build empty table shell immediately — no waiting - tbl.innerHTML = ` - -
HOSTNAMESTATUSTYPEIPMETRICSLAST SEENREGISTERED
`; - + tbl.innerHTML = ` + +
HOSTNAMESTATUSTYPEIPMETRICSLAST SEENREGISTERED
`; title.innerHTML = 'AGENTS SCANNING...'; - const agents = await api('agents_list'); - const tbody = document.getElementById('agents-tbody'); + let agents; + try { agents = await api('agents_list'); } + catch(e) { tbl.innerHTML='
ERROR LOADING AGENTS
'; title.textContent='AGENTS'; return; } - if (!agents.length) { + if (!Array.isArray(agents) || !agents.length) { tbl.innerHTML = '
NO AGENTS REGISTERED
'; title.textContent = 'AGENTS'; return; } - // Reveal each agent row with a staggered delay agents.forEach((a, i) => { setTimeout(() => { + const tbody = document.getElementById('agents-tbody'); + if (!tbody) return; const m = a.metrics; const online = a.status === 'online'; const lastSeen = a.last_seen ? (Date.now() - new Date(a.last_seen)) / 1000 : null; const fresh = lastSeen !== null && lastSeen < 30; - - // CPU/RAM mini bars - let meterCell = `no metrics`; - if (m) { - function miniBar(pct, warn=70, crit=85) { - if (pct == null) return '—'; - const c = pct>=crit?'var(--red)':pct>=warn?'var(--yellow)':'var(--green)'; - return `${Math.round(pct)}%`; - } - meterCell = `CPU ${miniBar(m.cpu_pct)} · RAM ${miniBar(m.mem_pct)} · DISK ${miniBar(m.disk_pct,80,90)}`; - } + const meterCell = m + ? `CPU ${miniBar(m.cpu_pct)} · RAM ${miniBar(m.mem_pct)} · DISK ${miniBar(m.disk_pct,80,90)}` + : `no metrics`; const row = document.createElement('tr'); row.className = 'agent-row'; - row.style.animationDelay = '0s'; row.innerHTML = ` - - + ${esc(a.hostname)} - ${fresh && online ? '● LIVE' : ''} + ${fresh&&online?'● LIVE':''} ${statusBadge(a.status)} ${esc(a.agent_type||'linux').toUpperCase()} @@ -882,15 +878,14 @@ async function loadAgents() { ${ago(a.last_seen)} ${ts(a.created_at)} `; - tbody?.appendChild(row); + tbody.appendChild(row); - // Update title counter as agents appear const found = i + 1; - const online_count = agents.slice(0, found).filter(x => x.status === 'online').length; - if (title) title.innerHTML = found < agents.length + const onlineCt = agents.slice(0, found).filter(x => x.status === 'online').length; + title.innerHTML = found < agents.length ? `AGENTS SCANNING... ${found}/${agents.length}` - : `AGENTS ${online_count} ONLINE / ${agents.length} TOTAL`; - }, i * 120); // 120ms stagger per agent + : `AGENTS ${onlineCt} ONLINE / ${agents.length} TOTAL`; + }, i * 120); }); }