From d3768b1d9712436da6df4e1eef54737890035f62 Mon Sep 17 00:00:00 2001 From: Toby Vincent Date: Sun, 13 Oct 2024 20:44:03 -0500 Subject: feat: improve ui and add test service --- assets/index.css | 108 +++++++++++++++++++++++++++++++++++++++++++----------- assets/index.html | 1 + assets/index.js | 58 +++++++++++++++++------------ config.toml | 6 ++- favicon.svg | 2 + src/service.rs | 17 +++++++++ 6 files changed, 146 insertions(+), 46 deletions(-) create mode 100644 favicon.svg diff --git a/assets/index.css b/assets/index.css index dff7a03..9d6fca2 100644 --- a/assets/index.css +++ b/assets/index.css @@ -1,3 +1,68 @@ +:root { + color-scheme: light dark; + --bg: #1d2021; + --bg-hard: #282828; + --bg1: #3c3836; + --bg2: #504945; + --bg3: #665c54; + --bg4: #7c6f64; + --fg: #f9f5d7; + --fg-hard: #fdf4c1; + --fg1: #ebdbb2; + --fg2: #d5c4a1; + --fg3: #bdae93; + --fg4: #a89984; + --red: #cc2412; + --green: #98971a; + --yellow: #d79921; + --blue: #458588; + --purple: #b16286; + --cyan: #689d6a; + --gray: #a89984; + --orange: #d65d0e; + --bright-red: #fb4934; + --bright-green: #b8bb26; + --bright-yellow: #fabd2f; + --bright-blue: #83a598; + --bright-purple: #d3869b; + --bright-cyan: #8ec07c; + --bright-gray: #928374; + --bright-orange: #fe8019; +} + +@media (prefers-color-scheme: light) { + :root { + --bg: #f9f5d7; + --bg-hard: #fdf4c1; + --bg1: #ebdbb2; + --bg2: #d5c4a1; + --bg3: #bdae93; + --bg4: #a89984; + --fg: #1d2021; + --fg-hard: #282828; + --fg1: #3c3836; + --fg2: #504945; + --fg3: #665c54; + --fg4: #7c6f64; + --red: #9d0006; + --green: #79740e; + --yellow: #b57614; + --blue: #076678; + --purple: #8f3f71; + --cyan: #427b58; + --orange: #af3a03; + --gray: #928374; + --bright-red: #cc2412; + --bright-green: #98971a; + --bright-yellow: #d79921; + --bright-blue: #458598; + --bright-purple: #b16286; + --bright-cyan: #689d6a; + --bright-orange: #d65d0e; + --bright-gray: #7c6f64; + } +} + html { background: var(--bg); color: var(--fg); @@ -11,7 +76,6 @@ body { width: calc(100vw - 4rem); max-width: 640px; margin: 0 2rem 1rem; - line-height: 1.4; align-self: center; } main { @@ -21,14 +85,19 @@ main { hgroup { text-align: center; } +hr { + border-width: 0; +} table { width: 100%; max-width: 500px; align-self: center; border-collapse: collapse; + background: var(--bg1); + color: var(--fg1); } -tr { - border: 2px solid #ddd; +tbody { + border: 2px solid var(--bg4); } td { padding: 5px; @@ -37,32 +106,29 @@ td { td:first-of-type + td { text-align: right; } -td > details > summary { - text-align: right; -} -td > details { - text-align: left; +tr:first-of-type + tr { + border-top: 1px solid var(--bg3); } + .ok { - color: #228b22; + color: var(--bright-green); } .warning { - color: #ff8c00; + color: var(--bright-yellow); } .error { - color: #dc143c; + color: var(--bright-red); } -#status { - color: #fff; - background: #228b22; -} -#status.ok { - background: #228b22; +.details { + visibility: collapse; + font-size: 8pt; + color: var(--fg-hard); + background: var(--bg-hard); } -#status.warning { - background: #ff8c00; +:hover + .details { + visibility: visible; } -#status.error { - background: #dc143c; +:hover { + visibility: visible; } diff --git a/assets/index.html b/assets/index.html index c03a7b7..dfa316a 100644 --- a/assets/index.html +++ b/assets/index.html @@ -3,6 +3,7 @@ + diff --git a/assets/index.js b/assets/index.js index 12bce67..a4e5c2b 100644 --- a/assets/index.js +++ b/assets/index.js @@ -1,4 +1,5 @@ const serviceMap = new Map(); +const elementMap = new Map(); async function getServices() { const url = "api/v1/list"; @@ -28,35 +29,44 @@ function updateStatus() { } } -function updateService(statusElm, name, data) { +function createStatusTbody(name, data) { + const tbody = document.createElement("tbody"); + + const trowService = document.createElement("tr"); + const tdataName = document.createElement("td"); + tdataName.textContent = name; + trowService.appendChild(tdataName); + + const tdataStatus = document.createElement("td"); switch (data.status) { case "ok": { - statusElm.innerHTML = ""; - statusElm.textContent = "Ok"; - statusElm.setAttribute("class", "ok"); + tdataStatus.textContent = "Ok"; + tdataStatus.setAttribute("class", "ok"); serviceMap.set(name, true); break; } case "error": { - const summaryElm = document.createElement("summary"); - summaryElm.textContent = "Error"; - - const expandElm = document.createElement("code"); - expandElm.textContent = data.output; - - const detailsElm = document.createElement("details"); - detailsElm.appendChild(summaryElm); - detailsElm.appendChild(expandElm); - - statusElm.innerHTML = ""; - statusElm.appendChild(detailsElm); - statusElm.setAttribute("class", "error"); + tdataStatus.textContent = "Error"; + tdataStatus.setAttribute("class", "error"); serviceMap.set(name, false); break; } } - updateStatus(); + trowService.appendChild(tdataStatus); + tbody.appendChild(trowService); + + if (data.output) { + const trowOutput = document.createElement("tr"); + trowOutput.setAttribute("class", "details"); + const tdataOutput = document.createElement("td"); + tdataOutput.textContent = data.output; + tdataOutput.setAttribute("colspan", "2"); + trowOutput.appendChild(tdataOutput); + tbody.appendChild(trowOutput); + } + + return tbody; } getServices().then((services) => { @@ -67,15 +77,15 @@ getServices().then((services) => { for (const service of services) { const table = document.getElementById("services"); - const row = table.insertRow(); - const nameElm = row.insertCell(); - nameElm.textContent = service; - const statusElm = row.insertCell(); + let tbody = createStatusTbody(service, { "data": "ok" }); + table.appendChild(tbody); evtSource.addEventListener(service, (event) => { data = JSON.parse(event.data); - updateService(statusElm, service, data); - console.log(`service: ${service}, event: ${event}`); + tbodyNew = createStatusTbody(service, data); + tbody.replaceWith(tbodyNew); + tbody = tbodyNew; + updateStatus(); }); } }); diff --git a/config.toml b/config.toml index e91e94f..8084a90 100644 --- a/config.toml +++ b/config.toml @@ -7,11 +7,15 @@ kind = "http" url = "https://tobyvin.dev" [[services]] -name = "test_cmd" +name = "stat" kind = "exec" command = "stat" args = ["/tmp/test_file"] +[[services]] +name = "test" +kind = "test" + [[services]] name = "dns" kind = "tcp" diff --git a/favicon.svg b/favicon.svg new file mode 100644 index 0000000..2a8e2b3 --- /dev/null +++ b/favicon.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/service.rs b/src/service.rs index b67ba51..74ecb1d 100644 --- a/src/service.rs +++ b/src/service.rs @@ -13,6 +13,21 @@ pub trait IntoService { ) -> impl std::future::Future; } +impl IntoService for () { + async fn into_service(self, tx: tokio::sync::watch::Sender) { + let mut interval = tokio::time::interval(std::time::Duration::from_secs(3)); + let mut status = Status::Ok; + + loop { + interval.tick().await; + status = match tx.send_replace(status) { + Status::Ok => Status::Error(Some("Test status is in the error state".into())), + Status::Error(_) => Status::Ok, + }; + } + } +} + pub fn default_interval() -> std::time::Duration { std::time::Duration::from_secs(5) } @@ -31,11 +46,13 @@ pub enum ServiceKind { Http(http::Http), Tcp(tcp::Tcp), Exec(command::Command), + Test(()), } impl IntoService for ServiceKind { async fn into_service(self, tx: tokio::sync::watch::Sender) { match self { + ServiceKind::Test(()) => ().into_service(tx).await, ServiceKind::Http(h) => h.into_service(tx).await, ServiceKind::Tcp(t) => t.into_service(tx).await, ServiceKind::Exec(c) => c.into_service(tx).await, -- cgit v1.2.3-70-g09d2