feat(ui): show host status, simplex and absent protocols
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uc9V1v7iXruubpoLiSE24M
This commit is contained in:
@@ -73,6 +73,7 @@
|
|||||||
.tipbox .up { color: var(--st-ok); font-weight: 700; }
|
.tipbox .up { color: var(--st-ok); font-weight: 700; }
|
||||||
.tipbox .dn { color: var(--st-crit); font-weight: 700; }
|
.tipbox .dn { color: var(--st-crit); font-weight: 700; }
|
||||||
.tipbox .ov { color: var(--st-warn); font-weight: 700; }
|
.tipbox .ov { color: var(--st-warn); font-weight: 700; }
|
||||||
|
.tipbox .ab { color: var(--st-faint); font-weight: 700; }
|
||||||
.tipbox .meta { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--st-line-soft); font-size: 11px; color: var(--st-faint); }
|
.tipbox .meta { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--st-line-soft); font-size: 11px; color: var(--st-faint); }
|
||||||
|
|
||||||
@media (max-width: 760px) {
|
@media (max-width: 760px) {
|
||||||
@@ -134,18 +135,18 @@
|
|||||||
function worstConnection(data) {
|
function worstConnection(data) {
|
||||||
var worst = null;
|
var worst = null;
|
||||||
(data.connections || []).forEach(function (c) {
|
(data.connections || []).forEach(function (c) {
|
||||||
if (!c.state || c.state === 'unknown') return;
|
if (!c.state || c.state === 'unknown' || c.state === 'absent') return;
|
||||||
if (!worst || (STATE_RANK[c.state] || 0) > (STATE_RANK[worst.state] || 0)) worst = c;
|
if (!worst || (STATE_RANK[c.state] || 0) > (STATE_RANK[worst.state] || 0)) worst = c;
|
||||||
});
|
});
|
||||||
return worst;
|
return worst;
|
||||||
}
|
}
|
||||||
|
|
||||||
function severity(data) {
|
function severity(data) {
|
||||||
var w = worstConnection(data);
|
var st = data.status;
|
||||||
if ((data.alert_critical_unacked || 0) > 0 || (data.alert_critical_acked || 0) > 0) return 'crit';
|
if ((data.alert_critical_unacked || 0) > 0 || (data.alert_critical_acked || 0) > 0) return 'crit';
|
||||||
if (w && w.state === 'down') return 'crit';
|
if (st === 'down') return 'crit';
|
||||||
if ((data.alert_warning_unacked || 0) > 0 || (data.alert_warning_acked || 0) > 0) return 'warn';
|
if ((data.alert_warning_unacked || 0) > 0 || (data.alert_warning_acked || 0) > 0) return 'warn';
|
||||||
if (w && w.state === 'overdue') return 'warn';
|
if (st === 'overdue') return 'warn';
|
||||||
return 'ok';
|
return 'ok';
|
||||||
}
|
}
|
||||||
var SEV_ORDER = { crit: 0, warn: 1, ok: 2 };
|
var SEV_ORDER = { crit: 0, warn: 1, ok: 2 };
|
||||||
@@ -171,17 +172,17 @@
|
|||||||
|
|
||||||
// ---- host row rendering ---------------------------------------------
|
// ---- host row rendering ---------------------------------------------
|
||||||
function statusChip(data) {
|
function statusChip(data) {
|
||||||
var w = worstConnection(data);
|
var st = data.status;
|
||||||
if (!w) return '<span class="chip outline">—</span>';
|
if (!st || st === 'unknown') return '<span class="chip outline">—</span>';
|
||||||
var cls = w.state === 'up' ? 'ok' : (w.state === 'down' ? 'crit' : 'warn');
|
var cls = (st === 'up' || st === 'simplex') ? 'ok' : (st === 'down' ? 'crit' : 'warn');
|
||||||
return '<span class="chip ' + cls + '">' + escHtml(w.state) + '</span>';
|
return '<span class="chip ' + cls + '">' + escHtml(st) + '</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function tipCard(data) {
|
function tipCard(data) {
|
||||||
var rows = '';
|
var rows = '';
|
||||||
(data.connections || []).forEach(function (c) {
|
(data.connections || []).forEach(function (c) {
|
||||||
if (!c.state || c.state === 'unknown') return;
|
if (!c.state || c.state === 'unknown') return;
|
||||||
var cls = c.state === 'up' ? 'up' : (c.state === 'down' ? 'dn' : 'ov');
|
var cls = c.state === 'up' ? 'up' : (c.state === 'down' ? 'dn' : (c.state === 'absent' ? 'ab' : 'ov'));
|
||||||
var fam = (c.afam || '').replace('IPv', 'v');
|
var fam = (c.afam || '').replace('IPv', 'v');
|
||||||
var rtt = (c.state === 'up' && c.rtts && c.rtts[0]) ? Math.round(c.rtts[0]) + ' ms' : '—';
|
var rtt = (c.state === 'up' && c.rtts && c.rtts[0]) ? Math.round(c.rtts[0]) + ' ms' : '—';
|
||||||
rows += '<tr><td>' + escHtml(fam) + '</td><td>' + escHtml(c.addr || '—') + '</td>'
|
rows += '<tr><td>' + escHtml(fam) + '</td><td>' + escHtml(c.addr || '—') + '</td>'
|
||||||
@@ -247,7 +248,9 @@
|
|||||||
else if (data.hbc_version !== HBD_VERSION) {
|
else if (data.hbc_version !== HBD_VERSION) {
|
||||||
staleTag = '<span class="stale" title="agent v' + escHtml(String(data.hbc_version)) + ' ≠ server v' + HBD_VERSION + '">v' + escHtml(String(data.hbc_version)) + '</span>';
|
staleTag = '<span class="stale" title="agent v' + escHtml(String(data.hbc_version)) + ' ≠ server v' + HBD_VERSION + '">v' + escHtml(String(data.hbc_version)) + '</span>';
|
||||||
}
|
}
|
||||||
var dotCls = w ? (w.state === 'up' ? sev : (w.state === 'down' ? 'down' : 'overdue')) : 'off';
|
var st = data.status;
|
||||||
|
var dotCls = (!st || st === 'unknown') ? 'off'
|
||||||
|
: ((st === 'up' || st === 'simplex') ? sev : (st === 'down' ? 'down' : 'overdue'));
|
||||||
var flapTag = '';
|
var flapTag = '';
|
||||||
var flapping = data.flapping || [];
|
var flapping = data.flapping || [];
|
||||||
if (flapping.length) {
|
if (flapping.length) {
|
||||||
@@ -286,11 +289,11 @@
|
|||||||
var total = 0, up = 0, overdue = 0, down = 0;
|
var total = 0, up = 0, overdue = 0, down = 0;
|
||||||
Object.values(hostData).forEach(function (d) {
|
Object.values(hostData).forEach(function (d) {
|
||||||
total++;
|
total++;
|
||||||
var w = worstConnection(d);
|
var st = d.status;
|
||||||
if (!w) return;
|
if (!st || st === 'unknown') return;
|
||||||
if (w.state === 'up') up++;
|
if (st === 'up' || st === 'simplex') up++;
|
||||||
else if (w.state === 'overdue') overdue++;
|
else if (st === 'overdue') overdue++;
|
||||||
else if (w.state === 'down') down++;
|
else if (st === 'down') down++;
|
||||||
});
|
});
|
||||||
var parts = [total + ' hosts', up + ' up'];
|
var parts = [total + ' hosts', up + ' up'];
|
||||||
if (overdue) parts.push(overdue + ' overdue');
|
if (overdue) parts.push(overdue + ' overdue');
|
||||||
|
|||||||
@@ -456,7 +456,7 @@
|
|||||||
</tr></thead><tbody>`;
|
</tr></thead><tbody>`;
|
||||||
for (const c of data.connections) {
|
for (const c of data.connections) {
|
||||||
const st = escHtml(c.state || '—');
|
const st = escHtml(c.state || '—');
|
||||||
const stCls = c.state === 'up' ? 'status-up' : (c.state ? 'status-down' : '');
|
const stCls = c.state === 'up' ? 'status-up' : (c.state === 'absent' ? '' : (c.state ? 'status-down' : ''));
|
||||||
const rtt = (c.state === 'up' && c.rtt) ? Math.round(c.rtt) + ' ms' : '—';
|
const rtt = (c.state === 'up' && c.rtt) ? Math.round(c.rtt) + ' ms' : '—';
|
||||||
const chg = c.statetime ? new Date(c.statetime * 1000).toLocaleString() : '—';
|
const chg = c.statetime ? new Date(c.statetime * 1000).toLocaleString() : '—';
|
||||||
const seen = c.lastbeat ? new Date(c.lastbeat * 1000).toLocaleString() : '—';
|
const seen = c.lastbeat ? new Date(c.lastbeat * 1000).toLocaleString() : '—';
|
||||||
@@ -1143,6 +1143,24 @@
|
|||||||
function renderNetworkTables(d) {
|
function renderNetworkTables(d) {
|
||||||
let html = '';
|
let html = '';
|
||||||
|
|
||||||
|
if (d.connectivity) {
|
||||||
|
let t = '<table class="data-table"><thead><tr><th>Protocol</th><th>Internet</th>'
|
||||||
|
+ '<th>Address</th><th>Gateway</th><th class="num">RTT</th></tr></thead><tbody>';
|
||||||
|
for (const fam of ['ipv4', 'ipv6']) {
|
||||||
|
const c = d.connectivity[fam];
|
||||||
|
if (!c) continue;
|
||||||
|
const known = c.present === true || c.present === false;
|
||||||
|
const cls = c.present === true ? 'status-up' : '';
|
||||||
|
const txt = c.present === true ? '✓ present' : (c.present === false ? 'absent' : '?');
|
||||||
|
t += `<tr><td>${fam === 'ipv4' ? 'IPv4' : 'IPv6'}</td>
|
||||||
|
<td class="${cls}">${txt}</td>
|
||||||
|
<td>${escHtml(c.addr || '—')}</td><td>${escHtml(c.gateway || '—')}</td>
|
||||||
|
<td class="num">${known && c.rtt != null ? Math.round(c.rtt) + ' ms' : '—'}</td></tr>`;
|
||||||
|
}
|
||||||
|
t += '</tbody></table>';
|
||||||
|
html += `<div class="table-section-label">Connectivity</div>${t}`;
|
||||||
|
}
|
||||||
|
|
||||||
if (d.interfaces && Object.keys(d.interfaces).length) {
|
if (d.interfaces && Object.keys(d.interfaces).length) {
|
||||||
const sample = Object.values(d.interfaces)[0];
|
const sample = Object.values(d.interfaces)[0];
|
||||||
const hasDelta = 'bytes_sent_delta' in sample;
|
const hasDelta = 'bytes_sent_delta' in sample;
|
||||||
|
|||||||
Reference in New Issue
Block a user