Metric history (5s to 1h tiers, persisted), uplink status, ping targets, DHCP leases, and a tar.gz backup of the state directory. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AeFqV9dZrK6nipHkPfyM4F
46 lines
1.5 KiB
JavaScript
46 lines
1.5 KiB
JavaScript
// Live updates for the overview: refetches the dashboard part of the page
|
|
// (rendered by the server, like the page itself) and switches time ranges
|
|
// without a reload. Without JavaScript the page and its links still work.
|
|
(function () {
|
|
"use strict";
|
|
const root = document.getElementById("dashboard");
|
|
if (!root) return;
|
|
let range = root.dataset.range;
|
|
let interval = Number(root.dataset.interval) || 5;
|
|
let timer = null;
|
|
|
|
async function refresh() {
|
|
try {
|
|
const r = await fetch("/dashboard?range=" + encodeURIComponent(range), { credentials: "same-origin" });
|
|
if (r.redirected || r.status === 401 || r.status === 403) {
|
|
location.href = "/login"; // the session ended
|
|
return;
|
|
}
|
|
if (r.ok) root.innerHTML = await r.text();
|
|
} catch (e) {
|
|
// The router may be restarting the UI (an apply); try again later.
|
|
}
|
|
schedule();
|
|
}
|
|
|
|
function schedule() {
|
|
clearTimeout(timer);
|
|
if (!document.hidden) timer = setTimeout(refresh, interval * 1000);
|
|
}
|
|
|
|
root.addEventListener("click", function (ev) {
|
|
const a = ev.target.closest("a[data-range]");
|
|
if (!a) return;
|
|
ev.preventDefault();
|
|
range = a.dataset.range;
|
|
interval = range === "1h" ? 5 : 60;
|
|
history.replaceState(null, "", "/?range=" + encodeURIComponent(range));
|
|
refresh();
|
|
});
|
|
document.addEventListener("visibilitychange", function () {
|
|
if (document.hidden) clearTimeout(timer);
|
|
else refresh();
|
|
});
|
|
schedule();
|
|
})();
|