diff --git a/build.rs b/build.rs index 697780e..3ef2682 100644 --- a/build.rs +++ b/build.rs @@ -30,7 +30,7 @@ fn pack_debug_page() -> Result<(), Box> { .unwrap(); let js = std::str::from_utf8(&out)?; - let css = Minifier::default().minify(&css, Level::Three).unwrap(); + let css = Minifier::default().minify(&css, Level::One).unwrap(); let (start, end) = html .split_once("") diff --git a/web/connected.svg b/web/connected.svg index aed3003..086b500 100644 --- a/web/connected.svg +++ b/web/connected.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/web/index.html b/web/index.html index eacecb0..4320473 100644 --- a/web/index.html +++ b/web/index.html @@ -10,25 +10,26 @@ - -
- -

-

+
- - - - - - - - - -
NummerPortZustandNameMeldungLetzte Änderung
+ + + + + + + + + + + +
NameNummerPortZustandSeit
+
\ No newline at end of file diff --git a/web/main.css b/web/main.css index c5d3f00..711a5a6 100644 --- a/web/main.css +++ b/web/main.css @@ -2,40 +2,52 @@ body { background-color: #eee; } -#connected_box { - position: absolute; - top: 5%; - right: 5%; - width: 5%; - height: 5%; +.last_change { + text-align: right; } -#free_ports, -#last_change { +.last_change .unit { + padding-left: 1ch; + min-width: 8ch; display: inline-block; + text-align: left; } +#last_ping, +#connected, #free_ports { - margin-right: 10%; + margin-top: 0; + margin-bottom: 0.25em; } +#connected svg { + height: 1em; +} + +#header { + display: flex; + flex-direction: row; + grid-template-columns: auto 1fr; + justify-content: space-between; +} td, th { border: 1px solid black; padding: 0.5em; -} - -th { - cursor: pointer; -} - -td { font-family: monospace; } table { border-spacing: 0; + max-width: 100%; + margin: 0 auto; +} + +th { + cursor: pointer; + user-select: none; + font-size: inherit; } th::after { @@ -55,20 +67,24 @@ th:not(.sort)::after { content: "\25bc"; } -.number { - text-align: right; +td { + text-align: left; } -.text { +.port { text-align: left; } .visible { - opacity: 1; - transition: opacity 500ms linear; + opacity: 0; + /*transition: opacity 500ms linear;*/ } .hidden { - opacity: 0.2; - transition: opacity 6000ms linear; + opacity: 1; + transition: opacity 5000ms ease-in; +} + +#connected { + fill: rgb(224, 32, 6) } \ No newline at end of file diff --git a/web/main.js b/web/main.js index df60eda..6a85cc1 100644 --- a/web/main.js +++ b/web/main.js @@ -13,13 +13,44 @@ window.onload = () => { let evtSource; let table = []; + let last_update = new Date(); + let direction = -1; let oldkey = "last_change"; table_elem.firstChild.firstChild.lastChild.className = "sort sort-down"; - console.log(oldkey, direction); + let time_ago = ms => { + + let value = ms / 1000; + // let prev = 0; + let unit = 0; + + let factors = [ + [1, 'Sekunde', 'n'], + [60, 'Minute', 'n'], + [60, 'Stunde', 'n'], + [24, 'Tag', 'e'], + [7, 'Woche', 'n'], + [4.348214, 'Monat', 'e'], + [12, 'Jahr', 'e'], + ]; + + for (let i in factors) { + let factor = factors[i][0]; + let new_value = Math.floor(value / factor); + if (new_value == 0) break; + + // prev = Math.floor(value % factor); + value = new_value; + unit = i; + } + + let factor = factors[unit]; + + return [value, factors[unit][1] + (value == 1 ? "" : factor[2])]; + } sort = (element, key) => { @@ -59,6 +90,7 @@ window.onload = () => { let fmt = Intl.DateTimeFormat('de-DE', { dateStyle: 'medium', timeStyle: 'medium' }); let format_date = date => fmt.format(date).replace(', ', ' '); + let format_time = date => fmt.format(date).split(', ', 2)[1]; let print_table = () => { while(table_elem.children.length > 1) { @@ -68,21 +100,47 @@ window.onload = () => { for (let row of table) { let tr = document.createElement("tr"); - + let values = [ + row.name === null ? "?" : row.name, row.number, row.port, row.status, - row.name || "?", - row.rejector || "", - format_date(row.last_change) + time_ago(last_update - row.last_change) ]; - for(let value of values) { + let names = [ + "name", + "number", + "port", + "status", + "last_change" + ]; + + for(let i in values) { + let value = values[i]; + let name = names[i]; + let td = document.createElement("td"); - td.innerText = value; - td.className = Number.isInteger(value) ? "number" : "text"; + td.className = name; + + if (name == "last_change") { + let [number, unit] = value; + + let span = document.createElement("span"); + // span.className = "value"; + span.innerText = number; + td.appendChild(span); + + span = document.createElement("span"); + span.className = "unit"; + span.innerText = unit; + td.appendChild(span); + } else { + td.innerText = value; + } tr.appendChild(td); + } table_elem.appendChild(tr) @@ -95,7 +153,7 @@ window.onload = () => { const allowed_ports = data.allowed_ports.map(x => x.end - x.start + 1).reduce((a,b) => a + b, 0); free_ports.innerText = `Freie Ports: ${allowed_ports - Object.keys(data.allocated_ports).length - data.errored_ports.length}`; - last_change.innerHTML = `Letzte Änderung: ${format_date(new Date(+data.last_update * 1000))}`; + // last_change.innerHTML = `Letzte Änderung: ${format_date(new Date(+data.last_update * 1000))}`; table = []; @@ -116,7 +174,7 @@ window.onload = () => { switch(status) { case "disconnected": - status = "getrennt"; + status = rejector ? `getrennt: ${rejector}` : "getrennt"; break; case "idle": status = "bereit"; @@ -130,19 +188,20 @@ window.onload = () => { } for (let [timestamp, port] of data.errored_ports) { - table.push({port, number: null, status: "Fehler", last_change: new Date(timestamp * 1000), rejector: null, name: null}) + table.push({port, number: null, status: "Fehler", last_change: new Date(timestamp * 1000), rejector: null, name: ""}) } console.log(table); - do_sort(oldkey, direction); print_table(); }; - let format_event = event => format_date(new Date(+event.data * 1000)); + let format_event = (event, method) => (method || format_date)(new Date(+event.data * 1000)); + + let display_disconnected; let connect_event_source = () => { @@ -154,7 +213,9 @@ window.onload = () => { evtSource = new EventSource("/events"); evtSource.addEventListener("change", event => { - last_ping.innerText = `Letzter Serverkontakt: ${format_event(event)}`; + last_ping.innerText = `Stand: ${format_event(event, format_time)}`; + + last_update = new Date(+event.data * 1000); fetch("/data") .then(res => res.json()) @@ -165,10 +226,15 @@ window.onload = () => { clearTimeout(ping_timeout); ping_timeout = setTimeout(connect_event_source, timeout_duration); + last_update = new Date(+event.data * 1000); - last_ping.innerText = `Letzter Serverkontakt: ${format_event(event)}`; + last_ping.innerText = `Stand: ${format_event(event, format_time)}`; connected.className = "visible"; - setTimeout(() => connected.className = "hidden", 1000); + + print_table(); + + clearTimeout(display_disconnected); + display_disconnected = setTimeout(() => connected.className = "hidden", 5000); });