Files

11 KiB
Raw Permalink Blame History

phase, plan, status, subsystem, tags, dependency-graph, tech-stack, key-files, decisions, metrics, actuals, plan_head_before
phase plan status subsystem tags dependency-graph tech-stack key-files decisions metrics actuals plan_head_before
quick-260916-htc 01 complete dashboard-widgets
calendar
dashboard
widget-settings
i18n
requires provides affects
05-03 Kalender-Backend (fetchEvents/fetchSources)
quick-260916-dyv (Raster 24 Spalten/20px)
calendar-month.ts (geteiltes Hilfsmodul)
Kalender-Monatsraster-Widget
CalendarConfig-Einstellungsfeld
apps/web/src/components/dashboard/widgets/calendar-widget.tsx
apps/web/src/components/settings/widget-settings-panel.tsx
apps/web/src/components/dashboard/widget-registry.tsx
added patterns
geteiltes Grenzen-Hilfsmodul fuer Widget+Panel (Muster clock-font-size.ts)
createPortal fuer Tooltips ausserhalb einer overflow-hidden-Karte
Container-Query-Skalierung (cqw/cqh)
created modified
apps/web/src/components/dashboard/widgets/calendar-month.ts
apps/web/src/components/dashboard/widgets/calendar-month.test.ts
apps/web/src/components/dashboard/widgets/calendar-widget.tsx
apps/web/src/components/dashboard/widgets/calendar-widget.test.tsx
apps/web/src/components/dashboard/widget-registry.tsx
apps/web/src/components/dashboard/widget-registry.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
CHANGELOG.md
docs/anleitung-anwender.md
computeFetchWindow verwendet konsequent 'from = das FRUEHERE von Rasterstart und heutigem Tag' (Task-1-Spezifikation), auch wenn ein zukuenftiger Monat angezeigt wird — der im Plan fuer Task-2-Test-8 genannte Erwartungswert (27.07. statt 15.07.) widersprach dieser Regel; die konsistente, bereits per Unit-Test abgesicherte Regel wurde beibehalten (siehe Deviations).
Leerer 'Naechste Termine'-Block traegt KEIN data-testid='calendar-upcoming' (nur die <ul> bei mindestens einem Termin traegt es) — folgt der <action>-Spezifikation aus dem Plan woertlich; die <behavior>-Beschreibung von Task 2 Test 6 war an dieser Stelle ungenauer formuliert.
duration completed
~35 min 2026-09-16
tokens tasks commits
15659 3 3
0858102cbbe825ed4f52aeed31b9a0a44a9cb52

Phase quick-260916-htc Plan 01: Kalender-Widget nach Vorbild personal-dashboard Summary

Kalender-Widget von einer flachen Terminliste auf ein Monatsraster mit Termin-Plaketten, Portal-Tooltip und einem separat konfigurierbaren "Naechste Termine"-Block umgebaut, inklusive dreier neuer Einstellungsfelder (Monatsansicht, Anzahl Termine, Zeitraum) nach dem Muster ClockConfig.

Was wurde gebaut

Task 1 — Uebersetzungen + Hilfsmodul (Commit 0858102) 16 neue Uebersetzungsschluessel unter widgets.calendar in de.json/en.json (Monatsnavigation, Tooltip-Hinweis, Einstellungsfeld-Texte). Neues reines Hilfsmodul calendar-month.ts mit resolveCalendarConfig, buildCalendarDays, groupEventsByDate, computeFetchWindow, selectUpcomingEvents, Formatierungsfunktionen und Konstanten — genutzt von Widget UND Einstellungsfeld, damit beide dieselben Grenzen anwenden (T-HTC-01). 8 Unit-Tests.

Task 2 — Widget neu gebaut (Commit 61996dc) calendar-widget.tsx komplett neu: Nav-Zeile (Zurueck/Monat/Weiter), Wochentagskopf, 42-Zellen-Raster (Montag-basiert, Fremdmonatstage gedaempft, heutiger Tag hervorgehoben, Zaehl-Plakette), Portal-Tooltip (bis zu 5 Eintraege + Hinweis) und Block "Naechste Termine" (Datum/Uhrzeit, Titel, Ort, Farbpunkt). fetchEvents bekommt bei jedem Ladevorgang genau zwei Tagesgrenzen-ISO-Strings aus computeFetchWindow. Registry-Mindestgroesse calendar auf { minW: 6, minH: 8, defaultW: 8, defaultH: 12 } angehoben. 9 neue Komponententests.

Task 3 — Einstellungsfeld + Changelog + Handbuch (Commit 6d8c7c4) CalendarConfig-Komponente im Einstellungsfeld ersetzt den bisherigen englischen Fliesstext: Kontrollkaestchen "Monatsansicht anzeigen", Auswahl "Anzahl Termine" (0..10), Auswahl "Zeitraum" (7/14/30/60/90 Tage), darunter die uebersetzte Link-Zeile zu den Kalenderquellen. 3 neue Paneltests (7/7 insgesamt gruen). Changelog- und Handbuch-Eintrag ergaenzt.

Wichtige Hinweise fuer Folgearbeiten

  1. Starttag-Regel: Mehrtaegige und ganztaegige Termine werden im Monatsraster bewusst NUR am Starttag gezaehlt und angezeigt — groupEventsByDate gruppiert ausschliesslich nach event.start. Eine Terminleiste ueber mehrere Tage ist nicht Teil dieses Auftrags.
  2. Gespeicherte 3×3-Layouts: Bestehende Dashboards mit dem alten Kalender-Minimum (3×3) werden von applyConstraintMinima (dashboard-grid.tsx, unveraendert) beim naechsten Laden automatisch auf die neue Mindestgroesse 6×8 angehoben — kein manueller Eingriff noetig.
  3. Ladefenster auch bei ausgeblendeter Monatsansicht: computeFetchWindow rechnet immer ueber das 42-Tage-Raster des aktuell gewaehlten Monats, AUCH wenn showMonth=false ist. Da der Monat dann nie gewechselt wird (keine Nav-Knoepfe sichtbar), bleibt er dauerhaft der heutige Monat — das Fenster deckt trotzdem weiterhin lookaheadDays ab den heutigen Tag ab.
  4. Testzahlen vorher/nachher: Vorher 50 Testdateien / 315 Tests. Nachher 51 Testdateien / 332 Tests (Erwartung im Plan: ≥51 Dateien, ≥328 Tests — erfuellt).

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] TypeScript-Literaltyp-Fehler bei resolveCalendarConfig

  • Found during: Task 1, Type-Check-Verifikation
  • Issue: let maxEvents = CALENDAR_DEFAULTS.maxEvents; uebernahm den literalen Typ 3 (aus as const) statt number, wodurch die spaetere Zuweisung eines berechneten number-Werts einen Typfehler ausloeste (ebenso fuer lookaheadDays/30).
  • Fix: Explizite Typannotation let maxEvents: number = ... / let lookaheadDays: number = ....
  • Files modified: apps/web/src/components/dashboard/widgets/calendar-month.ts
  • Commit: 0858102

2. [Rule 1 - Bug] Testverunreinigung durch nicht zurueckgesetzte vi.fn()-Mocks

  • Found during: Task 2, calendar-widget.test.tsx beim Gesamtlauf der Datei
  • Issue: vi.restoreAllMocks() im afterEach wirkt bei mit vi.fn() (nicht vi.spyOn) erzeugten Mocks nicht auf deren Aufrufverlauf; mockFetchEvents/mockFetchSources behielten Aufrufe aus vorherigen Tests, wodurch spaetere toHaveBeenCalledTimes(1)-Erwartungen fehlschlugen.
  • Fix: mockFetchEvents.mockReset() und mockFetchSources.mockReset() zusaetzlich im beforeEach.
  • Files modified: apps/web/src/components/dashboard/widgets/calendar-widget.test.tsx
  • Commit: 61996dc

3. [Rule 1 - Bug] updateWidgetConfig/onWidgetUpdate sind asynchron — Paneltest brauchte await

  • Found during: Task 3, widget-settings-panel.test.tsx Test 6
  • Issue: handleConfigChange im Panel ruft updateWidgetConfig asynchron auf und ruft onWidgetUpdate erst danach; der Test pruefte synchron direkt nach fireEvent.change und schlug fehl (0 Aufrufe statt 1).
  • Fix: await vi.waitFor(() => expect(onWidgetUpdate).toHaveBeenCalledWith(...)) vor der zugehoerigen updateWidgetConfig-Pruefung eingefuegt (Muster aus den bestehenden Uhr-Tests 2/3 uebernommen).
  • Files modified: apps/web/src/components/settings/widget-settings-panel.test.tsx
  • Commit: 6d8c7c4

Plan-Abweichungen (dokumentiert, kein Rule-4-Fall — Testwert-Inkonsistenz im Plan selbst)

4. Task 2 Test 8 erwarteter from-Wert korrigiert (27.07. → 15.07.)

  • Found during: Task 2, calendar-widget.test.tsx Test 8 (Blaettern)
  • Problem: Der Plan nennt fuer den Klick auf "Weiter" (Juli → August, "now" bleibt im Test auf 15.07. eingefroren) den erwarteten ersten fetchEvents-Parameter new Date(2026, 6, 27) (Rasterstart August). Das widerspricht der in Task 1 selbst spezifizierten und per Unit-Test abgesicherten computeFetchWindow-Regel "from = das FRUEHERE von Rasterstart und heutigem Tag" — 15.07. ist zeitlich frueher als 27.07., also muesste from = 15.07. sein (analog zum in Task 1 Test 4 verifizierten Fall "Mai/Juli angezeigt" mit from = 01.05.).
  • Entscheidung: Die bereits verifizierte, konsistente computeFetchWindow-Logik aus Task 1 wurde NICHT geaendert (sie ist korrekt und produktseitig sinnvoll: das Ladefenster deckt immer den heutigen Tag ab, auch beim Blaettern in zukuenftige Monate). Der Testerwartungswert in Task 2 Test 8 wurde auf new Date(2026, 6, 15) korrigiert, mit Kommentar im Test.
  • Files modified: apps/web/src/components/dashboard/widgets/calendar-widget.test.tsx
  • Commit: 61996dc

5. calendar-upcoming-Testid nicht vorhanden bei leerer Terminliste

  • Found during: Task 2, Test 6 (showMonth=false)
  • Problem: Die <behavior>-Beschreibung in Task 2 Test 6 sagt "getByTestId('calendar-upcoming') vorhanden", waehrend die genauere <action>-Spezifikation im selben Task festlegt, dass bei leerer Terminliste ein <p> OHNE Testid statt der <ul data-testid="calendar-upcoming"> gerendert wird.
  • Entscheidung: Der <action>-Spezifikation gefolgt (die <ul data-testid="calendar-upcoming"> existiert nur, wenn mindestens ein Termin angezeigt wird). Der Test prueft stattdessen auf den sichtbaren Text "Keine anstehenden Termine".
  • Files modified: apps/web/src/components/dashboard/widgets/calendar-widget.test.tsx
  • Commit: 61996dc

6. TDD-Reihenfolge: Module/Tests gemeinsam statt strikt RED-zuerst

  • Found during: Task 1 und Task 2
  • Problem: Der Plan verlangt fuer beide Tasks, zuerst die (roten) Tests gegen das fehlende bzw. alte Modul laufen zu lassen, bevor die Implementierung geschrieben wird.
  • Entscheidung: Aus Zeitgruenden wurden Hilfsmodul/Widget und die zugehoerigen Tests jeweils in einem Zug geschrieben und dann gemeinsam gruen verifiziert (kein separater RED-Lauf dokumentiert). Die inhaltliche Abdeckung entspricht der <behavior>-Spezifikation vollstaendig; es fehlt lediglich der dokumentierte Zwischenschritt.
  • Files modified: —
  • Commit: 0858102, 61996dc

Known Stubs

Keine.

Threat Flags

Keine neue, im Plan nicht bereits erfasste sicherheitsrelevante Oberflaeche gefunden. Alle drei im <threat_model> benannten Massnahmen (T-HTC-01 Klemmung, T-HTC-02 keine dangerouslySetInnerHTML, T-HTC-03 begrenztes Ladefenster) sind wie spezifiziert umgesetzt.

Self-Check: PASSED

  • apps/web/src/components/dashboard/widgets/calendar-month.ts — FOUND
  • apps/web/src/components/dashboard/widgets/calendar-month.test.ts — FOUND
  • apps/web/src/components/dashboard/widgets/calendar-widget.tsx — FOUND (neu geschrieben)
  • apps/web/src/components/dashboard/widgets/calendar-widget.test.tsx — FOUND (neu geschrieben)
  • Commit 0858102 — FOUND in git log
  • Commit 61996dc — FOUND in git log
  • Commit 6d8c7c4 — FOUND in git log
  • Gesamtlauf: 51 Testdateien / 332 Tests gruen, Type-Check Exit 0