Refine dashboard card icons and storage layout

This commit is contained in:
2026-04-06 18:24:24 +02:00
parent 72713448f6
commit e8af468f1e
3 changed files with 683 additions and 116 deletions
@@ -1,84 +1,69 @@
export function renderNetworkHealth(state) {
_renderAdGuard(state.adguard || {});
_renderScrutiny(state.scrutiny || {});
renderAdGuard(state.adguard || {});
renderScrutiny(state.scrutiny || {});
}
function _renderAdGuard(d) {
const online = d.source_status === "online";
function renderAdGuard(data) {
const online = data.source_status === "online";
setPill("adguard-pill", online ? "ONLINE" : "OFFLINE", online ? "pill-online" : "pill-offline");
const pill = document.getElementById("adguard-pill");
if (pill) {
pill.textContent = online ? "ONLINE" : "OFFLINE";
pill.className = "status-pill " + (online ? "pill-online" : "pill-offline");
}
setText("adguard-total", online ? fmtCompact(data.total_queries) : "\u2014");
setText("adguard-blocked", online ? fmtCompact(data.blocked_queries) : "\u2014");
setText("adguard-blocked-pct", online ? `${Math.round(data.blocked_percent ?? 0)}%` : "\u2014");
setText("adguard-latency", online ? `${Math.round(data.avg_processing_ms ?? 0)}ms` : "\u2014");
const set = (id, val) => { const el = document.getElementById(id); if (el) el.textContent = val; };
if (online) {
set("adguard-total", fmtK(d.total_queries));
set("adguard-blocked", fmtK(d.blocked_queries));
set("adguard-blocked-pct", `${d.blocked_percent ?? 0}%`);
set("adguard-latency", `${d.avg_processing_ms ?? 0}ms`);
const bar = document.getElementById("adguard-bar-fill");
if (bar) bar.style.width = `${Math.min(d.blocked_percent ?? 0, 100)}%`;
} else {
["adguard-total", "adguard-blocked", "adguard-blocked-pct", "adguard-latency"].forEach(id => set(id, "—"));
const bar = document.getElementById("adguard-bar-fill");
if (bar) bar.style.width = "0%";
const fill = document.getElementById("adguard-bar-fill");
if (fill) {
fill.style.width = `${online ? Math.min(data.blocked_percent ?? 0, 100) : 0}%`;
}
}
function _renderScrutiny(d) {
const online = d.source_status === "online";
function renderScrutiny(data) {
const online = data.source_status === "online";
setPill("scrutiny-pill", online ? "ONLINE" : "OFFLINE", online ? "pill-online" : "pill-offline");
const pill = document.getElementById("scrutiny-pill");
if (pill) {
pill.textContent = online ? "ONLINE" : "OFFLINE";
pill.className = "status-pill " + (online ? "pill-online" : "pill-offline");
}
const total = data.total_count ?? 0;
const failed = data.failed_count ?? 0;
const passed = Math.max(total - failed, 0);
// 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", "—");
}
setText("scrutiny-total", online ? total : "\u2014");
setText("scrutiny-passed", online ? passed : "\u2014");
setText("scrutiny-failed", online ? failed : "\u2014");
// disk list
const list = document.getElementById("scrutiny-list");
if (!list) return;
if (!online || !d.devices || d.devices.length === 0) {
list.innerHTML = `<div class="scrutiny-offline">— ${online ? "no devices" : "offline"}</div>`;
const devices = Array.isArray(data.devices) ? data.devices.slice(0, 3) : [];
if (!online || devices.length === 0) {
list.innerHTML = `<div class="scrutiny-offline">\u2014 ${online ? "no disks" : "offline"}</div>`;
return;
}
list.innerHTML = d.devices.map(dev => {
const ok = dev.status === "passed";
const icon = ok ? "" : dev.status === "failed" ? "" : "?";
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 `
<div class="scrutiny-row">
<span class="disk-icon ${cls}">${icon}</span>
<span class="disk-name">${dev.name}</span>
<span class="disk-model">${dev.model}</span>
${temp}
</div>`;
}).join("");
list.innerHTML = `<div class="scrutiny-strip">${devices.map((device) => {
const status = device.status || "unknown";
const cls = status === "passed" ? "ok" : status === "failed" ? "fail" : "unk";
const token = status === "passed" ? "OK" : status === "failed" ? "ER" : "--";
const name = device.name || device.device || "disk";
return `<span class="scrutiny-chip ${cls}"><strong>${token}</strong>${name}</span>`;
}).join("")}</div>`;
}
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);
function setText(id, value) {
const el = document.getElementById(id);
if (el) el.textContent = value;
}
function setPill(id, label, cls) {
const el = document.getElementById(id);
if (!el) return;
el.textContent = label;
el.className = `status-pill ${cls}`;
}
function fmtCompact(value) {
const num = Number(value ?? 0);
if (num >= 1_000_000) return `${(num / 1_000_000).toFixed(1)}M`;
if (num >= 1_000) return `${Math.round(num / 1_000)}K`;
return `${num}`;
}