From cd774827dd14f68d8405c45d2d9da30b3fab050e Mon Sep 17 00:00:00 2001 From: Toby Vincent Date: Sat, 28 Sep 2024 00:54:46 -0500 Subject: feat: refactor into pub-sub and impl SSE --- assets/index.js | 92 +++++++++++++++++++++++---------------------------------- 1 file changed, 37 insertions(+), 55 deletions(-) (limited to 'assets') diff --git a/assets/index.js b/assets/index.js index 246364f..e65369c 100644 --- a/assets/index.js +++ b/assets/index.js @@ -1,16 +1,7 @@ -/** - * @typedef {Object} Check - * @property {String} status - 'pass'|'fail'|'warn' - * @property {String} output - Details. Not present if 'pass' - */ +const serviceMap = new Map(); -/** - * @typedef {Check} HealthCheck - * @property {Map} checks - */ - -async function getHealthCheck() { - const url = "api/healthcheck"; +async function getServices() { + const url = "api/services"; try { const response = await fetch(url); if (!response.ok) { @@ -24,64 +15,55 @@ async function getHealthCheck() { } } -function updateStatus(check) { +function updateStatus() { const statusElm = document.getElementById("status"); const issuesElm = document.getElementById("issues"); - switch (check.status) { + const issues = [...serviceMap.values()].filter((s) => !s).length; + issuesElm.textContent = `${issues} issue(s) detected`; + if (issues) { + statusElm.setAttribute("class", "error"); + } else { + statusElm.setAttribute("class", "ok"); + } +} + +function updateService(name, node, status) { + switch (status.status) { case "pass": - issuesElm.textContent = "No issues detected"; - statusElm.setAttribute("class", "ok"); + node.textContent = "Operational"; + node.setAttribute("class", "ok"); break; case "fail": - issuesElm.textContent = check.output; - statusElm.setAttribute("class", "error"); + node.textContent = "Down"; + node.title = status.output; + node.setAttribute("class", "error"); break; case "warn": - issuesElm.textContent = check.output; - statusElm.setAttribute("class", "warning"); + node.textContent = "Warning"; + node.title = status.output; + node.setAttribute("class", "warning"); break; - default: - issuesElm.textContent = "Unknown"; - statusElm.setAttribute("class", "warning"); + case "unknown": + node.textContent = "Unknown"; + node.setAttribute("class", "warning"); } -} -getHealthCheck().then((healthCheck) => { - const table = document.getElementById("services"); - const evtSource = new EventSource("sse"); - updateStatus(healthCheck); + serviceMap.set(name, status.status === "pass"); + updateStatus(); +} - for (const [service, check] of Object.entries(healthCheck.checks)) { +getServices().then((services) => { + for (const [service] of Object.entries(services)) { + const table = document.getElementById("services"); const row = table.insertRow(); - const nameNode = row.insertCell(); nameNode.textContent = service; + const node = row.insertCell(); - const stateNode = row.insertCell(); - switch (check.status) { - case "pass": - stateNode.textContent = "Operational"; - stateNode.setAttribute("class", "ok"); - break; - case "fail": - stateNode.textContent = "Down"; - stateNode.title = check.output; - stateNode.setAttribute("class", "error"); - break; - case "warn": - stateNode.textContent = "Warning"; - stateNode.title = check.output; - stateNode.setAttribute("class", "warning"); - break; - default: - stateNode.textContent = "Unknown"; - statusElm.setAttribute("class", "warning"); - } - - evtSource.addEventListener(service, (event) => { + const evtSource = new EventSource(`sse/${service}`); + evtSource.onmessage = (event) => { const status = JSON.parse(event.data); - stateNode.textContent = status.state; - stateNode.title = status.output; - }); + updateService(service, node, status); + }; } }); -- cgit v1.2.3-70-g09d2