monitor/html/js/office-modal.js
fds2610-bot 10ecad93d5 Phase 3-5 der Neuausrichtung: Board/Monitor-Wand live, SSE-Push, Agenten-Animation
Setzt Visualization.md Abschnitt 9, Phasen 3-5 vollstaendig um:

Phase 3 (Kanban-Board live): Board zeigt echte Ticket-Daten aus GET /api/v1/tickets
(office-api.js), Klick auf eine Spalte oeffnet ein Modal mit Titel/Beschreibung/Typ und
einem Link auf die Codeberg-Quelle bei per Sync angelegten Tickets (F4).

Phase 4 (Monitor-Wand live): Event-, System- und KPI-Monitor zeigen echte Daten,
Klick-Modals fuer alle drei. Neuer SSE-Endpoint GET /api/v1/stream (F13) meldet per
ChangeFeed-Fingerabdruck, welche Ressourcen sich geaendert haben; office-realtime.js nutzt
EventSource mit Polling-Fallback. KPI-Monitor zeichnet eine eigene SVG-Sparkline (F10, kein
Chart-Lib) sobald KPIs gemeldet wurden, sonst weiterhin der Phase-2-Platzhalter (F7 bleibt
inhaltlich offen). API-Antworten tragen jetzt CORS-Header, da Frontend (:8090) und API
(:8091) im Docker-Compose-Setup unterschiedliche Origins sind.

Phase 5 (Agenten & Animation): resolveAgentVisualState bildet gemeldete Agenten-Zustaende
auf Ort/Pose ab; Agenten-Avatare sind eine per CSS transition animierte, von Board/
Schreibtisch-Moebeln entkoppelte Schicht, die zwischen Schreibtisch, Board, Monitor-Wand und
einer neuen Kaffee-Ecke laufen. Idle-Varianten (Zeitung/Kaffee/Schwaetzchen) werden rein
kosmetisch client-seitig zufaellig ausgeloest (F8), eine AnimationQueue serialisiert
Update-Animationen bei vielen gleichzeitigen Ereignissen (F9).

29 Node-Tests (100% Line-Coverage office-scene.js) und neue PHPUnit-Tests fuer
Response::stream(), ChangeFeed, StreamController und die neuen Repository::fingerprint()-
Methoden. PHP/Docker-Ausfuehrung konnte in dieser Umgebung nicht verifiziert werden (kein
PHP verfuegbar) - vor dem Merge bitte `docker compose run --rm api composer test` pruefen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 17:50:44 +02:00

59 lines
1.8 KiB
JavaScript

// Generisches Modal fuer Board-/Monitor-Detailansichten (Visualization.md 4.5: "Modals sind
// reines HTML/CSS/JS ohne fremde UI-Bibliothek, per <dialog>-Element ... umgesetzt"). Dieses
// Modul kuemmert sich nur um Erzeugen/Oeffnen/Schliessen des <dialog>-Elements; welchen Inhalt
// es zeigt, entscheidet der Aufrufer (office-render.js) per renderBody-Callback.
let dialogEl = null;
function ensureDialog() {
if (dialogEl) {
return dialogEl;
}
dialogEl = document.createElement("dialog");
dialogEl.className = "office-modal";
dialogEl.innerHTML = `
<form method="dialog" class="office-modal-form">
<header class="office-modal-header">
<h2 class="office-modal-title"></h2>
<button type="submit" class="office-modal-close" aria-label="Schliessen">&times;</button>
</header>
<div class="office-modal-body"></div>
</form>
`;
document.body.appendChild(dialogEl);
return dialogEl;
}
/**
* Oeffnet das Modal mit einem Titel und laesst den Aufrufer den Body fuellen.
*
* @param {{title: string}} content
* @param {(body: HTMLElement, content: object) => void} renderBody
*/
export function openModal(content, renderBody) {
const dialog = ensureDialog();
dialog.querySelector(".office-modal-title").textContent = content.title;
const body = dialog.querySelector(".office-modal-body");
body.replaceChildren();
renderBody(body, content);
if (typeof dialog.showModal === "function") {
dialog.showModal();
} else {
// Fallback fuer Umgebungen ohne <dialog>-Unterstuetzung (z.B. sehr alte Browser).
dialog.setAttribute("open", "");
}
}
export function closeModal() {
if (dialogEl === null) {
return;
}
if (typeof dialogEl.close === "function") {
dialogEl.close();
} else {
dialogEl.removeAttribute("open");
}
}