ITSM/static/aes-monitor.js

121 lines
4.2 KiB
JavaScript
Executable File

/* AES-Suite Live-Monitoring — pollt monitor.json und rendert Dienste +
Backends grafisch. Von /static ausgeliefert (CSP script-src 'self'). */
(function () {
"use strict";
var root = document.getElementById("aes-monitor");
if (!root) return;
var src = root.getAttribute("data-src") || "/erweiterungen/aes/monitor.json";
var INTERVAL = 5000;
function el(tag, cls, text) {
var e = document.createElement(tag);
if (cls) e.className = cls;
if (text != null) e.textContent = text;
return e;
}
function bar(label, pct) {
var wrap = el("div", "sz");
wrap.style.margin = "2px 0";
var v = Math.max(0, Math.min(100, Math.round(pct || 0)));
wrap.appendChild(document.createTextNode(label + " "));
var track = el("span");
track.style.display = "inline-block";
track.style.width = "120px";
track.style.height = "8px";
track.style.borderRadius = "4px";
track.style.background = "var(--border, #333)";
track.style.verticalAlign = "middle";
track.style.margin = "0 6px";
var fill = el("span");
fill.style.display = "block";
fill.style.height = "8px";
fill.style.borderRadius = "4px";
fill.style.width = v + "%";
fill.style.background = v > 85 ? "#d9534f" : (v > 60 ? "#e0a800" : "#3fb950");
track.appendChild(fill);
wrap.appendChild(track);
wrap.appendChild(document.createTextNode(v + "%"));
return wrap;
}
function render(data) {
root.textContent = "";
// Dienst-Ampeln
var svcRow = el("div");
svcRow.style.display = "flex";
svcRow.style.flexWrap = "wrap";
svcRow.style.gap = "10px";
(data.services || []).forEach(function (s) {
var card = el("div", "card");
card.style.flex = "1";
card.style.minWidth = "180px";
var head = el("div");
head.style.display = "flex";
head.style.justifyContent = "space-between";
head.style.alignItems = "center";
head.appendChild(el("b", null, s.name));
head.appendChild(el("span", "badge " + (s.ok ? "ok" : "err"), s.ok ? "up" : "down"));
card.appendChild(head);
card.appendChild(el("div", "sz", s.detail || ""));
svcRow.appendChild(card);
});
root.appendChild(svcRow);
// Backends
var h = el("h3", null, "Backends / Agenten");
h.style.margin = "16px 0 6px";
root.appendChild(h);
var bes = data.backends || [];
if (!bes.length) {
root.appendChild(el("p", "sz", "Keine Backends online."));
} else {
bes.forEach(function (b) {
var card = el("div", "card");
var head = el("div");
head.style.display = "flex";
head.style.justifyContent = "space-between";
head.appendChild(el("b", null, b.url));
head.appendChild(el("span", "badge " + (b.healthy ? "ok" : "err"), b.healthy ? "healthy" : "offline"));
card.appendChild(head);
card.appendChild(bar("CPU", b.cpu));
card.appendChild(bar("RAM", b.ram));
card.appendChild(bar("VRAM", b.vram));
var meta = el("div", "sz");
meta.textContent = "Latenz " + (b.latency || 0) + "ms · Agent " + (b.agent_online ? "online" : "offline") +
" · Modelle: " + ((b.models && b.models.length) ? b.models.join(", ") : "-");
card.appendChild(meta);
root.appendChild(card);
});
}
// Runner + Projekte + Zeitstempel
var foot = el("p", "sz");
foot.style.marginTop = "10px";
var r = data.runner || {};
foot.textContent = "Runner: " + (r.available ? "aktiv" : "offline") +
" · beobachtete Repos: " + ((r.watched && r.watched.length) || 0) +
" · Projekte: " + (data.projects_total || 0) +
" · Stand: " + new Date().toLocaleTimeString();
root.appendChild(foot);
}
function tick() {
fetch(src, { headers: { "Accept": "application/json" }, credentials: "same-origin" })
.then(function (r) { return r.json(); })
.then(render)
.catch(function () {
var p = document.getElementById("aes-monitor-err");
if (!p) {
p = el("p", "err", "Live-Daten momentan nicht abrufbar — naechster Versuch laeuft.");
p.id = "aes-monitor-err";
root.appendChild(p);
}
});
}
tick();
setInterval(tick, INTERVAL);
})();