Introduce a closed, compile-time widget registry and backend CRUD for dashboard widget instances. - Add dashboard_widgets SQLite table in SettingsStore with CRUD helpers and default seeding (Jellyfin + Backups) on first install. - Add Pydantic models with credential-key and secret-value rejection. - Add widgets router: /api/widgets/sources, /types, /instances CRUD. - Call ensure_defaults() in app lifespan so fresh installs seed defaults. - Add backend tests covering registry, CRUD, validation, and seeding. - Include SDD artifacts: exploration, proposal, spec, design, tasks.
3.1 KiB
Apply Progress: Configurable Dashboard Widgets
Change: configurable-dashboard-widgets
Apply run: PR 1 / Slice 1 — Backend CRUD and default seeding
Date: 2026-06-19
Completed tasks (Slice 1)
All Slice 1 tasks are marked - [x] in tasks.md:
- 1.1 Create widget Pydantic models
- 1.2 Create backend widget registry
- 1.3 Implement widgets router (CRUD + metadata)
- 1.4 Extend
SettingsStorefordashboard_widgets - 1.5 Register widgets router in
main.py - 1.6 Add backend tests for registry, CRUD, and seeding
- 1.7 Verify backend slice
Files changed
New files
backend/src/media_library_viewer_api/models/widgets.py— Pydantic models:WidgetInstance,WidgetInstanceInput,WidgetTypeInfo,WidgetDataResponse, plus credential-key/secret-value validators.backend/src/media_library_viewer_api/widgets/__init__.py— Package marker.backend/src/media_library_viewer_api/widgets/registry.py— ClosedWIDGET_REGISTRYfor six Phase 1 widget types, source-type listing, type metadata, and lightweight config-schema validation.backend/src/media_library_viewer_api/routers/widgets.py— REST endpoints for/api/widgets/sources,/types,/instances, and instance CRUD.backend/tests/test_widgets.py— 12 tests covering registry, CRUD, validation, and seeding.
Modified files
backend/src/media_library_viewer_api/services/settings_store.py— Addeddashboard_widgetstable, index, CRUD helpers, default seeding, and refactoredensure_defaults()to seed widgets independently of machine seeding.backend/src/media_library_viewer_api/main.py— Registeredwidgets_router.
Verification
Commands run:
cd backend
.venv/bin/python -m ruff check . # All checks passed
PYTHONPATH=src .venv/bin/python -m pytest # 185 passed, 2 warnings
cd ../frontend
npm run lint # 2 pre-existing warnings, 0 errors
npm run build # Built successfully
Focused widget test output: 12 passed.
Deviations from design
- None significant for Slice 1. The implementation follows the design's backend CRUD layout.
- Used
HTTP_422_UNPROCESSABLE_CONTENTinstead of the deprecatedHTTP_422_UNPROCESSABLE_ENTITY.
Remaining work
- Slice 2: Backend source adapters +
GET /api/widgets/instances/{id}/data - Slice 3: Frontend types/API/hooks/registry/components
- Slice 4: Dashboard loop + configuration UI + addon pages
PR boundary
This slice is PR 1 of 4 in the approved stacked-to-main chain. It is backend-only and leaves the frontend build/lint green.
Actual changed-line count: ~780 added lines across production code and tests (new files: ~597 lines; modified files: ~181 insertions). This is above the nominal ~400-line review budget, but Slice 1 is the smallest coherent backend unit: removing the CRUD router, store helpers, or tests would leave the slice non-functional or unverifiable. If the reviewer prefers a smaller blast radius, the store helpers (~90 lines) could be split into a preceding PR, though that PR would not be independently user-visible.