Files

5.8 KiB

phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics
05-dashboard-calendar 02 dashboard
dashboard
widgets
search
notes
markdown
settings
prisma
i18n
requires provides affects
DashboardModule
WidgetRegistry
SettingsLayout
SearchWidget
NoteWidget
WidgetSettingsPanel
SearchProviderForm
SearchProviderModel
apps/api/prisma/schema.prisma
apps/web/src/components/dashboard/widget-registry.tsx
apps/web/src/lib/dashboard-api.ts
apps/web/src/messages/en.json
apps/web/src/messages/de.json
added patterns
@uiw/react-md-editor@4.1.1
rehype-sanitize
AbortController for in-flight request cancellation
debounced autosave
wireWidget deferred wiring
SearchProvider defaults-as-constants merged with user rows
created modified
apps/web/src/components/dashboard/widgets/search-widget.tsx
apps/web/src/components/dashboard/widgets/note-widget.tsx
apps/web/src/components/dashboard/widgets/search-widget.test.tsx
apps/web/src/components/dashboard/widgets/note-widget.test.tsx
apps/web/src/app/(portal)/settings/dashboard/page.tsx
apps/web/src/components/settings/widget-settings-panel.tsx
apps/web/src/components/settings/search-provider-form.tsx
apps/api/src/dashboard/dto/create-search-provider.dto.ts
apps/web/src/components/dashboard/widget-registry.tsx
apps/web/src/lib/dashboard-api.ts
apps/web/package.json
apps/web/src/messages/en.json
apps/web/src/messages/de.json
apps/api/prisma/schema.prisma
apps/api/src/dashboard/dashboard.controller.ts
apps/api/src/dashboard/dashboard.service.ts
useRef with explicit undefined initial value for React 19 strict TypeScript compatibility
SearchProvider defaults as code constants merged with user DB rows (no seed migration needed)
typeof narrowing for unknown config.title to satisfy ReactNode type constraint
prisma db push via host-to-container IP (DB port not exposed to host)
duration completed tasks files_created files_modified
4min 2026-06-24T12:57:00Z 4 8 8

Phase 05 Plan 02: Search + Notes Widgets + Widget Settings Summary

Search widget with provider dropdown and new-tab open via window.open(url, '_blank', 'noopener,noreferrer'), Notes widget with MDEditor + rehype-sanitize + debounced autosave using AbortController, SearchProvider Prisma model with defaults-as-constants CRUD, and Widget Settings panel (Settings > Dashboard) with clock timezone/date toggle, note title editor, and custom search provider management with {query} client-side validation.

Tasks Completed

Task Name Commit Key Files
1 (RED) Failing tests for search + note widgets 97c1380 search-widget.test.tsx, note-widget.test.tsx
1 (GREEN) Search + Notes widgets implementation dd02098 search-widget.tsx, note-widget.tsx, widget-registry.tsx, dashboard-api.ts
2 SearchProvider backend (model + CRUD + defaults) 38dcfdf schema.prisma, dashboard.controller.ts, dashboard.service.ts, create-search-provider.dto.ts
3 Widget settings panel (Settings > Dashboard) 7e2592b page.tsx, widget-settings-panel.tsx, search-provider-form.tsx, en.json, de.json
4 Prisma schema push (no code change) Database SearchProvider table created

Verification Results

  • prisma validate: PASS
  • tsc --noEmit (apps/api): PASS
  • tsc --noEmit (apps/web): PASS
  • vitest run src/components/dashboard: 14/14 PASS (4 test files)
  • prisma db push: "database is already in sync" (second run confirms)

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] useRef missing initial value for React 19 strict mode

  • Found during: Task 3 (tsc --noEmit verification)
  • Issue: useRef<ReturnType<typeof setTimeout>>() without an argument fails in React 19 with strict TypeScript -- Expected 1 arguments, but got 0
  • Fix: Changed to useRef<ReturnType<typeof setTimeout> | undefined>(undefined) for both timerRef and abortRef
  • Files modified: apps/web/src/components/dashboard/widgets/note-widget.tsx
  • Commit: 7e2592b (included in Task 3 commit)

2. [Rule 1 - Bug] unknown type not assignable to ReactNode in JSX

  • Found during: Task 3 (tsc --noEmit verification)
  • Issue: widget.config.title is unknown, and using it in a && JSX chain caused TS2322: Type 'unknown' is not assignable to type 'ReactNode'
  • Fix: Changed to typeof widget.config.title === 'string' && widget.config.title !== '' narrowing
  • Files modified: apps/web/src/components/settings/widget-settings-panel.tsx
  • Commit: 7e2592b (included in Task 3 commit)

3. [Rule 2 - Missing critical] i18n keys for search provider management

  • Found during: Task 3 (search-provider-form.tsx creation)
  • Issue: SearchProviderForm uses t('search.providers'), t('search.addProvider'), t('search.addProviderButton') which did not exist in the translation files
  • Fix: Added 3 new i18n keys to both en.json and de.json
  • Files modified: apps/web/src/messages/en.json, apps/web/src/messages/de.json
  • Commit: 7e2592b (included in Task 3 commit)

Decisions Made

Decision Context Outcome
useRef explicit undefined init React 19 strict TS requires argument Added undefined initial value with union type
typeof narrowing for config.title unknown not assignable to ReactNode in JSX Used typeof string check instead of truthiness
DB push via container IP DB port not exposed to host, docker exec path doesn't have schema Used Docker internal IP 172.22.0.2 with DATABASE_URL from host

Known Stubs

File Line Stub Reason
widget-registry.tsx calendar entry (line 181) PlaceholderWidget for calendar Implemented in plan 05-03

Self-Check: PASSED