From 266432c7df96c1601e3a95c448e2cdddcc72ab29 Mon Sep 17 00:00:00 2001 From: fds2610-bot Date: Thu, 1 Oct 2026 11:29:56 +0200 Subject: [PATCH] KPIs: keine Graphen mehr in Kachel und Detail-Modal Co-Authored-By: Claude Sonnet 5.5 --- Visualization.md | 2 +- html/css/office.css | 22 +--------------- html/js/office-render.js | 28 --------------------- html/js/office-scene.js | 39 ++--------------------------- tests/frontend/office-scene.test.js | 13 ---------- 5 files changed, 4 insertions(+), 100 deletions(-) diff --git a/Visualization.md b/Visualization.md index 7599e7d..86d85aa 100644 --- a/Visualization.md +++ b/Visualization.md @@ -244,7 +244,7 @@ externe Datenbankserver (nur PHP/Python-Standardbibliothek) auskommen, um die 5. **Phase 4 – Monitor-Wand live**: Event-, System- und KPI-Monitor zeigen echte Daten, Klick-Modals. ✅ erledigt: Events/Systeme/KPIs kommen live von der API, ein neuer SSE-Endpoint (`GET /api/v1/stream`, F13) stoesst Frontend-Updates an (Polling-Fallback in - `office-realtime.js`), KPI-Monitor zeichnet eine eigene SVG-Sparkline (F10, kein Chart-Lib) + `office-realtime.js`), KPI-Monitor zeichnet nur Zahlenwerte (keine Graphen) sobald KPIs gemeldet wurden. "Agenten" (registrierte Agenten) und "Online" (davon praesent, isAgentPresent()) sind als erste zwei KPI-Kacheln immer sichtbar, direkt aus der Agentenliste abgeleitet statt gemeldet (Issue #39). Ganz rechts kommt als vierte, ebenfalls diff --git a/html/css/office.css b/html/css/office.css index 5a03cfb..fa3b3c7 100644 --- a/html/css/office.css +++ b/html/css/office.css @@ -672,7 +672,7 @@ header.office-header h1 { text-anchor: middle; } -/* KPI-Sparklines (Phase 4, F10: kein Chart-Lib, eigenes SVG-Zeichnen) */ +/* KPI-Kacheln */ .kpi-tile-label { fill: var(--color-text-inverse); @@ -690,18 +690,6 @@ header.office-header h1 { fill: #facc15; } -.kpi-sparkline-bg { - fill: rgba(255, 255, 255, 0.04); -} - -.kpi-sparkline-line { - fill: none; - stroke: #7dd3fc; - stroke-width: 2; - stroke-linejoin: round; - stroke-linecap: round; -} - /* Modal (Phase 3/4: Board-/Monitor-Detailansicht, Visualization.md 4.5) */ .office-modal { @@ -815,14 +803,6 @@ header.office-header h1 { font-style: italic; } -.kpi-modal-sparkline { - width: 100%; - height: 80px; - margin-top: 8px; - background: #10131a; - border-radius: 6px; -} - /* Projekte-Modal (Issue #27: Klick auf den PO -> Projekte des Codeberg-Sync verwalten) */ .office-modal-error { diff --git a/html/js/office-render.js b/html/js/office-render.js index 014cc70..eb013e2 100644 --- a/html/js/office-render.js +++ b/html/js/office-render.js @@ -520,15 +520,6 @@ function renderSystemMonitor(frame, systems, onConfigClick) { return g; } -function renderSparkline(points, width, height, x, y) { - const g = el("g", { class: "kpi-sparkline", transform: `translate(${x}, ${y})` }); - g.appendChild(el("rect", { x: 0, y: 0, width, height, class: "kpi-sparkline-bg" })); - if (points) { - g.appendChild(el("polyline", { points, class: "kpi-sparkline-line" })); - } - return g; -} - function renderKpiMonitor(frame, kpis) { const tiles = buildKpiTiles(kpis); const g = el("g", { class: "monitor monitor-kpi" }); @@ -549,15 +540,7 @@ function renderKpiMonitor(frame, kpis) { return g; } - // Die Zeilen stehen direkt untereinander, statt die Monitorhoehe gleichmaessig unter den - // Kacheln aufzuteilen: Zaehler-Kacheln wie "Agenten"/"Online" (Issue #39) und "Hooks" - // (Issue #38) haben history: [] und damit keine Sparkline - verteilt man die Hoehe trotzdem, - // klaffen zwischen den Werten grosse leere Sparkline-Kaesten. Ein Verlauf bekommt seinen - // Platz deshalb nur, wenn es ihn wirklich gibt. const LABEL_HEIGHT = 20; - // Passt zur Punkteberechnung in buildKpiSparklinePoints() (Default-Hoehe 32) - so fuellt die - // Linie den Kasten genau aus. - const SPARKLINE_HEIGHT = 32; const ROW_GAP = 4; let rowTop = frame.y + 20; @@ -573,11 +556,6 @@ function renderKpiMonitor(frame, kpis) { ); rowTop += LABEL_HEIGHT; - if (tile.sparklinePoints) { - g.appendChild(renderSparkline(tile.sparklinePoints, frame.w - 32, SPARKLINE_HEIGHT, frame.x + 16, rowTop)); - rowTop += SPARKLINE_HEIGHT; - } - rowTop += ROW_GAP; }); @@ -1561,12 +1539,6 @@ function renderKpiModalBody(body, content) { label.textContent = `${item.label}: ${item.currentValue ?? "–"} ${item.unit}`; li.appendChild(label); - const svg = document.createElementNS(SVG_NS, "svg"); - svg.setAttribute("viewBox", "0 0 320 80"); - svg.setAttribute("class", "kpi-modal-sparkline"); - svg.appendChild(el("polyline", { points: item.sparklinePoints, class: "kpi-sparkline-line" })); - li.appendChild(svg); - list.appendChild(li); } body.appendChild(list); diff --git a/html/js/office-scene.js b/html/js/office-scene.js index 1b054dd..5274f96 100644 --- a/html/js/office-scene.js +++ b/html/js/office-scene.js @@ -458,43 +458,10 @@ export function formatSystemCheckTime(value) { }); } -/** - * Erzeugt die Punkte-Liste (SVG ) fuer eine einfache - * KPI-Sparkline - bewusst ohne Chart-Lib gezeichnet (F10). Die API liefert die Historie - * absteigend (neuester Wert zuerst, siehe KpiRepository::history()), fuer die Sparkline - * wird chronologisch (aeltester zuerst) von links nach rechts gezeichnet. - * - * @param {Array<{value: number}>} history - * @param {number} [width] - * @param {number} [height] - * @param {number} [padding] - * @returns {string} - */ -export function buildKpiSparklinePoints(history = [], width = 140, height = 32, padding = 4) { - if (history.length === 0) { - return ""; - } - - const chronological = [...history].reverse(); - const values = chronological.map((point) => point.value); - const min = Math.min(...values); - const max = Math.max(...values); - const range = max - min || 1; - const stepX = chronological.length > 1 ? (width - padding * 2) / (chronological.length - 1) : 0; - - return chronological - .map((point, index) => { - const x = padding + index * stepX; - const y = height - padding - ((point.value - min) / range) * (height - padding * 2); - return `${x.toFixed(1)},${y.toFixed(1)}`; - }) - .join(" "); -} - // Fuenf statt vier Kacheln, seit "Problem" (abgelaufene Agenten-Anmeldung) hinzugekommen ist: // renderOfficeScene() reserviert bereits die letzte Kachel fuer "Hooks" (Issue #38), womit // "Agenten"/"Online"/"Problem" die uebrigen drei fuellen wuerden - fuer die gemeldeten KPIs (F7) -// bliebe dann kein Platz mehr. Der KPI-Monitor ist hoch genug: eine Zeile ohne Sparkline braucht +// bliebe dann kein Platz mehr. Der KPI-Monitor ist hoch genug: eine Zeile braucht // 24 px von 340 (siehe renderKpiMonitor() in office-render.js). export const MAX_KPI_TILES = 5; @@ -514,7 +481,6 @@ export function buildKpiTiles(kpis = []) { // Nur abgeleitete Kacheln setzen einen Schweregrad (aktuell "Problem", siehe // buildAgentCountKpis()); gemeldete KPIs (F7) kennen kein solches Feld und bleiben neutral. severity: kpi.severity ?? null, - sparklinePoints: buildKpiSparklinePoints(kpi.history || []), })); } @@ -535,7 +501,7 @@ export function buildHooksKpi(count) { } /** - * Inhaltsmodell fuer das KPI-Monitor-Modal (groessere Sparkline als die Wandkachel). + * Inhaltsmodell fuer das KPI-Monitor-Modal . * * @param {Array} kpis */ @@ -548,7 +514,6 @@ export function buildKpiModalContent(kpis = []) { unit: kpi.unit || "", currentValue: kpi.current_value, history: kpi.history || [], - sparklinePoints: buildKpiSparklinePoints(kpi.history || [], 320, 80), })), }; } diff --git a/tests/frontend/office-scene.test.js b/tests/frontend/office-scene.test.js index 74af8c5..8ee62c3 100644 --- a/tests/frontend/office-scene.test.js +++ b/tests/frontend/office-scene.test.js @@ -23,7 +23,6 @@ import { buildSystemModalContent, systemsWithoutHostConfig, formatSystemCheckTime, - buildKpiSparklinePoints, buildKpiTiles, buildKpiModalContent, buildAgentCountKpis, @@ -415,18 +414,6 @@ test("formatSystemCheckTime liefert null fuer fehlende/ungueltige Werte", () => assert.equal(formatSystemCheckTime("nicht-valide"), null); }); -test("buildKpiSparklinePoints liefert leeren String ohne Historie und einen Punkt pro Messwert sonst", () => { - assert.equal(buildKpiSparklinePoints([]), ""); - const points = buildKpiSparklinePoints([{ value: 3 }, { value: 1 }, { value: 2 }], 100, 20); - assert.equal(points.split(" ").length, 3); -}); - -test("buildKpiSparklinePoints behandelt konstante Werte ohne Division durch 0", () => { - const points = buildKpiSparklinePoints([{ value: 5 }, { value: 5 }], 100, 20); - assert.equal(points.split(" ").length, 2); - assert.ok(points.length > 0); -}); - test("buildKpiTiles kappt bei MAX_KPI_TILES", () => { const kpis = Array.from({ length: MAX_KPI_TILES + 2 }, (_, i) => ({ key: `k${i}`,