Files
manage/openspec/changes/service-registry/apply-progress.md
T
Developer 1da67f38c7 feat(services): frontend services runtime and widget rebind
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.
2026-06-22 18:59:41 +00:00

88 lines
3.9 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.
# Apply Progress: Runtime Service Registry
**Change:** `service-registry`
**Apply run:** PR 1 + PR 2 + PR 3 (Slices 13)
**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
- [x] 3.1 Service + new widget TypeScript types (`ServiceInstance`,
`ServiceInstanceInput`, `ServiceTypeInfo`, `ServiceWidgetKindInfo`,
`SecretFieldInfo`, `BuiltinWidgetKindInfo`; widget gains `service_id` +
`widget_kind`).
- [x] 3.2 Services API + hooks (`api/services.ts`, `hooks/useServices.ts`).
Reconciled `api/widgets.ts` + `hooks/useWidgets.ts` to the new shape
(removed sources/types; added builtin kinds).
- [x] 3.3 Closed frontend service registry (`integrations/registry.ts`)
mirroring the backend; `resolveWidget(widget, services)` maps a widget to
its component + refresh interval.
- [x] 3.4 Service page at `/services/:serviceType/:serviceId` with config view,
empty-on-edit secret inputs + "set" badges, enable toggle, delete, and the
service's widget-kind list.
- [x] 3.5 Route swap: added `/services/:serviceType/:serviceId`; addon route
retained for now (removed in Slice 4 cleanup).
- [x] 3.6 Reconciled widget components to take `refreshIntervalMs` +
`description` props; rewrote `WidgetConfigDialog` around the
service → widget-kind picker (pulled 4.1 forward to keep the build whole).
- [x] 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 six `widgets/*.tsx` components, `widgets/index.ts`.
- Deleted: `widgets/registry.ts`, `widgets/registry.test.ts`.
### Verification (Slice 3)
```bash
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
- `WidgetConfigDialog` was 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_url` env vars, and writes the changelog.
## Remaining work
- Slice 4: remove addon pages + machine app fields, remove
`grafana_url`/`prometheus_url` from config + compose, docs + changelog
(breaking upgrade note).