From fd992d7e3c03f37fbcafe9d3f26c72a2ead3b2a7 Mon Sep 17 00:00:00 2001 From: Toby Vincent Date: Thu, 26 Sep 2024 17:31:16 -0500 Subject: feat!: impl full api --- assets/index.css | 61 ++++++++++++++++++++++++++++++++++++++ assets/index.html | 30 +++++++++++++++++++ assets/index.js | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 assets/index.css create mode 100644 assets/index.html create mode 100644 assets/index.js (limited to 'assets') diff --git a/assets/index.css b/assets/index.css new file mode 100644 index 0000000..9c170e4 --- /dev/null +++ b/assets/index.css @@ -0,0 +1,61 @@ +html { + background: var(--bg); + color: var(--fg); + font-size: 12pt; + font-family: monospace; + display: flex; + flex-direction: column; +} +body { + height: calc(100vh - 1rem); + width: calc(100vw - 4rem); + max-width: 640px; + margin: 0 2rem 1rem; + line-height: 1.4; + align-self: center; +} +main { + display: flex; + flex-direction: column; +} +hgroup { + text-align: center; +} +table { + width: 100%; + max-width: 500px; + align-self: center; + border-collapse: collapse; +} +tr { + border: 2px solid #ddd; +} +td { + padding: 5px; +} +td:first-of-type + td { + text-align: right; +} +.ok { + color: #228b22; +} +.warning { + color: #ff8c00; +} +.error { + color: #dc143c; +} + +#status { + color: #fff; + background: #228b22; +} +#status.ok { + background: #228b22; +} +#status.warning { + background: #ff8c00; +} +#status.error { + background: #dc143c; +} diff --git a/assets/index.html b/assets/index.html new file mode 100644 index 0000000..c168318 --- /dev/null +++ b/assets/index.html @@ -0,0 +1,30 @@ + + + + + + status.tobyvin.dev + + + + +
+
+
+

tobyvin.dev Status

+
+
+ + + + + + +
StatusNo issues detected
+ +
+ +
+
+ + diff --git a/assets/index.js b/assets/index.js new file mode 100644 index 0000000..173ed72 --- /dev/null +++ b/assets/index.js @@ -0,0 +1,87 @@ +/** + * @typedef {Object} Check + * @property {String} status - 'pass'|'fail'|'warn' + * @property {String} output - Details. Not present if 'pass' + */ + +/** + * @typedef {Check} HealthCheck + * @property {Map} checks + */ + +async function getHealthCheck() { + const url = "api/healthcheck"; + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Response status: ${response.status}`); + } + + const json = await response.json(); + return json; + } catch (error) { + console.error(error.message); + } +} + +function updateStatus(check) { + const statusElm = document.getElementById("status"); + const issuesElm = document.getElementById("issues"); + switch (check.status) { + case "pass": + issuesElm.textContent = "No issues detected"; + statusElm.setAttribute("class", "ok"); + break; + case "fail": + issuesElm.textContent = `${check.output} issues detected`; + statusElm.setAttribute("class", "error"); + break; + case "warn": + issuesElm.textContent = `${check.output} warnings detected`; + statusElm.setAttribute("class", "warning"); + break; + default: + issuesElm.textContent = "Unknown"; + statusElm.setAttribute("class", "warning"); + } +} + +getHealthCheck().then((healthCheck) => { + const table = document.getElementById("services"); + const evtSource = new EventSource("sse"); + updateStatus(healthCheck); + + for (const [service, check] of Object.entries(healthCheck.checks)) { + const row = table.insertRow(); + + const nameNode = row.insertCell(); + nameNode.textContent = service; + + 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 status = JSON.parse(event.data); + stateNode.textContent = status.state; + stateNode.title = status.output; + }); + } +}); -- cgit v1.2.3-70-g09d2