a8dfbd5dc6
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).
134 lines
8.0 KiB
Markdown
134 lines
8.0 KiB
Markdown
# 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 5–9), 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 5–9).
|
||
- **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.
|
||
|
||
```acceptance-report
|
||
{
|
||
"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."
|
||
}
|