From a779f5046be04dbed97d8e1c462987bd8b4bae6d Mon Sep 17 00:00:00 2001 From: Micha Date: Mon, 6 Apr 2026 07:36:48 +0000 Subject: [PATCH] feat: update services renderer with pill and colour counts --- .../dashboard/assets/js/renderers/services.js | 100 +++--------------- 1 file changed, 17 insertions(+), 83 deletions(-) diff --git a/apps/dashboard/assets/js/renderers/services.js b/apps/dashboard/assets/js/renderers/services.js index a989ede..b316191 100644 --- a/apps/dashboard/assets/js/renderers/services.js +++ b/apps/dashboard/assets/js/renderers/services.js @@ -1,90 +1,24 @@ -function serviceTone(status) { - if (status === "offline") return "offline"; - if (status === "degraded") return "warning"; - return "online"; -} - -function healthLabel(status) { - if (status === "offline") return "Offline"; - if (status === "degraded") return "Degraded"; - return "Healthy"; -} - -function sourceLabel(source) { - if (source === "home_assistant") return "Core Automation Hub"; - if (source === "uptime_kuma") return "External availability and latency surface."; - if (source === "docker") return "Container runtime state without external monitor data."; - return "Service state from aggregator."; -} - -function formatTimestamp(value) { - if (!value) return "n/a"; - const date = new Date(value); - return new Intl.DateTimeFormat("de-DE", { - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - hour12: false, - }).format(date); -} - export function renderServices(state) { - const { services, overview } = state.data; + const services = state.services || {}; + const summary = services.summary || {}; - const dockerPill = document.getElementById("docker-summary-pill"); - dockerPill.className = `status-pill ${services.summary.docker.source_status === "online" ? "online" : "offline"}`; - dockerPill.textContent = services.summary.docker.source_status === "online" ? "Online" : "Offline"; - document.getElementById("docker-running").textContent = String(services.summary.docker.running); - document.getElementById("docker-stopped").textContent = String(services.summary.docker.stopped); - document.getElementById("docker-unhealthy").textContent = String(services.summary.docker.unhealthy); + const set = (id, val) => { const el = document.getElementById(id); if (el) el.textContent = val; }; - const kumaPill = document.getElementById("kuma-summary-pill"); - kumaPill.className = `status-pill ${services.summary.uptime_kuma.source_status === "online" ? "online" : "offline"}`; - kumaPill.textContent = services.summary.uptime_kuma.source_status === "online" ? "Synced" : "Offline"; - document.getElementById("kuma-up").textContent = String(services.summary.uptime_kuma.monitors_up); - document.getElementById("kuma-down").textContent = String(services.summary.uptime_kuma.monitors_down); - document.getElementById("kuma-paused").textContent = String(services.summary.uptime_kuma.monitors_paused); + set("svc-online", summary.online ?? "—"); + set("svc-degraded", summary.degraded ?? "—"); + set("svc-offline", summary.offline ?? "—"); + set("svc-total", summary.total ?? "—"); - const ha = services.services.find((service) => service.id === "homeassistant"); - if (ha) { - const haPill = document.getElementById("service-ha-pill"); - const tone = serviceTone(ha.status); - haPill.className = `status-pill ${tone}`; - haPill.textContent = ha.status === "online" ? "Reachable" : ha.status === "degraded" ? "Degraded" : "Offline"; - document.getElementById("service-ha-version").textContent = overview.home_assistant.version ?? "unknown"; - document.getElementById("service-ha-version").className = "info"; - document.getElementById("service-ha-latency").textContent = ha.latency_ms != null ? `${ha.latency_ms} MS` : "N/A"; - document.getElementById("service-ha-latency").className = tone === "offline" ? "offline" : tone === "warning" ? "warning" : "online"; - document.getElementById("service-ha-last-check").textContent = formatTimestamp(ha.last_checked); + const pill = document.getElementById("services-pill"); + if (pill) { + const s = summary.overall_status || "offline"; + pill.textContent = s.toUpperCase(); + pill.className = "status-pill " + (s === "online" ? "pill-online" : s === "degraded" ? "pill-degraded" : "pill-offline"); } - const dynamicServices = services.services.filter((service) => service.id !== "homeassistant").slice(0, 3); - const existingFallbacks = [ - document.getElementById("service-card-fallback-1"), - document.getElementById("service-card-fallback-2"), - document.getElementById("service-card-fallback-3"), - ]; - - dynamicServices.forEach((service, index) => { - const node = existingFallbacks[index]; - if (!node) return; - node.style.display = ""; - const tone = serviceTone(service.status); - const pillClass = tone === "warning" ? "warning" : tone === "offline" ? "offline" : "online"; - node.querySelector(".card-label").textContent = service.name; - node.querySelector(".status-pill").className = `status-pill ${pillClass}`; - node.querySelector(".status-pill").textContent = healthLabel(service.status); - node.querySelector(".card-title").textContent = service.name === "Immich" ? "Photo Pipeline" : service.name === "Gitea" ? "Git Platform" : `${service.name} Service`; - node.querySelector(".card-copy").textContent = sourceLabel(service.source); - - const rows = node.querySelectorAll(".service-meta-row strong"); - rows[0].textContent = service.latency_ms != null ? `${service.latency_ms} MS` : "N/A"; - rows[0].className = tone === "offline" ? "offline" : tone === "warning" ? "warning" : "online"; - rows[1].textContent = String(service.docker_state).toUpperCase(); - rows[1].className = service.docker_state === "stopped" ? "offline" : service.docker_state === "unhealthy" ? "warning" : "online"; - }); - - for (let index = dynamicServices.length; index < existingFallbacks.length; index += 1) { - existingFallbacks[index].style.display = "none"; - } + // Colour counts + const degEl = document.getElementById("svc-degraded"); + if (degEl) degEl.className = "stat-num" + ((summary.degraded ?? 0) > 0 ? " warn" : ""); + const offEl = document.getElementById("svc-offline"); + if (offEl) offEl.className = "stat-num" + ((summary.offline ?? 0) > 0 ? " danger" : ""); }