Files
manage/.pi-tmp/svc-hub-slice4-out.md
T
Developer a8dfbd5dc6 Cleanup: delete dead top-level pages + update docs (Slice 11)
Delete the old top-level page files whose content was migrated into
service-page tabs in slices 5-9:
- pages/Media.tsx, Applications.tsx (-> MediaTab)
- pages/FileBrowser.tsx, FileBrowser.impl.tsx (-> FilesTab)
- pages/Actions.tsx (-> ActionsTab)
- pages/Users.tsx, UsersPage.impl.tsx (replaced by Authentik tabs)
- components/BackupsPage.tsx (-> JobsTab)
- components/ObservabilityPage.tsx (split into Alerts/Links/Metrics tabs)
- hooks/useUsers.ts (orphaned after Users page deletion)
- the corresponding page test files (Media, FileBrowser, Applications,
  Actions, UsersPage) that tested the deleted pages directly.

The service-tab components are the live implementations; ServicePage
renders them. No live code references the deleted files.

Docs: append an Information Architecture section to REQUIREMENTS.md
documenting the services-as-hub model (nav shape, service-page tabs,
service type registry, Users->Authentik, Observability split, legacy
route 404s, empty state). Add a CHANGELOG entry under [Unreleased].

92 frontend tests pass (was 112; -20 deleted page tests); 271 backend
tests pass; lint/build green.

Refs openspec/changes/services-as-hub-ia/ (tasks slice 11).
2026-06-26 20:11:02 +00:00

8.0 KiB
Raw Blame History

Slice 4 — Frontend: top-nav generation + service-page skeleton (worker output)

Files changed (12 tracked + new)

File Status Lines
frontend/src/integrations/navEntries.ts new 49
frontend/src/integrations/__tests__/navEntries.test.ts new 57
frontend/src/api/dashboards.ts new 42
frontend/src/hooks/useDashboards.ts new 31
frontend/src/pages/service-tabs/stubs.tsx new 57
frontend/src/pages/service-tabs/index.ts new 64
frontend/src/pages/ServiceTypePage.tsx new 48
frontend/src/pages/ServicePage.tsx modified full rewrite to tab skeleton + instance switcher
frontend/src/pages/Dashboard.tsx modified +23 (services empty-state CTA)
frontend/src/App.tsx modified data-driven nav, legacy routes removed, 404 added
frontend/src/pages/__tests__/Dashboard.test.tsx modified +3 (mock useServiceInstances)
frontend/src/pages/__tests__/ServicePage.test.tsx new 97

Total: ~530 changed lines (new files ~445 + modifications). Over the 400-line budget, dominated by the ServicePage refactor (the config/secrets editing was lifted into ConfigBody verbatim — it accounts for ~120 lines) and the 12 new files' boilerplate. The genuine new-logic delta is ~250 lines.

Final nav shape

Empty install (no services, no dashboards):

Dashboard | Services | Settings

Populated install (Jellyfin + SSH + Alertmanager + 2 named dashboards):

Dashboard | Storage | Incident | Media | Files | Actions | Alerts | Services | Settings

Tab skeleton per service type

Type Tabs
jellyfin Overview, Media, Requests, Widgets, Config
ssh_tasks Overview, Files, Actions, Widgets, Config
backups Overview, Jobs, Widgets, Config
authentik Overview, Users, Messaging, Widgets, Config
alertmanager Overview, Alerts, Widgets, Config
grafana Overview, Links, Widgets, Config
prometheus Overview, Metrics, Widgets, Config
nextcloud Overview, Widgets, Config

All content tabs are stubs ("coming soon"). Config + Widgets render the existing config/secrets/widgets UI. Instance switcher (Select) appears when >1 sibling of the same type.

Validation

npm run lint   → 0 errors, 2 pre-existing warnings (UsersPage.impl.tsx exhaustive-deps, untouched)
npm run build  → ✓ built (tsc -b + vite)
npm run test   → 25 files / 83 tests passed

Deviations from design

  1. Over 400-line budget. The ServicePage refactor dominates because the existing config/secrets editing was lifted verbatim into ConfigBody (~120 lines). The genuine new-logic delta is ~250 lines. Could have split the ServicePage refactor into its own slice, but it's structurally required for the tab skeleton.

  2. No mobile SheetForm on ServicePage in this slice. The old ServicePage had a SheetForm-based mobile form (from the mobile-parity change). The refactor uses desktop Tabs for all breakpoints in this slice. The mobile SheetForm will be re-added when content tabs get real content (slices 59), since the mobile form needs to wrap whatever the tabs render.

  3. Dashboard CTA uses a SectionCard rather than a full-page takeover. The existing shortcuts/widgets UI still renders below the CTA so the Dashboard isn't broken for existing users with shortcuts but no services.

  4. NotFoundPage is a simple inline component in App.tsx (not a separate page file). It renders a heading + "Back to dashboard" link.

  5. Legacy /monitoring and /applications redirects removed (they were redirects to now-404 routes). All 6 legacy routes + the 2 redirect aliases are gone.

skill_resolution

none — no project/user SKILL.md paths were injected; no .atl/skill-registry.md found.

Residual risks

  • Old page files still imported by their tests. The Dashboard.test now mocks useServiceInstances, but old page test files (Media.test, FileBrowser.test, Actions.test, UsersPage.test, Settings.test) still import their pages. The pages themselves are still in the repo (unused routes removed, but files remain). They'll be deleted in Slice 11 (cleanup). The tests pass because the files exist.
  • Mobile SheetForm regression on ServicePage. The mobile-parity SheetForm-based form for ServicePage is gone in this refactor. It will be re-added when real content tabs are wired (slices 59).
  • NamedDashboardPage not yet created. The /d/:slug route is not yet wired (named dashboard rendering is Slice 10). Nav entries for dashboards point to /d/:slug which currently 404s. This is expected — the backend endpoint exists, the frontend page doesn't yet.
{
  "criteriaSatisfied": [
    {
      "id": "criterion-1",
      "status": "satisfied",
      "evidence": "Slice 4 implements data-driven nav (useNavItems from useServiceInstances + useDashboards), service-page tab skeleton with instance switcher, legacy route removal (404 catch-all), empty-state CTAs, and stubs for all content tabs. Old page files stay in repo for now (cleanup is Slice 11). 83 tests pass; lint/build green."
    }
  ],
  "changedFiles": [
    "frontend/src/integrations/navEntries.ts",
    "frontend/src/integrations/__tests__/navEntries.test.ts",
    "frontend/src/api/dashboards.ts",
    "frontend/src/hooks/useDashboards.ts",
    "frontend/src/pages/service-tabs/stubs.tsx",
    "frontend/src/pages/service-tabs/index.ts",
    "frontend/src/pages/ServiceTypePage.tsx",
    "frontend/src/pages/ServicePage.tsx",
    "frontend/src/pages/Dashboard.tsx",
    "frontend/src/App.tsx",
    "frontend/src/pages/__tests__/Dashboard.test.tsx",
    "frontend/src/pages/__tests__/ServicePage.test.tsx"
  ],
  "testsAddedOrUpdated": [
    "frontend/src/integrations/__tests__/navEntries.test.ts",
    "frontend/src/pages/__tests__/ServicePage.test.tsx",
    "frontend/src/pages/__tests__/Dashboard.test.tsx"
  ],
  "commandsRun": [
    { "command": "cd frontend && npm run lint", "result": "passed", "summary": "0 errors, 2 pre-existing warnings" },
    { "command": "cd frontend && npm run build", "result": "passed", "summary": "tsc -b + vite clean" },
    { "command": "cd frontend && npm run test", "result": "passed", "summary": "25 files / 83 tests passed" }
  ],
  "validationOutput": [
    "Data-driven nav: useNavItems() builds from useServiceInstances + useDashboards; nav order is Main Dashboard, named dashboards, conditional service-type entries, Services, Settings.",
    "Service page: tab skeleton [Overview, ...content, Widgets, Config]; instance switcher (Select) when siblings > 1; Config tab preserves existing config/secrets editing verbatim.",
    "ServiceTypePage: /services/:type resolves first enabled instance, redirects to /services/:type/:id; empty state when none.",
    "Legacy routes (/media, /files, /actions, /users, /observability, /backups, /monitoring, /applications) removed; 404 catch-all added.",
    "Dashboard: empty-state CTA when no services configured.",
    "All content tabs are stubs (coming soon); real content in slices 5-9."
  ],
  "residualRisks": [
    "Old page files (Media.tsx, FileBrowser.impl.tsx, Actions.tsx, UsersPage.impl.tsx, ObservabilityPage.tsx, BackupsPage.tsx) still in repo with passing tests; deleted in Slice 11.",
    "Mobile SheetForm on ServicePage removed in this refactor; re-added when content tabs get real content.",
    "NamedDashboardPage (/d/:slug) not yet created; nav dashboard entries 404 until Slice 10."
  ],
  "noStagedFiles": true,
  "diffSummary": "Data-driven top nav replacing static navItems; service-page tab skeleton with instance switcher; ServiceTypePage resolver; stub components for all content tabs; legacy routes 404; Dashboard empty-state CTA; navEntries + ServicePage + Dashboard tests. ~530 changed lines across 12 files.",
  "reviewFindings": [
    "no blockers"
  ],
  "manualNotes": "Over 400-line budget due to ServicePage ConfigBody lift (existing config/secrets UI preserved verbatim). Mobile SheetForm on ServicePage will be re-added in content slices. Old page files kept for now (tests still pass); deleted in Slice 11 cleanup."
}