Files
tessera-ctl/.planning/quick/260924-i8v-proxmox-kachel-fuers-dashboard/260924-i8v-SUMMARY.md
T
schalli dd09c08311
Tessera CI/CD / Lint & Type Check (push) Successful in 54s
Tessera CI/CD / Tests (push) Successful in 1m22s
Tessera CI/CD / Desktop-Pakete bauen (push) Successful in 20s
Tessera CI/CD / Build & Publish Images (push) Successful in 3m18s
docs(quick-260924-i8v): Proxmox-Kachel fuers Dashboard
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 13:38:17 +02:00

174 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
quick_id: 260924-i8v
phase: quick
plan: 260924-i8v
subsystem: web / dashboard, proxmox-modul; shared (Kacheltypen); api (Kachel-Modul-Zuordnung)
status: complete
tags: [proxmox, dashboard, modul-kachel, container-query, statusfarben, a11y]
requires: [quick-260922-m1h (Modul bringt Kachel mit), quick-260924-h7x (Statussprache Proxmox), quick-260923-dhh (Proxmox-Modul)]
provides:
- Kacheltyp proxmox (WIDGET_TYPES zuletzt, WIDGET_MODULE_SLUGS = { proxmox: 'proxmox' })
- ProxmoxWidget mit Balken, Zusammenfassung, Serverliste, Minutentakt, Bearbeitungsmodus
- gemeinsamer Ordner apps/web/src/components/proxmox/ (Statuslogik, HealthBar compact, Stile, Zahlformat, Serverauswahl)
- ProxmoxWidgetConfigForm fuer Einstellungen > Dashboard
affects:
- apps/web/src/app/(portal)/modules/proxmox/* (Importpfade, Zahlformat aus gemeinsamer Datei)
- apps/web/src/components/dashboard/widget-registry.tsx, (portal)/page.tsx
- apps/web/src/components/settings/widget-settings-panel.tsx
- apps/api/src/dashboard/widget-module-map.* (Zuordnung jetzt nicht mehr leer)
tech-stack:
added: []
patterns:
- Modul-Kachel liest nur das Zwischenlager des Moduls, nie eine Live-Abfrage (Grep-Tor + Spion im Test)
- Zeilen im Ansichtsmodus Links, im Bearbeitungsmodus schlichte Elemente (Abbruch-Selektor des Rasters)
- Groessenstufen per Container-Query am Wrapper-Rumpf, kein innerer Container
- Zeitgeber-Tests faelschen nur setInterval bzw. setTimeout, damit die Warte-Helfer der Testing Library laufen
key-files:
created:
- apps/web/src/components/dashboard/widgets/proxmox-widget.tsx
- apps/web/src/components/dashboard/widgets/proxmox-widget.test.tsx
- apps/web/src/components/dashboard/widgets/proxmox-widget-model.ts
- apps/web/src/components/dashboard/widgets/proxmox-widget-model.test.ts
- apps/web/src/components/proxmox/proxmox-server-picker.tsx
- apps/web/src/components/proxmox/proxmox-server-picker.test.tsx
- apps/web/src/components/settings/proxmox-widget-config-form.tsx
- apps/web/src/components/settings/proxmox-widget-config-form.test.tsx
moved:
- apps/web/src/components/proxmox/proxmox-status.ts (git mv aus app/(portal)/modules/proxmox/components/)
- apps/web/src/components/proxmox/proxmox-status.test.ts (git mv)
- apps/web/src/components/proxmox/HealthBar.tsx (git mv)
- apps/web/src/components/proxmox/status-styles.ts (git mv)
modified:
- packages/shared/src/index.ts
- apps/api/src/dashboard/widget-module-map.ts
- apps/api/src/dashboard/widget-module-map.spec.ts
- apps/web/src/app/(portal)/modules/proxmox/page.tsx
- apps/web/src/app/(portal)/modules/proxmox/components/ServerCard.tsx
- apps/web/src/app/(portal)/page.tsx
- apps/web/src/app/(portal)/page.test.tsx
- apps/web/src/components/dashboard/widget-registry.tsx
- apps/web/src/components/dashboard/widget-registry.test.tsx
- apps/web/src/components/dashboard/widget-catalog-modal.test.tsx
- apps/web/src/components/settings/widget-settings-panel.tsx
- apps/web/src/components/settings/widget-settings-panel.test.tsx
- apps/web/src/messages/de.json
- apps/web/src/messages/en.json
- docs/anleitung-anwender.md
- docs/anleitung-entwicklung.md
- CHANGELOG.md
decisions:
- Die Kachel zeigt im Zustand „ausgewählte Server gibt es nicht mehr“ bei offener Auswahl direkt die Auswahl statt des Satzes, damit sich der Zustand an Ort und Stelle beheben lässt
- „Server auswählen“ erscheint nur, wenn eine Serverliste geladen und nicht leer ist
- Speichern aus der Kachel (Titel, Auswahl) fängt Fehler still ab; der nächste Ladevorgang zeigt den gespeicherten Stand
- Die Kennzahl bei PVE-Warnung fällt auf die Gästezahl zurück, falls kein einziger Auslastungswert bekannt ist
metrics:
duration: 22min
completed: 2026-09-24
tasks: 3
files: 29
plan_head_before: 8bfa4fc46737b91ed6860089721a67f17014c3d1
actuals:
tokens: 29800
tasks: 3
commits: 6
---
# Quick 260924-i8v: Proxmox-Kachel fürs Dashboard
Die erste echte Modul-Kachel: „Proxmox“ zeigt oben einen 6 px hohen Gesundheitsbalken und darunter in Worten „Alles in Ordnung“ oder zum Beispiel „1 nicht erreichbar, 1 mit Warnung“ in der Farbe des schlimmsten Zustands. Darunter stehen die Server nach Dringlichkeit, jeder mit Statuspunkt, Name und genau einer Kennzahl. Ein Klick führt zur Modulseite. Die Kachel liest nur das Zwischenlager, frischt sich minütlich auf, lässt sich auf Titel und Serverauswahl einstellen und stuft sich per Container-Query ab.
## Was gebaut wurde
**Aufgabe 1: Durchstich (a906c67)**
- Die vier gemeinsamen Dateien (`proxmox-status.ts` samt Test, `HealthBar.tsx`, `status-styles.ts`) liegen jetzt per `git mv` unter `apps/web/src/components/proxmox/`. Die Git-Historie bleibt erhalten. Modulseite und `ServerCard` importieren sie über `@/components/proxmox/...`. An der Logik hat sich nichts geändert.
- `HealthBar` hat eine neue Variante `variant="compact"`: 6 px hoch (`h-1.5`), ohne Legende und mit `aria-hidden`. Die Variante `full` ist Standard, die Modulseite sieht unverändert aus. Beide tragen `data-variant`.
- `packages/shared`: `'proxmox'` steht am Ende von `WIDGET_TYPES`, dazu `WIDGET_MODULE_SLUGS = { proxmox: 'proxmox' }`. Der Kommentar „bewusst leer“ ist in beiden Dateien korrigiert, in `shared` und in `widget-module-map.ts`.
- Registry: 3/4/8/8 mit Rechenkommentar, Inline-Symbol mit Server-Einschüben, `moduleSlug: WIDGET_MODULE_SLUGS.proxmox`.
- `registerWidget('proxmox', ProxmoxWidget)` steht in `(portal)/page.tsx`, das passende `vi.mock` im Seitentest.
- Die bestehenden Tests sind nachgezogen:
- Die Registry kennt zehn Typen. Nur proxmox trägt einen Modul-Slug. Die Tests für einen unbekannten Typ nutzen jetzt `'gibt-es-nicht'`.
- Der Katalog zeigt zehn Kacheln bei `['proxmox']`, neun bei `[]`. Mit `null` fehlt Proxmox, und zwar an der echten Kachel statt an der vorher nur vorübergehend umgebauten Uhr.
- Die API-Spec prüft `getModuleSlugForWidgetType('proxmox') === 'proxmox'`.
**Aufgabe 2: Serverliste (RED 92bf130, GREEN a217d60)**
- `formatPercent` und `formatCount` sind unverändert aus `ServerCard.tsx` nach `proxmox-status.ts` gezogen. ServerCard importiert sie von dort, damit das Zahlformat nicht doppelt existiert.
- Die reinen Funktionen in `proxmox-widget-model.ts`:
- `resolveProxmoxWidgetConfig` liest die Konfiguration abwehrend: Nicht-Strings und leere Kennungen fallen weg, doppelte zählen einmal.
- `selectServers`: leere Auswahl bedeutet alle Server; bleiben nur gelöschte Kennungen, wird `selectionGone` gesetzt.
- `widgetKeyFigure` wählt die eine Kennzahl je Zeile:
- Status bei down, idle und orphan
- Gäste bei PVE im Normalzustand, bei PVE-Warnung der höchste bekannte Anteil aus CPU, RAM und Speicher
- bei PBS die älteste bekannte Sicherung samt Hinweis, ob sie veraltet ist
- bei PMG `countIn`
- sonst `unknown`, nie 0
- Kachel:
- Die gefilterte Liste speist Balken, Zusammenfassung und Zeilen, sortiert nach `sortServersByHealth`.
- Je Zeile ein Punkt, der Name (bei orphan nur der Name mit `opacity-70`) und das Zustandswort als `sr-only`.
- Die Kennzahl steht rechts mit `@max-[15rem]:hidden`. Wiederholt sie nur den Zustand, ist sie `aria-hidden`.
- Die Liste trägt `[@container(max-height:7.5rem)]:hidden @max-[8rem]:hidden`.
- Im Ansichtsmodus ist jede Zeile ein `next/link` auf `/modules/proxmox`. Im Bearbeitungsmodus ist sie ein `div` ohne Tabstopp, das gilt auch für den Admin-Link im Leerzustand.
- Takt: `REFRESH_MS = 60_000`, bei verborgenem Tab kein Abruf, `visibilitychange` zurück auf sichtbar lädt sofort. Beim Aushängen wird aufgeräumt.
- Scheitert ein späteres Nachladen, bleibt die zuletzt geladene Liste stehen.
**Aufgabe 3: Einstellen, Doku, Tore (RED 377b6e3, GREEN 586da44, Doku 602a45c)**
- `ProxmoxServerPicker`:
- ein `fieldset` mit der Legende „Angezeigte Server“ und dem sichtbaren Hinweis „Ohne Auswahl zeigt die Kachel alle Server.“
- je Server ein Kästchen, sortiert nach `position`, Name plus Produktwort, eindeutige Kennungen per `useId`
- `onChange` liefert die Kennungen in Listenreihenfolge und nur für vorhandene Server. Kennungen gelöschter Server räumen sich dabei selbst auf.
- Kachel im Bearbeitungsmodus:
- `pt-5` unter der Griffleiste. Die Kopfzeile erscheint immer, mit Titelfeld (`widgetNoDrag`, 1500 ms entprellt, `updateWidgetConfig({ title })`) und dem Textknopf „Server auswählen“ (`aria-expanded`, `data-no-drag`).
- Die offene Auswahl ersetzt den Listenbereich in einer Hülle mit `widgetNoDrag`. Sie bekommt die ungefilterte, schon geladene Liste; ein zusätzlicher Abruf findet nicht statt.
- Eine Änderung filtert sofort und speichert `{ serverIds }`. Beim Verlassen des Bearbeitungsmodus schließt die Auswahl.
- `ProxmoxWidgetConfigForm` (Titel `proxmox-widget-title` plus Auswahl) ist unter Einstellungen > Dashboard eingehängt. Die Instanz-Kopfzeile zeigt „Proxmox #1 — Titel“.
- Doku:
- Anwenderdoku: Tabellenzeile „Proxmox“, Aufzählung der zusätzlichen Einstellungen, Absatz „Dashboard > Widgets“, Absatz im Abschnitt „### Proxmox“.
- Entwicklerdoku: Proxmox als erstes Beispiel unter „Eine Kachel zum Modul“, mit dem Ort `components/proxmox/`.
- CHANGELOG: ein Punkt unter „Unveröffentlicht > Neu“.
## Abweichungen vom Plan
1. **[Rule 1, Kommentar] `apps/api/src/dashboard/widget-module-map.ts`** stand nicht in der Dateiliste. Sein Kopfkommentar behauptete aber weiterhin „Die Tabelle ist bewusst leer“. Korrigiert ist nur der Kommentar, der Code ist unverändert (a906c67).
2. **Zeitgeber-Tests:** Statt `vi.useFakeTimers()` ohne Einschränkung werden nur `setInterval`/`clearInterval` gefälscht, beim Entprell-Test nur `setTimeout`/`clearTimeout`. Grund: `findBy`/`waitFor` der Testing Library laufen über `setTimeout` und blieben mit vollständig gefälschten Zeitgebern unter Vitest hängen. Die geforderten Nachweise sind unverändert erbracht (60 s, verborgen, sichtbar, Aushängen).
3. **Auswahl im Zustand „Server gibt es nicht mehr“:** Ist die Auswahl im Bearbeitungsmodus offen, zeigt die Kachel dort die Auswahl statt des Satzes. Der Satz selbst fordert dazu auf, im Bearbeitungsmodus andere Server zu wählen, und das ist so an Ort und Stelle möglich.
4. **Biome:** Importreihenfolge in `ServerCard.tsx` und Formatierung der neuen Dateien mit `biome check --write` angeglichen. Die Reihenfolge verschob sich durch den neuen `@/components`-Pfad. Keine Logikänderung.
Keine Architekturfragen, keine neuen Pakete, keine Anmelde-Sperren.
## Tore (gemessen)
| Tor | Ergebnis |
|---|---|
| Web-Tests vollständig (`vitest run`) | 91 Dateien, 864 Tests grün |
| API-Tests vollständig (`vitest run`) | 84 Dateien, 1370 Tests grün, darunter `src/prisma/rls-access-inventory.spec.ts` (30 Tests, einzeln nachgeprüft) |
| `pnpm turbo run type-check lint` | 9 von 9 Aufgaben erfolgreich |
| Biome-Warnungen Web | 53 (Grenze 53); die neuen Dateien sind warnungsfrei |
| Stil-Grep (uppercase, tracking-widest, Mittelpunkt, Pfeil, dangerouslySetInnerHTML) | leer |
| Abfrage-Grep `pollServer` in Kachel, Modell, Auswahl, Formular | 0 Treffer außerhalb von Kommentaren |
| Übersetzungen `widgets.proxmox.*` (15 Schlüssel) in de und en | vollständig; die Umlaut-Wache ist grün |
| Tailwind-Probelauf (Wegwerfskript im Scratchpad, danach gelöscht) | `@container (width < 15rem)`, `@container (width < 8rem)` und `@container (max-height:7.5rem)` werden erzeugt |
| `any`, `!`, `biome-ignore` in neuen Dateien | keine |
**TDD:** Die RED-Phase ist im Verlauf belegt: Test-Commit 92bf130 vor a217d60 und Test-Commit 377b6e3 vor 586da44. Die Tests schlugen aus dem richtigen Grund fehl: fehlende Exporte, Zeilen und Module.
## Hinweise für den Browser-Nachweis
- Die Kachel braucht einen neu gebauten Web-Container, also `--build`. Docker wurde vom Executor nicht angefasst.
- Zeilen tragen `data-testid="proxmox-row"` und `data-server-name`, die Kennzahl `data-testid="proxmox-key-figure"`, die Liste `data-testid="proxmox-list"`, die Zusammenfassung `data-testid="proxmox-summary"`, der Balken `data-testid="health-bar"` mit `data-variant="compact"`.
- Größenstufen: bei 4 Spalten (rund 216 px, also unter 15rem = 240 px) nur Punkte und Namen. Bei 3×4 (104 px hoch, unter 7.5rem = 120 px) nur Balken und Zusammenfassung.
- Netzwerk: im Minutentakt nur `GET /modules/proxmox/servers`. Beim Öffnen von „Server auswählen“ gibt es keinen weiteren Abruf.
- Im Bearbeitungsmodus sind Titelfeld, Knopf und Auswahlhülle vom Ziehen ausgenommen. Die Zeilen sind keine Links, die Kachel bleibt über ihnen ziehbar.
## Bewusst offen
- Einstellungen > Dashboard zeigt weiterhin nur die Kacheln des ersten Reiters (bekannte Grenze aus quick-260923-ad9). Deshalb gibt es Titel und Serverauswahl zusätzlich direkt an der Kachel.
- Lokaler Titel- und Auswahlzustand der Kachel wird wie bei den Favoriten nur beim Einhängen aus `config` gelesen. Eine Änderung unter Einstellungen > Dashboard wirkt auf eine gleichzeitig offene Dashboard-Seite erst nach dem Neuladen.
## Known Stubs
Keine.
## Self-Check: PASSED
- Alle angelegten Dateien vorhanden: proxmox-widget.tsx, proxmox-widget-model.ts, beide Tests, proxmox-server-picker.tsx samt Test, proxmox-widget-config-form.tsx samt Test, die vier verschobenen Dateien unter components/proxmox/.
- Alle Commits vorhanden: a906c67, 92bf130, a217d60, 377b6e3, 586da44, 602a45c.