import { decode } from "/vendor/msgpack/index.mjs"; const target = document.querySelector("#target"); const day = document.querySelector("#day"); const detail = document.querySelector("#detail"); const observed = document.querySelector("#observed"); const percent = (value) => value === null ? "Unknown" : `${(value * 100).toFixed(2)}% healthy`; function state(value) { switch (value) { case null: return "unknown"; case 1: return "good"; case 0: return "down"; default: return "mixed"; } } async function load() { const response = await fetch( document.querySelector("script[data-api]").dataset.api, ); return response.ok ? decode(await response.arrayBuffer()) : null; } function renderRow(record, recordIndex, dates, select) { const row = document.createElement("article"); row.className = "health-row"; const title = document.createElement("h3"); title.textContent = record.name; const bars = document.createElement("div"); bars.className = "bars"; bars.setAttribute("role", "group"); bars.setAttribute("aria-label", `${record.name}, daily history`); for (const [dayIndex, value] of record.values.entries()) { const button = document.createElement("button"); button.type = "button"; button.className = `bar ${state(value)}`; button.title = `${dates[dayIndex]}: ${percent(value)}`; button.setAttribute("aria-label", `${record.name} · ${button.title}`); button.setAttribute("aria-pressed", "false"); button.dataset.target = String(recordIndex); button.dataset.day = String(dayIndex); button.addEventListener("click", () => { target.value = String(recordIndex); day.value = String(dayIndex); select(); }); bars.append(button); } row.append(title, bars); return row; } function renderGroup(group, groupIndex, records, dates, select) { const [header, labels, values] = group; const section = document.createElement("section"); section.className = "health-group"; const heading = document.createElement("h2"); heading.id = `group-${groupIndex}`; heading.textContent = `${String(groupIndex + 1).padStart(2, "0")} ${header}`; section.setAttribute("aria-labelledby", heading.id); section.append(heading); for (const [seriesIndex, metric] of labels.entries()) { const name = Object.entries(metric) .map(([key, value]) => `${key}=${value}`) .join(", ") || "{}"; const record = { name, values: values[seriesIndex] }; const recordIndex = records.length; records.push(record); target.add(new Option(`${header} · ${name}`, String(recordIndex))); section.append(renderRow(record, recordIndex, dates, select)); } return section; } function render([start, groups]) { const dates = Array.from({ length: 30 }, (_, index) => new Date((start + index * 86400) * 1000).toISOString().slice(0, 10), ); observed.textContent = `${dates[0]} – ${dates.at(-1)} · UTC`; const records = []; const select = () => { const record = records[Number(target.value)]; const dayIndex = Number(day.value); detail.textContent = `${record.name} · ${dates[dayIndex]}: ${percent(record.values[dayIndex])}.`; for (const bar of document.querySelectorAll(".bar")) { const selected = bar.dataset.target === target.value && bar.dataset.day === day.value; bar.setAttribute("aria-pressed", String(selected)); } }; for (const [index, date] of dates.entries()) { day.add(new Option(date, String(index))); } day.value = "29"; groups.sort((left, right) => left[1].length - right[1].length); const container = document.querySelector("#groups"); for (const [groupIndex, group] of groups.entries()) { container.append(renderGroup(group, groupIndex, records, dates, select)); } if (records.length) { document.querySelector(".controls").hidden = false; target.addEventListener("change", select); day.addEventListener("change", select); select(); } else { observed.textContent = "No data"; } } let snapshot; try { snapshot = await load(); } catch { snapshot = null; } if (snapshot === null) { observed.textContent = "No data"; } else { render(snapshot); } document.documentElement.dataset.ready = "true";