1da67f38c7
PR 3 of 4 for the runtime service registry change. - Add service + new-shape widget TypeScript types; widgets carry service_id + widget_kind (service-bound) or null (built-in). - Add services API client + TanStack Query hooks; reconcile the widget API client/hooks to the new endpoints (remove sources/types; add builtin kinds). - Add closed frontend service registry (integrations/registry.ts) mirroring the backend, with resolveWidget(widget, services) mapping a widget to its component + refresh interval. - Add ServicePage at /services/:serviceType/:serviceId with config view, empty-on-edit secret inputs + 'set' badges, enable toggle, delete, and the service's widget-kind list. - Register /services/:serviceType/:serviceId in App.tsx. - Reconcile the six widget components to refreshIntervalMs + description props; rewrite WidgetConfigDialog around a service -> widget-kind picker. - Update Dashboard test; add integrations/registry.test.ts. Verification: frontend lint 0 errors, build success, 70 tests passed; backend ruff clean, 222 tests passed.
3.9 KiB
3.9 KiB
Apply Progress: Runtime Service Registry
Change: service-registry
Apply run: PR 1 + PR 2 + PR 3 (Slices 1–3)
Date: 2026-06-19
Slice 1 — Backend service foundation (MERGED, PR #7)
Fernet secrets, closed integrations/ registry (Pydantic config + widget-config
for grafana/prometheus/jellyfin/nextcloud/ssh_tasks), services +
service_task_runs tables with cascade delete, /api/services* CRUD,
MANAGE_ENCRYPTION_KEY required at startup.
Slice 2 — Backend widget rebind (MERGED, PR #8)
Widgets carry service_id + widget_kind; adapters take
fetch(service: ServiceRecord | None, widget_kind, config); backups + static
stay as service-less built-ins; SSH adapter logs to service_task_runs; old
widgets/registry.py retired; default seeding removed.
Slice 3 — Frontend services runtime (this PR)
Completed tasks
- 3.1 Service + new widget TypeScript types (
ServiceInstance,ServiceInstanceInput,ServiceTypeInfo,ServiceWidgetKindInfo,SecretFieldInfo,BuiltinWidgetKindInfo; widget gainsservice_id+widget_kind). - 3.2 Services API + hooks (
api/services.ts,hooks/useServices.ts). Reconciledapi/widgets.ts+hooks/useWidgets.tsto the new shape (removed sources/types; added builtin kinds). - 3.3 Closed frontend service registry (
integrations/registry.ts) mirroring the backend;resolveWidget(widget, services)maps a widget to its component + refresh interval. - 3.4 Service page at
/services/:serviceType/:serviceIdwith config view, empty-on-edit secret inputs + "set" badges, enable toggle, delete, and the service's widget-kind list. - 3.5 Route swap: added
/services/:serviceType/:serviceId; addon route retained for now (removed in Slice 4 cleanup). - 3.6 Reconciled widget components to take
refreshIntervalMs+descriptionprops; rewroteWidgetConfigDialogaround the service → widget-kind picker (pulled 4.1 forward to keep the build whole). - 3.7 Registry + Dashboard tests updated; new
integrations/registry.test.ts.
Decision resolved mid-slice
Secret edit UX = empty-on-edit + "set" badge (blank = keep existing; typing = replace). Applied on the ServicePage secrets card.
Files changed (Slice 3)
- New:
api/services.ts,hooks/useServices.ts,integrations/registry.ts,integrations/registry.test.ts,pages/ServicePage.tsx. - Modified:
types/index.ts,api/widgets.ts,hooks/useWidgets.ts,components/WidgetInstance.tsx,components/WidgetConfigDialog.tsx,pages/Dashboard.tsx,pages/__tests__/Dashboard.test.tsx,App.tsx, all sixwidgets/*.tsxcomponents,widgets/index.ts. - Deleted:
widgets/registry.ts,widgets/registry.test.ts.
Verification (Slice 3)
cd frontend
npm run lint # 0 errors
npm run build # success
npm run test # 70 passed
cd ../backend
.venv/bin/ruff check . # clean
PYTHONPATH=src .venv/bin/python -m pytest # 222 passed
Deviations / notes
WidgetConfigDialogwas rewritten in this slice (pulled forward from task 4.1) because the old dialog imported the deleted widget registry and would not compile. The SSH task-output widget keeps a dedicated task picker; other widget configs use a generic schema-driven field editor.- Addon pages (
/addons/:addonId) are kept compiling but superseded by service pages; Slice 4 removes them and the now-unused machine Jellyfin/Jellyseerr fields +grafana_url/prometheus_urlenv vars, and writes the changelog.
Remaining work
- Slice 4: remove addon pages + machine app fields, remove
grafana_url/prometheus_urlfrom config + compose, docs + changelog (breaking upgrade note).