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) {
|
||||
const li = document.createElement("li");
|
||||
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);
|
||||
}
|
||||
body.appendChild(list);
|
||||
|
|
|
|||
|
|
@ -329,11 +329,38 @@ export function buildSystemModalContent(systems = []) {
|
|||
status: system.status,
|
||||
type: system.type || "host",
|
||||
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
|
||||
* KPI-Sparkline - bewusst ohne Chart-Lib gezeichnet (F10). Die API liefert die Historie
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import {
|
|||
EVENT_LINE_CHAR_WIDTH,
|
||||
buildEventModalContent,
|
||||
buildSystemModalContent,
|
||||
formatSystemCheckTime,
|
||||
buildKpiSparklinePoints,
|
||||
buildKpiTiles,
|
||||
buildKpiModalContent,
|
||||
|
|
@ -335,6 +336,26 @@ test("buildSystemModalContent uebernimmt Status/Detail je System", () => {
|
|||
]);
|
||||
assert.equal(content.items[0].status, "ok");
|
||||
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", () => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue