2024-12-01 03:35:04 +01:00
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
<link crossorigin rel="stylesheet" href="https://cdn.alemi.dev/web/alemi.css">
|
|
|
|
|
<title>uppe.rs</title>
|
|
|
|
|
<style>
|
|
|
|
|
span.cell {
|
2024-12-03 01:24:23 +01:00
|
|
|
|
position: relative;
|
2024-12-01 03:35:04 +01:00
|
|
|
|
display: inline-block;
|
2024-12-03 01:24:23 +01:00
|
|
|
|
width: .5rem;
|
|
|
|
|
height: 1.2rem;
|
2024-12-01 03:35:04 +01:00
|
|
|
|
border: 1px solid var(--secondary);
|
2024-12-03 01:24:23 +01:00
|
|
|
|
font-size: 8pt;
|
|
|
|
|
line-height: 1.2rem;
|
2024-12-01 03:35:04 +01:00
|
|
|
|
background-color: rgba(var(--secondary-rgb), 0.4);
|
2024-12-03 01:24:23 +01:00
|
|
|
|
margin-top: .3rem;
|
|
|
|
|
margin-bottom: .3rem;
|
2024-12-01 03:35:04 +01:00
|
|
|
|
padding-top: 0;
|
|
|
|
|
padding-bottom: 0;
|
|
|
|
|
transition: .1s;
|
|
|
|
|
text-align: center;
|
|
|
|
|
cursor: default;
|
2024-12-03 01:24:23 +01:00
|
|
|
|
border-radius: .3rem;
|
|
|
|
|
color: #ffffff00;
|
2024-12-01 03:35:04 +01:00
|
|
|
|
}
|
|
|
|
|
span.cell:hover {
|
2024-12-03 01:24:23 +01:00
|
|
|
|
padding-top: .3rem;
|
|
|
|
|
padding-bottom: .3rem;
|
|
|
|
|
width: 2rem;
|
|
|
|
|
font-size: 8pt;
|
2024-12-01 03:35:04 +01:00
|
|
|
|
margin-top: 0;
|
|
|
|
|
margin-bottom: 0;
|
2024-12-03 01:24:23 +01:00
|
|
|
|
margin-right: -0.75rem;
|
|
|
|
|
margin-left: -0.75rem;
|
|
|
|
|
color: var(--background);
|
|
|
|
|
background-color: rgba(var(--secondary-rgb), 1);
|
|
|
|
|
z-index: 1;
|
|
|
|
|
font-weight: bold;
|
2024-12-01 03:35:04 +01:00
|
|
|
|
}
|
2024-12-01 04:36:31 +01:00
|
|
|
|
span.cell.warning {
|
|
|
|
|
border-color: var(--accent);
|
|
|
|
|
}
|
|
|
|
|
span.cell.error {
|
|
|
|
|
border-color: var(--accent);
|
2024-12-01 03:35:04 +01:00
|
|
|
|
background-color: rgba(var(--accent-rgb), 0.4);
|
|
|
|
|
}
|
2024-12-03 01:24:23 +01:00
|
|
|
|
span.cell.error:hover {
|
|
|
|
|
background-color: rgba(var(--accent-rgb), 1);
|
|
|
|
|
}
|
2024-12-03 03:30:55 +01:00
|
|
|
|
span.sep {
|
|
|
|
|
color: var(--background-secondary);
|
|
|
|
|
margin-right: 1em;
|
|
|
|
|
margin-left: 1em;
|
|
|
|
|
}
|
2024-12-01 03:35:04 +01:00
|
|
|
|
hr.color {
|
|
|
|
|
color: var(--accent);
|
|
|
|
|
border-color: var(--accent);
|
|
|
|
|
}
|
2024-12-03 01:24:23 +01:00
|
|
|
|
div.card {
|
|
|
|
|
display: inline-block;
|
2024-12-01 04:23:59 +01:00
|
|
|
|
white-space: nowrap;
|
2024-12-03 01:24:23 +01:00
|
|
|
|
overflow-x: scroll;
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
margin-top: 2em;
|
|
|
|
|
border-radius: 1em;
|
|
|
|
|
border: 1px solid var(--background-secondary);
|
|
|
|
|
padding: 1em;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
transition: .3s;
|
|
|
|
|
}
|
|
|
|
|
div.card:hover {
|
|
|
|
|
background-color: var(--background-dim);
|
2024-12-01 04:23:59 +01:00
|
|
|
|
}
|
2024-12-03 03:30:55 +01:00
|
|
|
|
body {
|
|
|
|
|
margin: 0;
|
|
|
|
|
}
|
|
|
|
|
footer {
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
div.content {
|
|
|
|
|
min-height: calc(100vh - 3.5rem);
|
|
|
|
|
}
|
2024-12-01 03:35:04 +01:00
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
2024-12-03 03:30:55 +01:00
|
|
|
|
<div class="content">
|
|
|
|
|
<div class="ml-1">
|
|
|
|
|
<h1 class="mt-0 pt-1">uppe.rs</h1>
|
|
|
|
|
<p>%%DESCRIPTION%%</p>
|
|
|
|
|
</div>
|
|
|
|
|
<hr class="color"/>
|
2024-12-01 03:35:04 +01:00
|
|
|
|
|
2024-12-03 03:30:55 +01:00
|
|
|
|
<main id="uppe-rs-content">
|
|
|
|
|
|
|
|
|
|
</main>
|
|
|
|
|
</div>
|
2024-12-01 03:35:04 +01:00
|
|
|
|
|
2024-12-03 03:30:55 +01:00
|
|
|
|
<footer>
|
|
|
|
|
<hr />
|
|
|
|
|
<p class="mt-s mb-s">
|
|
|
|
|
<span class="cell error">...</span> down <span class="sep">|</span>
|
|
|
|
|
<span class="cell warning">...</span> slow <span class="sep">|</span>
|
|
|
|
|
<span class="cell">...</span> up
|
|
|
|
|
</p>
|
|
|
|
|
</footer>
|
2024-12-01 03:35:04 +01:00
|
|
|
|
</body>
|
|
|
|
|
<script>
|
|
|
|
|
function cell(timestamp, rtt) {
|
|
|
|
|
let d = new Date(timestamp * 1000);
|
2024-12-01 04:36:31 +01:00
|
|
|
|
let warning = "";
|
2024-12-03 01:58:49 +01:00
|
|
|
|
if (rtt !== null && rtt >= %%THRESHOLD%%) {
|
2024-12-01 04:36:31 +01:00
|
|
|
|
warning = " warning";
|
|
|
|
|
}
|
2024-12-01 03:35:04 +01:00
|
|
|
|
if (rtt === null) {
|
2024-12-03 01:24:23 +01:00
|
|
|
|
return `<span class="cell error" title="${d}">╳</span>`;
|
2024-12-01 03:35:04 +01:00
|
|
|
|
} else {
|
2024-12-01 04:36:31 +01:00
|
|
|
|
return `<span class="cell${warning}" title="${rtt}ms -- ${d}">${rtt}</span>`;
|
2024-12-01 03:35:04 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-02 23:44:27 +01:00
|
|
|
|
function card(key, history, last_rtt) {
|
2024-12-01 03:35:04 +01:00
|
|
|
|
let bar = "";
|
2024-12-03 03:06:16 +01:00
|
|
|
|
let now = Math.floor(Date.now() / 1000);
|
|
|
|
|
let first = history[0][0];
|
|
|
|
|
let hrs_ago = (now - first) / 3600;
|
2024-12-01 03:35:04 +01:00
|
|
|
|
for (let el of history) {
|
|
|
|
|
bar += cell(el[0], el[1]);
|
|
|
|
|
}
|
|
|
|
|
return `<div class="card">
|
2024-12-03 01:24:23 +01:00
|
|
|
|
<h3 class="mt-0">${key} <code class="color">${last_rtt ? last_rtt + 'ms' : 'DOWN'}</code></h3>
|
2024-12-01 03:35:04 +01:00
|
|
|
|
<div class="box">
|
2024-12-03 01:24:23 +01:00
|
|
|
|
${bar}
|
2024-12-03 03:06:16 +01:00
|
|
|
|
<p class="ma-0"><small>^ ~${hrs_ago.toFixed(1)}h ago</small></p>
|
2024-12-01 03:35:04 +01:00
|
|
|
|
</div>
|
2024-12-03 01:24:23 +01:00
|
|
|
|
</div>`;
|
2024-12-01 03:35:04 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let main = document.getElementById("uppe-rs-content");
|
|
|
|
|
|
|
|
|
|
async function updateStatus() {
|
|
|
|
|
let res = await fetch("/api/status")
|
|
|
|
|
let status = await res.json()
|
2024-12-03 01:24:23 +01:00
|
|
|
|
if (status.error) {
|
|
|
|
|
console.error("server error:", status);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-01 03:35:04 +01:00
|
|
|
|
let keys = Object.keys(status);
|
|
|
|
|
keys.sort();
|
|
|
|
|
|
|
|
|
|
let out = "";
|
|
|
|
|
|
|
|
|
|
for (let key of keys) {
|
2024-12-02 23:48:31 +01:00
|
|
|
|
let res = await fetch(`/api/status/${key}?limit=120`);
|
2024-12-01 03:35:04 +01:00
|
|
|
|
let history = await res.json();
|
2024-12-02 23:44:27 +01:00
|
|
|
|
out += card(key, history, status[key]);
|
2024-12-03 01:24:23 +01:00
|
|
|
|
out += "\n";
|
2024-12-01 03:35:04 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
main.innerHTML = out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setInterval(updateStatus, 60 * 1000)
|
|
|
|
|
updateStatus()
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
</html>
|
|
|
|
|
|