mirror of
https://github.com/myronblair/jarvis
synced 2026-06-30 17:50:23 -05:00
Fix agents render: move miniBar outside setTimeout scope, add Array.isArray guard
This commit is contained in:
+26
-31
@@ -827,53 +827,49 @@ function scanShell(tblWrapId, headers, titleEl, scanLabel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── AGENTS ────────────────────────────────────────────────────────────────────
|
// ── 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 `<span style="color:${c}">${Math.round(pct)}%</span>`;
|
||||||
|
};
|
||||||
|
|
||||||
async function loadAgents() {
|
async function loadAgents() {
|
||||||
const tbl = document.getElementById('agents-tbl');
|
const tbl = document.getElementById('agents-tbl');
|
||||||
const title = document.getElementById('agents-title');
|
const title = document.getElementById('agents-title');
|
||||||
|
|
||||||
// Build empty table shell immediately — no waiting
|
tbl.innerHTML = `<table><thead><tr>
|
||||||
tbl.innerHTML = `<table id="agents-table">
|
<th>HOSTNAME</th><th>STATUS</th><th>TYPE</th><th>IP</th><th>METRICS</th><th>LAST SEEN</th><th>REGISTERED</th><th></th>
|
||||||
<thead><tr><th>HOSTNAME</th><th>STATUS</th><th>TYPE</th><th>IP</th><th>METRICS</th><th>LAST SEEN</th><th>REGISTERED</th><th></th></tr></thead>
|
</tr></thead><tbody id="agents-tbody"></tbody></table>`;
|
||||||
<tbody id="agents-tbody"></tbody></table>`;
|
|
||||||
|
|
||||||
title.innerHTML = 'AGENTS <span style="color:var(--dim);font-size:0.6rem;letter-spacing:2px">SCANNING...</span>';
|
title.innerHTML = 'AGENTS <span style="color:var(--dim);font-size:0.6rem;letter-spacing:2px">SCANNING...</span>';
|
||||||
|
|
||||||
const agents = await api('agents_list');
|
let agents;
|
||||||
const tbody = document.getElementById('agents-tbody');
|
try { agents = await api('agents_list'); }
|
||||||
|
catch(e) { tbl.innerHTML='<div class="empty">ERROR LOADING AGENTS</div>'; title.textContent='AGENTS'; return; }
|
||||||
|
|
||||||
if (!agents.length) {
|
if (!Array.isArray(agents) || !agents.length) {
|
||||||
tbl.innerHTML = '<div class="empty">NO AGENTS REGISTERED</div>';
|
tbl.innerHTML = '<div class="empty">NO AGENTS REGISTERED</div>';
|
||||||
title.textContent = 'AGENTS';
|
title.textContent = 'AGENTS';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reveal each agent row with a staggered delay
|
|
||||||
agents.forEach((a, i) => {
|
agents.forEach((a, i) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
const tbody = document.getElementById('agents-tbody');
|
||||||
|
if (!tbody) return;
|
||||||
const m = a.metrics;
|
const m = a.metrics;
|
||||||
const online = a.status === 'online';
|
const online = a.status === 'online';
|
||||||
const lastSeen = a.last_seen ? (Date.now() - new Date(a.last_seen)) / 1000 : null;
|
const lastSeen = a.last_seen ? (Date.now() - new Date(a.last_seen)) / 1000 : null;
|
||||||
const fresh = lastSeen !== null && lastSeen < 30;
|
const fresh = lastSeen !== null && lastSeen < 30;
|
||||||
|
const meterCell = m
|
||||||
// CPU/RAM mini bars
|
? `<span style="font-size:0.65rem">CPU ${miniBar(m.cpu_pct)} · RAM ${miniBar(m.mem_pct)} · DISK ${miniBar(m.disk_pct,80,90)}</span>`
|
||||||
let meterCell = `<span style="color:var(--dim);font-size:0.65rem">no metrics</span>`;
|
: `<span style="color:var(--dim);font-size:0.65rem">no metrics</span>`;
|
||||||
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 `<span style="color:${c}">${Math.round(pct)}%</span>`;
|
|
||||||
}
|
|
||||||
meterCell = `<span style="font-size:0.65rem">CPU ${miniBar(m.cpu_pct)} · RAM ${miniBar(m.mem_pct)} · DISK ${miniBar(m.disk_pct,80,90)}</span>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const row = document.createElement('tr');
|
const row = document.createElement('tr');
|
||||||
row.className = 'agent-row';
|
row.className = 'agent-row';
|
||||||
row.style.animationDelay = '0s';
|
|
||||||
row.innerHTML = `
|
row.innerHTML = `
|
||||||
<td>
|
<td><span class="dot ${online?'dot-green':'dot-red'}"></span>
|
||||||
<span class="dot ${online ? 'dot-green' : 'dot-red'}"></span>
|
|
||||||
<strong>${esc(a.hostname)}</strong>
|
<strong>${esc(a.hostname)}</strong>
|
||||||
${fresh && online ? '<span style="font-size:0.55rem;color:var(--green);margin-left:4px">● LIVE</span>' : ''}
|
${fresh&&online?'<span style="font-size:0.55rem;color:var(--green);margin-left:4px">● LIVE</span>':''}
|
||||||
</td>
|
</td>
|
||||||
<td>${statusBadge(a.status)}</td>
|
<td>${statusBadge(a.status)}</td>
|
||||||
<td><span class="badge badge-cyan">${esc(a.agent_type||'linux').toUpperCase()}</span></td>
|
<td><span class="badge badge-cyan">${esc(a.agent_type||'linux').toUpperCase()}</span></td>
|
||||||
@@ -882,15 +878,14 @@ async function loadAgents() {
|
|||||||
<td class="ts">${ago(a.last_seen)}</td>
|
<td class="ts">${ago(a.last_seen)}</td>
|
||||||
<td class="ts">${ts(a.created_at)}</td>
|
<td class="ts">${ts(a.created_at)}</td>
|
||||||
<td><button class="btn btn-xs btn-red" onclick="delAgent('${esc(a.agent_id)}','${esc(a.hostname)}')">DEL</button></td>`;
|
<td><button class="btn btn-xs btn-red" onclick="delAgent('${esc(a.agent_id)}','${esc(a.hostname)}')">DEL</button></td>`;
|
||||||
tbody?.appendChild(row);
|
tbody.appendChild(row);
|
||||||
|
|
||||||
// Update title counter as agents appear
|
|
||||||
const found = i + 1;
|
const found = i + 1;
|
||||||
const online_count = agents.slice(0, found).filter(x => x.status === 'online').length;
|
const onlineCt = agents.slice(0, found).filter(x => x.status === 'online').length;
|
||||||
if (title) title.innerHTML = found < agents.length
|
title.innerHTML = found < agents.length
|
||||||
? `AGENTS <span style="color:var(--dim);font-size:0.6rem;letter-spacing:2px">SCANNING... ${found}/${agents.length}</span>`
|
? `AGENTS <span style="color:var(--dim);font-size:0.6rem;letter-spacing:2px">SCANNING... ${found}/${agents.length}</span>`
|
||||||
: `AGENTS <span style="color:var(--cyan);font-size:0.6rem;letter-spacing:2px">${online_count} ONLINE / ${agents.length} TOTAL</span>`;
|
: `AGENTS <span style="color:var(--cyan);font-size:0.6rem;letter-spacing:2px">${onlineCt} ONLINE / ${agents.length} TOTAL</span>`;
|
||||||
}, i * 120); // 120ms stagger per agent
|
}, i * 120);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user