Letzte erfolgreiche Ping-Prüfung im System-Monitor-Modal anzeigen (Issue #57)
Die per PING ueberwachten lokalen Server (check_fds.sh -> status.txt ->
LegacyStatusFileReader -> SystemRepository) landen bereits als Kacheln im
System-Monitor, dem mittleren der drei Monitore an der Buero-Wand - das ist
exakt der "alte Monitor" aus dem Issue. GET /api/v1/systems liefert
last_check_at dafuer schon mit, das Klick-Modal hat den Wert aber bisher
weder abgeholt noch angezeigt.
buildSystemModalContent() (office-scene.js) formatiert last_check_at jetzt
ueber die neue formatSystemCheckTime() - sie kommt sowohl mit ISO-8601
(API-gemeldete Systeme) als auch mit dem "YYYY-MM-DD HH:MM"-Format der
Legacy-status.txt klar. renderSystemModalBody() (office-render.js) zeigt den
Zeitpunkt nur bei Status "ok" an ("zuletzt erfolgreich geprüft: ..."), da nur
dann Erreichbarkeit UND Ping-Erfolg zusammenfallen - bei "Fehler" bliebe eine
Zeitangabe ohne Aenderung an check_fds.sh irrefuehrend.
Bewusst nicht Teil dieser Aenderung: Die im Issue zusaetzlich genannte
Portscan-Liste (Detailseite fuer weitere, nur manuell zu pruefende Server)
ist als "koennten" markiert und ohne konkrete Vorgabe zu unscharf fuer eine
automatisierte Umsetzung. Die sechs konkret genannten Hosts/IPs gehoeren in
die lokale, nicht versionierte hosts.conf (Analogon zu credentials.conf) und
damit auf den Produktivserver, nicht in dieses oeffentliche Repo.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
0228ee4ae6
commit
c16c4b1e46
3 changed files with 54 additions and 2 deletions
|
|
@ -1254,7 +1254,11 @@ function renderSystemModalBody(body, content) {
|
||||||
for (const item of content.items) {
|
for (const item of content.items) {
|
||||||
const li = document.createElement("li");
|
const li = document.createElement("li");
|
||||||
li.className = `office-modal-item status-${item.status}`;
|
li.className = `office-modal-item status-${item.status}`;
|
||||||
li.textContent = `${item.name} (${item.type}) – ${item.status === "ok" ? "OK" : "Fehler"}${item.detail ? `: ${item.detail}` : ""}`;
|
const isReachable = item.status === "ok";
|
||||||
|
const lastCheckText = isReachable && item.lastCheckAt
|
||||||
|
? ` · zuletzt erfolgreich geprüft: ${item.lastCheckAt}`
|
||||||
|
: "";
|
||||||
|
li.textContent = `${item.name} (${item.type}) – ${isReachable ? "OK" : "Fehler"}${item.detail ? `: ${item.detail}` : ""}${lastCheckText}`;
|
||||||
list.appendChild(li);
|
list.appendChild(li);
|
||||||
}
|
}
|
||||||
body.appendChild(list);
|
body.appendChild(list);
|
||||||
|
|
|
||||||
|
|
@ -329,11 +329,38 @@ export function buildSystemModalContent(systems = []) {
|
||||||
status: system.status,
|
status: system.status,
|
||||||
type: system.type || "host",
|
type: system.type || "host",
|
||||||
detail: system.detail || "",
|
detail: system.detail || "",
|
||||||
lastCheckAt: system.last_check_at,
|
lastCheckAt: formatSystemCheckTime(system.last_check_at),
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formatiert last_check_at eines Systems (GET /api/v1/systems, Issue #57: "wann der letzte
|
||||||
|
* erfolgreiche Ping war") fuers Modal. Zwei Quellformate kommen vor: ISO-8601 UTC (per API
|
||||||
|
* gemeldete Systeme) und "YYYY-MM-DD HH:MM" ohne Zeitzone (Legacy-Import aus status.txt,
|
||||||
|
* geschrieben von check_fds.sh in Serverzeit) - beide werden von `Date` geparst, fehlende/
|
||||||
|
* ungueltige Werte liefern `null` statt eines irrefuehrenden Zeitstempels.
|
||||||
|
*
|
||||||
|
* @param {string|null|undefined} value
|
||||||
|
* @returns {string|null}
|
||||||
|
*/
|
||||||
|
export function formatSystemCheckTime(value) {
|
||||||
|
if (!value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const date = new Date(value);
|
||||||
|
if (Number.isNaN(date.getTime())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return date.toLocaleString("de-DE", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "2-digit",
|
||||||
|
year: "2-digit",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erzeugt die Punkte-Liste (SVG <polyline points="...">) fuer eine einfache
|
* Erzeugt die Punkte-Liste (SVG <polyline points="...">) fuer eine einfache
|
||||||
* KPI-Sparkline - bewusst ohne Chart-Lib gezeichnet (F10). Die API liefert die Historie
|
* KPI-Sparkline - bewusst ohne Chart-Lib gezeichnet (F10). Die API liefert die Historie
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import {
|
||||||
EVENT_LINE_CHAR_WIDTH,
|
EVENT_LINE_CHAR_WIDTH,
|
||||||
buildEventModalContent,
|
buildEventModalContent,
|
||||||
buildSystemModalContent,
|
buildSystemModalContent,
|
||||||
|
formatSystemCheckTime,
|
||||||
buildKpiSparklinePoints,
|
buildKpiSparklinePoints,
|
||||||
buildKpiTiles,
|
buildKpiTiles,
|
||||||
buildKpiModalContent,
|
buildKpiModalContent,
|
||||||
|
|
@ -335,6 +336,26 @@ test("buildSystemModalContent uebernimmt Status/Detail je System", () => {
|
||||||
]);
|
]);
|
||||||
assert.equal(content.items[0].status, "ok");
|
assert.equal(content.items[0].status, "ok");
|
||||||
assert.equal(content.items[0].detail, "");
|
assert.equal(content.items[0].detail, "");
|
||||||
|
assert.equal(content.items[0].lastCheckAt, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("buildSystemModalContent formatiert einen gueltigen last_check_at (Issue #57)", () => {
|
||||||
|
const content = buildSystemModalContent([
|
||||||
|
{ id: "srv1", name: "Webserver", status: "ok", type: "host", detail: "1.2.3.4", last_check_at: "2026-08-20 18:40" },
|
||||||
|
]);
|
||||||
|
assert.match(content.items[0].lastCheckAt, /^\d{2}\.\d{2}\.\d{2}, \d{2}:\d{2}$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("formatSystemCheckTime akzeptiert ISO-8601 (API) und 'YYYY-MM-DD HH:MM' (Legacy-status.txt)", () => {
|
||||||
|
assert.match(formatSystemCheckTime("2026-07-27T10:00:00Z"), /^\d{2}\.\d{2}\.\d{2}, \d{2}:\d{2}$/);
|
||||||
|
assert.match(formatSystemCheckTime("2026-08-20 18:40"), /^\d{2}\.\d{2}\.\d{2}, \d{2}:\d{2}$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("formatSystemCheckTime liefert null fuer fehlende/ungueltige Werte", () => {
|
||||||
|
assert.equal(formatSystemCheckTime(null), null);
|
||||||
|
assert.equal(formatSystemCheckTime(undefined), null);
|
||||||
|
assert.equal(formatSystemCheckTime(""), null);
|
||||||
|
assert.equal(formatSystemCheckTime("nicht-valide"), null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("buildKpiSparklinePoints liefert leeren String ohne Historie und einen Punkt pro Messwert sonst", () => {
|
test("buildKpiSparklinePoints liefert leeren String ohne Historie und einen Punkt pro Messwert sonst", () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue