// Public status page client JS: // 1. Click any monitor row to collapse/expand its detail panel. // 2. Hover any heartbeat bar to see the bucket time range and uptime breakdown. // All monitor detail HTML is server-rendered; this script only toggles a CSS // class on click. Reads its config from window.PINGQL_PAGE. (function () { var cfg = window.PINGQL_PAGE || {}; var barFrequency = cfg.bar_frequency || "daily"; // ── Click to expand/collapse ────────────────────────────────────────── var rows = document.querySelectorAll(".monitor .monitor-row"); for (var r = 0; r < rows.length; r++) { (function (row) { var card = row.parentElement; row.addEventListener("click", function () { var isOpen = card.classList.toggle("expanded-state"); row.setAttribute("aria-expanded", isOpen ? "true" : "false"); }); })(rows[r]); } // ── Bar tooltips ────────────────────────────────────────────────────── var tooltip = document.getElementById("bar-tooltip"); if (!tooltip) return; var bucketSpanMs = (barFrequency === "hourly") ? 3600 * 1000 : 86400 * 1000; function fmtBucketRange(startIso) { var start = new Date(startIso); var end = new Date(start.getTime() + bucketSpanMs); var dateOpts = { month: "short", day: "numeric" }; var timeOpts = { hour: "2-digit", minute: "2-digit" }; if (barFrequency === "hourly") { return start.toLocaleDateString(undefined, dateOpts) + ", " + start.toLocaleTimeString(undefined, timeOpts) + " - " + end.toLocaleTimeString(undefined, timeOpts); } return start.toLocaleDateString(undefined, { weekday: "short", month: "short", day: "numeric" }); } function uptimeBand(p) { if (p == null) return ""; if (p >= 99.9) return "good"; if (p >= 99.0) return "warn"; return "bad"; } function showTooltipForBar(bar) { var total = parseInt(bar.getAttribute("data-total") || "0", 10); var up = parseInt(bar.getAttribute("data-up") || "0", 10); var start = bar.getAttribute("data-start"); var latRaw = bar.getAttribute("data-latency"); var lat = latRaw == null ? null : parseInt(latRaw, 10); if (!start) return; // Full precision pct so the formatter can decide. Anything below 100% gets // 2 truncated (not rounded) decimals - same rule as the page-level uptime // numbers, so a bucket with one failed check never displays as "100%". var pct = total > 0 ? (100 * up / total) : null; var pctText; if (pct == null) pctText = "-"; else if (pct >= 100) pctText = "100%"; else pctText = (Math.floor(pct * 100) / 100).toFixed(2) + "%"; var html = '