redesign UI

This commit is contained in:
soruh 2023-06-11 19:20:36 +02:00
parent 9b39bac8d7
commit 2f41d7a2ea
5 changed files with 142 additions and 59 deletions

View File

@ -30,7 +30,7 @@ fn pack_debug_page() -> Result<(), Box<dyn std::error::Error>> {
.unwrap(); .unwrap();
let js = std::str::from_utf8(&out)?; 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 let (start, end) = html
.split_once("<!--INSERT SVG HERE-->") .split_once("<!--INSERT SVG HERE-->")

View File

@ -1 +1 @@
<svg><g transform="translate(-38.3 -51.4)"><path d="m98.8 55.1-6.52 6.52-3.78-3.78 6.52-6.52zm-7.49 20.5-8.5 8.5-16.8-16.8 8.5-8.5zm-16.9 0.0741a11.9 11.9 45 0 1 0.0256-16.8 11.9 11.9 45 0 1 16.8-0.0256 11.9 11.9 45 0 1-0.0256 16.8 11.9 11.9 45 0 1-16.8 0.0256zm-36.2 32.6 6.52-6.52 3.78 3.78-6.52 6.52zm19.7-25.3 8.39-8.39 1.88 1.88-8.39 8.39zm7.46 7.5 8.39-8.39 1.88 1.88-8.39 8.39zm-19.7-2.72 8.5-8.5 16.8 16.8-8.5 8.5zm16.9-0.0741a11.9 11.9 45 0 1-0.0256 16.8 11.9 11.9 45 0 1-16.8 0.0256 11.9 11.9 45 0 1 0.0256-16.8 11.9 11.9 45 0 1 16.8-0.0256z"/></g></svg> <svg version="1.1" viewBox="0 0 60.59 60.734" xmlns="http://www.w3.org/2000/svg"><g transform="translate(-38.21,-51.32)"><path d="m98.8 55.1-6.52 6.52-3.78-3.78 6.52-6.52zm-7.49 20.5-8.5 8.5-16.8-16.8 8.5-8.5zm-16.9 0.0741a11.9 11.9 45 0 1 0.0256-16.8 11.9 11.9 45 0 1 16.8-0.0256 11.9 11.9 45 0 1-0.0256 16.8 11.9 11.9 45 0 1-16.8 0.0256zm-36.2 32.6 6.52-6.52 3.78 3.78-6.52 6.52zm19.7-25.3 8.39-8.39 1.88 1.88-8.39 8.39zm7.46 7.5 8.39-8.39 1.88 1.88-8.39 8.39zm-19.7-2.72 8.5-8.5 16.8 16.8-8.5 8.5zm16.9-0.0741a11.9 11.9 45 0 1-0.0256 16.8 11.9 11.9 45 0 1-16.8 0.0256 11.9 11.9 45 0 1 0.0256-16.8 11.9 11.9 45 0 1 16.8-0.0256z"/></g></svg>

Before

Width:  |  Height:  |  Size: 564 B

After

Width:  |  Height:  |  Size: 643 B

View File

@ -10,25 +10,26 @@
</head> </head>
<body> <body>
<div id="header"> <div class="content">
<p id="free_ports" />
<p id="last_change" />
</div>
<div id="connected_box">
<div id="connected" class="hidden"><!--INSERT SVG HERE--></div>
<p id="last_ping" />
</div>
<table id="table"> <div id="header">
<tr> <p id="free_ports" />
<th onclick="sort(this,'number')">Nummer</th> <!--<p id="last_change" />-->
<th onclick="sort(this,'port')">Port</th> <div id="connected" class="hidden"><!--INSERT SVG HERE--></div>
<th onclick="sort(this,'status')">Zustand</th> <p id="last_ping" />
<th onclick="sort(this,'name')">Name</th> </div>
<th onclick="sort(this,'rejector')">Meldung</th>
<th onclick="sort(this,'last_change')">Letzte Änderung</th> <table id="table">
</tr> <tr>
</table> <th onclick="sort(this,'name')">Name</th>
<th onclick="sort(this,'number')">Nummer</th>
<th onclick="sort(this,'port')">Port</th>
<th onclick="sort(this,'status')">Zustand</th>
<th onclick="sort(this,'last_change')">Seit</th>
</tr>
</table>
</div>
</body> </body>
</html> </html>

View File

@ -2,40 +2,52 @@ body {
background-color: #eee; background-color: #eee;
} }
#connected_box { .last_change {
position: absolute; text-align: right;
top: 5%;
right: 5%;
width: 5%;
height: 5%;
} }
#free_ports, .last_change .unit {
#last_change { padding-left: 1ch;
min-width: 8ch;
display: inline-block; display: inline-block;
text-align: left;
} }
#last_ping,
#connected,
#free_ports { #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, td,
th { th {
border: 1px solid black; border: 1px solid black;
padding: 0.5em; padding: 0.5em;
}
th {
cursor: pointer;
}
td {
font-family: monospace; font-family: monospace;
} }
table { table {
border-spacing: 0; border-spacing: 0;
max-width: 100%;
margin: 0 auto;
}
th {
cursor: pointer;
user-select: none;
font-size: inherit;
} }
th::after { th::after {
@ -55,20 +67,24 @@ th:not(.sort)::after {
content: "\25bc"; content: "\25bc";
} }
.number { td {
text-align: right; text-align: left;
} }
.text { .port {
text-align: left; text-align: left;
} }
.visible { .visible {
opacity: 1; opacity: 0;
transition: opacity 500ms linear; /*transition: opacity 500ms linear;*/
} }
.hidden { .hidden {
opacity: 0.2; opacity: 1;
transition: opacity 6000ms linear; transition: opacity 5000ms ease-in;
}
#connected {
fill: rgb(224, 32, 6)
} }

View File

@ -13,13 +13,44 @@ window.onload = () => {
let evtSource; let evtSource;
let table = []; let table = [];
let last_update = new Date();
let direction = -1; let direction = -1;
let oldkey = "last_change"; let oldkey = "last_change";
table_elem.firstChild.firstChild.lastChild.className = "sort sort-down"; 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) => { sort = (element, key) => {
@ -59,6 +90,7 @@ window.onload = () => {
let fmt = Intl.DateTimeFormat('de-DE', { dateStyle: 'medium', timeStyle: 'medium' }); let fmt = Intl.DateTimeFormat('de-DE', { dateStyle: 'medium', timeStyle: 'medium' });
let format_date = date => fmt.format(date).replace(', ', ' '); let format_date = date => fmt.format(date).replace(', ', ' ');
let format_time = date => fmt.format(date).split(', ', 2)[1];
let print_table = () => { let print_table = () => {
while(table_elem.children.length > 1) { while(table_elem.children.length > 1) {
@ -68,21 +100,47 @@ window.onload = () => {
for (let row of table) { for (let row of table) {
let tr = document.createElement("tr"); let tr = document.createElement("tr");
let values = [ let values = [
row.name === null ? "?" : row.name,
row.number, row.number,
row.port, row.port,
row.status, row.status,
row.name || "?", time_ago(last_update - row.last_change)
row.rejector || "",
format_date(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"); let td = document.createElement("td");
td.innerText = value; td.className = name;
td.className = Number.isInteger(value) ? "number" : "text";
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); tr.appendChild(td);
} }
table_elem.appendChild(tr) 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); 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}`; 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 = []; table = [];
@ -116,7 +174,7 @@ window.onload = () => {
switch(status) { switch(status) {
case "disconnected": case "disconnected":
status = "getrennt"; status = rejector ? `getrennt: ${rejector}` : "getrennt";
break; break;
case "idle": case "idle":
status = "bereit"; status = "bereit";
@ -130,19 +188,20 @@ window.onload = () => {
} }
for (let [timestamp, port] of data.errored_ports) { 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); console.log(table);
do_sort(oldkey, direction); do_sort(oldkey, direction);
print_table(); 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 = () => { let connect_event_source = () => {
@ -154,7 +213,9 @@ window.onload = () => {
evtSource = new EventSource("/events"); evtSource = new EventSource("/events");
evtSource.addEventListener("change", event => { 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") fetch("/data")
.then(res => res.json()) .then(res => res.json())
@ -165,10 +226,15 @@ window.onload = () => {
clearTimeout(ping_timeout); clearTimeout(ping_timeout);
ping_timeout = setTimeout(connect_event_source, timeout_duration); 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"; connected.className = "visible";
setTimeout(() => connected.className = "hidden", 1000);
print_table();
clearTimeout(display_disconnected);
display_disconnected = setTimeout(() => connected.className = "hidden", 5000);
}); });