feat: update network-health renderer for new scrutiny/adguard UI
This commit is contained in:
@@ -1,85 +1,84 @@
|
|||||||
function statusTone(status) {
|
|
||||||
if (status === "failed" || status === "offline") return "offline";
|
|
||||||
if (status === "unknown") return "warning";
|
|
||||||
return "online";
|
|
||||||
}
|
|
||||||
|
|
||||||
function deviceStatusIcon(status) {
|
|
||||||
if (status === "passed") return "online";
|
|
||||||
if (status === "failed") return "offline";
|
|
||||||
return "warning";
|
|
||||||
}
|
|
||||||
|
|
||||||
function fmtNumber(n) {
|
|
||||||
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
|
||||||
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;
|
|
||||||
return String(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function renderNetworkHealth(state) {
|
export function renderNetworkHealth(state) {
|
||||||
renderAdGuard(state.data.adguard);
|
_renderAdGuard(state.adguard || {});
|
||||||
renderScrutiny(state.data.scrutiny);
|
_renderScrutiny(state.scrutiny || {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderAdGuard(adguard) {
|
function _renderAdGuard(d) {
|
||||||
|
const online = d.source_status === "online";
|
||||||
|
|
||||||
const pill = document.getElementById("adguard-pill");
|
const pill = document.getElementById("adguard-pill");
|
||||||
const totalEl = document.getElementById("adguard-total");
|
if (pill) {
|
||||||
const blockedEl = document.getElementById("adguard-blocked");
|
pill.textContent = online ? "ONLINE" : "OFFLINE";
|
||||||
const blockedPctEl = document.getElementById("adguard-blocked-pct");
|
pill.className = "status-pill " + (online ? "pill-online" : "pill-offline");
|
||||||
const latencyEl = document.getElementById("adguard-latency");
|
}
|
||||||
const barFill = document.getElementById("adguard-bar-fill");
|
|
||||||
|
|
||||||
if (!pill) return;
|
const set = (id, val) => { const el = document.getElementById(id); if (el) el.textContent = val; };
|
||||||
|
|
||||||
const online = adguard.source_status === "online";
|
if (online) {
|
||||||
pill.className = `status-pill ${online ? "online" : "offline"}`;
|
set("adguard-total", fmtK(d.total_queries));
|
||||||
pill.textContent = online ? "Online" : "Offline";
|
set("adguard-blocked", fmtK(d.blocked_queries));
|
||||||
|
set("adguard-blocked-pct", `${d.blocked_percent ?? 0}%`);
|
||||||
|
set("adguard-latency", `${d.avg_processing_ms ?? 0}ms`);
|
||||||
|
|
||||||
totalEl.textContent = fmtNumber(adguard.total_queries);
|
const bar = document.getElementById("adguard-bar-fill");
|
||||||
blockedEl.textContent = fmtNumber(adguard.blocked_queries);
|
if (bar) bar.style.width = `${Math.min(d.blocked_percent ?? 0, 100)}%`;
|
||||||
blockedPctEl.textContent = `${adguard.blocked_percent ?? 0}%`;
|
} else {
|
||||||
|
["adguard-total", "adguard-blocked", "adguard-blocked-pct", "adguard-latency"].forEach(id => set(id, "—"));
|
||||||
const pct = adguard.blocked_percent ?? 0;
|
const bar = document.getElementById("adguard-bar-fill");
|
||||||
blockedPctEl.className = pct > 30 ? "metric-accent warning" : "metric-accent online";
|
if (bar) bar.style.width = "0%";
|
||||||
|
}
|
||||||
latencyEl.textContent = online ? `${adguard.avg_processing_ms ?? 0} MS` : "N/A";
|
|
||||||
latencyEl.className = online ? "online" : "offline";
|
|
||||||
|
|
||||||
const barPct = Math.min(pct, 100);
|
|
||||||
barFill.style.width = `${barPct}%`;
|
|
||||||
const bar = barFill.closest(".metric-bar");
|
|
||||||
if (bar) bar.className = pct > 40 ? "metric-bar warning" : "metric-bar";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderScrutiny(scrutiny) {
|
function _renderScrutiny(d) {
|
||||||
|
const online = d.source_status === "online";
|
||||||
|
|
||||||
const pill = document.getElementById("scrutiny-pill");
|
const pill = document.getElementById("scrutiny-pill");
|
||||||
const listEl = document.getElementById("scrutiny-list");
|
if (pill) {
|
||||||
|
pill.textContent = online ? "ONLINE" : "OFFLINE";
|
||||||
|
pill.className = "status-pill " + (online ? "pill-online" : "pill-offline");
|
||||||
|
}
|
||||||
|
|
||||||
if (!pill || !listEl) return;
|
// stat blocks
|
||||||
|
const set = (id, val) => { const el = document.getElementById(id); if (el) el.textContent = val; };
|
||||||
|
if (online) {
|
||||||
|
set("scrutiny-total", d.total_count ?? 0);
|
||||||
|
set("scrutiny-failed", d.failed_count ?? 0);
|
||||||
|
const passedEl = document.getElementById("scrutiny-passed");
|
||||||
|
if (passedEl) {
|
||||||
|
passedEl.textContent = (d.total_count ?? 0) - (d.failed_count ?? 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
set("scrutiny-total", "—");
|
||||||
|
set("scrutiny-failed", "—");
|
||||||
|
set("scrutiny-passed", "—");
|
||||||
|
}
|
||||||
|
|
||||||
const online = scrutiny.source_status === "online";
|
// disk list
|
||||||
const hasFailed = scrutiny.failed_count > 0;
|
const list = document.getElementById("scrutiny-list");
|
||||||
pill.className = `status-pill ${hasFailed ? "offline" : online ? "online" : "offline"}`;
|
if (!list) return;
|
||||||
pill.textContent = hasFailed ? "Failed" : online ? "All Passed" : "Offline";
|
|
||||||
|
|
||||||
if (!online || scrutiny.devices.length === 0) {
|
if (!online || !d.devices || d.devices.length === 0) {
|
||||||
listEl.innerHTML = `<div class="storage-row"><strong style="color:var(--text-dim)">No data</strong><span>—</span><span></span><span></span></div>`;
|
list.innerHTML = `<div class="scrutiny-offline">— ${online ? "no devices" : "offline"}</div>`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
listEl.innerHTML = scrutiny.devices.map((device) => {
|
list.innerHTML = d.devices.map(dev => {
|
||||||
const tone = deviceStatusIcon(device.status);
|
const ok = dev.status === "passed";
|
||||||
const shortName = device.name.replace(/^sd/, "sd").toUpperCase();
|
const icon = ok ? "✓" : dev.status === "failed" ? "✗" : "?";
|
||||||
const shortModel = device.model.length > 22 ? device.model.slice(0, 22) + "…" : device.model;
|
const cls = ok ? "disk-ok" : dev.status === "failed" ? "disk-fail" : "disk-unk";
|
||||||
|
const temp = dev.temperature != null ? `<span class="disk-temp">${dev.temperature}°C</span>` : "";
|
||||||
return `
|
return `
|
||||||
<div class="storage-row">
|
<div class="scrutiny-row">
|
||||||
<strong>${shortName}</strong>
|
<span class="disk-icon ${cls}">${icon}</span>
|
||||||
<span>${shortModel}</span>
|
<span class="disk-name">${dev.name}</span>
|
||||||
<div class="metric-bar ${tone === "offline" ? "danger" : ""}">
|
<span class="disk-model">${dev.model}</span>
|
||||||
<span style="width:${tone === "online" ? "100" : "0"}%"></span>
|
${temp}
|
||||||
</div>
|
</div>`;
|
||||||
<span class="status-pill ${tone}">${device.status.toUpperCase()}</span>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}).join("");
|
}).join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fmtK(n) {
|
||||||
|
if (n >= 1_000_000) return (n / 1_000_000).toFixed(1) + "M";
|
||||||
|
if (n >= 1_000) return (n / 1_000).toFixed(0) + "K";
|
||||||
|
return String(n ?? 0);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user