const timeElement = document.querySelector("#local-time"); const refreshElement = document.querySelector("#refresh-indicator"); const fields = { cpu: document.querySelector("#cpu-value"), memory: document.querySelector("#memory-value"), uptime: document.querySelector("#uptime-value"), containers: document.querySelector("#containers-value"), targets: document.querySelector("#targets-value"), telemetry: document.querySelector("#telemetry-value"), }; let lastSuccessfulUpdate = null; let requestInFlight = false; function updateClock() { const now = new Date(); timeElement.textContent = new Intl.DateTimeFormat("en-US", { timeZone: "America/Detroit", hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false, }).format(now); } function formatUptime(totalSeconds) { const seconds = Math.max(0, Number(totalSeconds) || 0); const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const minutes = Math.floor((seconds % 3600) / 60); if (days > 0) return days + "d " + hours + "h"; if (hours > 0) return hours + "h " + minutes + "m"; return minutes + "m"; } function setUnavailable() { for (const key of ["cpu", "memory", "uptime", "containers", "targets"]) { fields[key].textContent = "--"; } fields.telemetry.textContent = "UNAVAILABLE"; fields.telemetry.classList.add("metric-error"); refreshElement.textContent = "TELEMETRY UNAVAILABLE"; refreshElement.classList.add("telemetry-error"); } function renderStatus(data) { fields.cpu.textContent = Number(data.host.cpu_percent).toFixed(1); fields.memory.textContent = Number(data.host.memory_percent).toFixed(1); fields.uptime.textContent = formatUptime(data.host.uptime_seconds); fields.containers.textContent = String(data.containers.running); fields.targets.textContent = data.prometheus.up + "/" + data.prometheus.total; fields.telemetry.textContent = "LIVE"; fields.telemetry.classList.remove("metric-error"); refreshElement.classList.remove("telemetry-error"); lastSuccessfulUpdate = Date.now(); updateRefreshLabel(); } function updateRefreshLabel() { if (!lastSuccessfulUpdate) return; const ageSeconds = Math.max(0, Math.floor((Date.now() - lastSuccessfulUpdate) / 1000)); refreshElement.textContent = "LIVE TELEMETRY ยท UPDATED " + String(ageSeconds).padStart(2, "0") + "s AGO"; } async function refreshTelemetry() { if (requestInFlight) return; requestInFlight = true; try { const response = await fetch("/api/status", { cache: "no-store", headers: { "Accept": "application/json" }, }); if (!response.ok) throw new Error("status " + response.status); const data = await response.json(); if (!data.ok) throw new Error("telemetry unavailable"); renderStatus(data); } catch (error) { console.error("ByteGeist telemetry request failed:", error); setUnavailable(); } finally { requestInFlight = false; } } updateClock(); refreshTelemetry(); window.setInterval(updateClock, 1000); window.setInterval(updateRefreshLabel, 1000); window.setInterval(refreshTelemetry, 15000);