full server dashboard working

This commit is contained in:
2026-03-22 18:44:07 -07:00
parent 324eaff135
commit 97fdb3d5d8
19 changed files with 1441 additions and 169 deletions

134
files/server/sidebar.js Normal file
View File

@ -0,0 +1,134 @@
// Helper - return the value of the ?host= querystring
function getSelectedHost() {
const params = new URLSearchParams(window.location.search);
return params.get('host') || '';
}
// Build the endpoints list when we receive data
socket.on('client_hostnames', rawMsg => {
// rawMsg is the JSON string that redis-cli prints
let hosts;
try {
hosts = JSON.parse(rawMsg);
} catch (e) {
console.warn('Could not parse client_hostnames message', rawMsg);
return;
}
// Sanitycheck
if (!Array.isArray(hosts)) { return; }
const ol = document.getElementById('endpointList');
const selected = getSelectedHost().toLowerCase();
// Clear old list
ol.innerHTML = '';
hosts.forEach(host => {
const li = document.createElement('li');
const a = document.createElement('a');
a.href = '?host=' + encodeURIComponent(host);
a.textContent = host;
if (host.toLowerCase() === selected) {
a.classList.add('active');
}
li.appendChild(a);
ol.appendChild(li);
});
});
/* -----------------------------------------------
2. (Optional) Rebuild the list if the URL changes
----------------------------------------------- */
window.addEventListener('popstate', () => {
// When the user navigates via back/forward the page
// still holds the old list, so we rebuild it.
const currentSelected = getSelectedHost().toLowerCase();
const anchors = document.querySelectorAll('#endpointList a');
anchors.forEach(a => {
a.classList.toggle('active', a.textContent.toLowerCase() === currentSelected);
});
});
(function () {
/* ----------------------------------------------------------
Use the socket that system_metrics.js already created.
If for some reason it isnt defined, create a new one.
---------------------------------------------------------- */
const sock = typeof socket !== 'undefined' ? socket : io();
/* ----------------------------------------------------------
Return the hostname that is currently selected in the URL
(the value of the “?host=…” query string).
---------------------------------------------------------- */
function getSelectedHost() {
const params = new URLSearchParams(window.location.search);
return params.get('host') || '';
}
/* ----------------------------------------------------------
Populate <ul id="endpointList"> with <li><a> items.
---------------------------------------------------------- */
function buildList(hosts) {
const ol = document.getElementById('endpointList');
const selected = getSelectedHost().toLowerCase();
ol.innerHTML = ''; // clear old items
hosts.forEach(host => {
const li = document.createElement('li');
const a = document.createElement('a');
a.href = '?host=' + encodeURIComponent(host);
a.textContent = host;
if (host.toLowerCase() === selected) a.classList.add('active');
li.appendChild(a);
ol.appendChild(li);
});
}
/* ----------------------------------------------------------
Listen for the “client_hostnames” event from the server.
The payload can be:
a JSON string → parse it
a plain array → use it directly
an object with a .data array (fallback)
---------------------------------------------------------- */
sock.on('client_hostnames', payload => {
let hosts;
if (typeof payload === 'string') {
try {
hosts = JSON.parse(payload);
} catch (e) {
console.warn('client_hostnames message is not JSON:', payload);
return;
}
} else if (Array.isArray(payload)) {
hosts = payload;
} else if (payload && Array.isArray(payload.data)) {
hosts = payload.data;
} else {
console.warn('client_hostnames payload format unrecognised:', payload);
return;
}
if (!Array.isArray(hosts)) {
console.warn('client_hostnames payload did not resolve to an array:', hosts);
return;
}
buildList(hosts);
});
/* ----------------------------------------------------------
When the user navigates via the back/forward buttons,
reapply the “active” class to the correct link.
---------------------------------------------------------- */
window.addEventListener('popstate', () => {
const selected = getSelectedHost().toLowerCase();
document.querySelectorAll('#endpointList a').forEach(a => {
a.classList.toggle('active', a.textContent.toLowerCase() === selected);
});
});
})();