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).
7.9 KiB
Slice 6 — ssh_tasks content tabs: Files + Actions (worker output)
Files changed
| File | Status | Lines |
|---|---|---|
frontend/src/pages/service-tabs/FilesTab.tsx |
new | 528 |
frontend/src/pages/service-tabs/ActionsTab.tsx |
new | 308 |
frontend/src/pages/service-tabs/__tests__/FilesTab.test.tsx |
new | 63 |
frontend/src/pages/service-tabs/__tests__/ActionsTab.test.tsx |
new | 49 |
frontend/src/pages/service-tabs/index.ts |
modified | +4/-4 (import real FilesTab/ActionsTab) |
frontend/src/pages/service-tabs/stubs.tsx |
modified | -8 (removed FilesTab/ActionsTab stubs) |
frontend/src/pages/service-tabs/MediaTab.tsx |
modified | +10/-1 (row-click nav fix) |
frontend/src/pages/service-tabs/__tests__/MediaTab.test.tsx |
modified | +4 (mock useServiceInstances) |
Total: ~967 lines (948 new + 27 modified diff). Over the 400-line budget; dominated by the verbatim lift of the FileBrowser content (~528 lines) and Actions content (~308 lines). The genuine new-logic delta is ~30 lines (instance wiring + row-click fix + tests).
How instance.id is wired into hooks
FilesTab: instance.id replaces the old machine_id from search params. All hooks (useDirectoryListing, useFfprobe, useRunJob) receive instance.id directly as the machineId parameter. The machine-tab selector (TabbedCard + useMonitoringSettings), the machine_id search-param logic, and the "no file machines" fallback are all removed. The initial path is read from ?path= search param for deep-link support.
ActionsTab: instance.id is used as the fixed runServiceId — the old useServiceInstances("ssh_tasks") call and the service selector dropdown are removed. Tasks run on this instance by default. The task editor dialog no longer has a "Default SSH task service" dropdown (the instance is implicit). The services prop on TaskEditor/TaskDialog is removed entirely since the instance is fixed.
MediaTab row-click resolution (cross-slice fix from slice 5)
The old row-click navigated to /files?path=... (legacy route, now 404s). Fixed:
const { data: sshServices = [] } = useServiceInstances("ssh_tasks");
const handleRowClick = (row: MediaItem) => {
const sshInstance = sshServices.find((s) => s.enabled);
const base = sshInstance
? `/services/ssh_tasks/${sshInstance.id}`
: "/services/ssh_tasks";
navigate(`${base}?path=${encodeURIComponent(row.path)}`);
};
If an enabled ssh_tasks instance exists, the link opens its service page with the path query param (FilesTab reads ?path=). If none exists, the link goes to /services/ssh_tasks (ServiceTypePage empty state / resolver).
Validation
npm run lint → 0 errors, 2 pre-existing warnings (UsersPage.impl.tsx, unrelated)
npm run build → ✓ built (tsc -b + vite)
npm run test → 29 files / 94 tests passed (was 90; +4 new)
Deviations from design
-
Over 400-line budget. The FilesTab lift is ~528 lines because it includes all the ffprobe rendering helpers + component logic verbatim from FileBrowser.impl.tsx. ActionsTab is ~308 lines. Could not shrink without dropping features. The task explicitly acknowledged this: "FileBrowser.impl.tsx is large; the lift is mostly mechanical."
-
ActionsTab simplified: no service-selector dropdown. The old Actions page had a "Default SSH task service" dropdown in both the editor and the run pane, using
useServiceInstances("ssh_tasks"). Since the tab is already on a specific instance, the run service is alwaysinstance.id. The dropdown and theservicesprop on TaskEditor/TaskDialog are removed. TheNONEsentinel constant is also removed. -
No mobile layout. This branch is based on main, NOT on mobile-responsive-parity. FilesTab lifts main's DataTable + column-visibility pattern (no MobileCardRow).
-
Old page files kept. FileBrowser.impl.tsx and Actions.tsx stay in the repo (cleanup is Slice 11). Their test files still pass since they render the page components directly.
skill_resolution
none — no project/user SKILL.md paths were injected; no .atl/skill-registry.md found.
Residual risks
- FilesTab and ActionsTab duplicate code from their old top-level pages. The duplicates are temporary (Slice 11 deletes the old pages).
- ActionsTab removed the service-selector dropdown. If users need to run a task on a DIFFERENT ssh_tasks instance (not the current one), they'd need to switch instances via the service page's instance switcher. This is consistent with the new IA (each instance has its own page).
- MediaTab now depends on
useServiceInstances("ssh_tasks"). This adds a TanStack Query call but it's cache-shared with other ssh_tasks queries.
{
"criteriaSatisfied": [
{
"id": "criterion-1",
"status": "satisfied",
"evidence": "Slice 6 implements FilesTab (lift from FileBrowser.impl.tsx, instance-scoped hooks, ?path= deep-link), ActionsTab (lift from Actions.tsx, instance as default run service), resolves the MediaTab row-click cross-slice dependency (navigate to /services/ssh_tasks/<id>?path=...), and adds tests for both tabs. No scope widening: only service-tab files + MediaTab row-click + test mock touched. Old page files preserved for Slice 11. 94 tests pass; lint/build green."
}
],
"changedFiles": [
"frontend/src/pages/service-tabs/FilesTab.tsx",
"frontend/src/pages/service-tabs/ActionsTab.tsx",
"frontend/src/pages/service-tabs/__tests__/FilesTab.test.tsx",
"frontend/src/pages/service-tabs/__tests__/ActionsTab.test.tsx",
"frontend/src/pages/service-tabs/index.ts",
"frontend/src/pages/service-tabs/stubs.tsx",
"frontend/src/pages/service-tabs/MediaTab.tsx",
"frontend/src/pages/service-tabs/__tests__/MediaTab.test.tsx"
],
"testsAddedOrUpdated": [
"frontend/src/pages/service-tabs/__tests__/FilesTab.test.tsx",
"frontend/src/pages/service-tabs/__tests__/ActionsTab.test.tsx",
"frontend/src/pages/service-tabs/__tests__/MediaTab.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 build clean" },
{ "command": "cd frontend && npm run test", "result": "passed", "summary": "29 files / 94 tests passed (was 90; +4 new)" }
],
"validationOutput": [
"FilesTab: instance.id wired into useDirectoryListing/useFfprobe/useRunJob; ?path= read from useSearchParams; machine selector removed.",
"ActionsTab: instance.id used as fixed runServiceId; service-selector dropdown removed; TaskEditor/TaskDialog simplified.",
"MediaTab row-click: navigates to /services/ssh_tasks/<first-enabled-id>?path=... (resolves slice 5 cross-slice flag).",
"stubs.tsx: FilesTab/ActionsTab stubs removed; index.ts imports real components.",
"MediaTab.test.tsx: useServiceInstances mock added to fix QueryClient error."
],
"residualRisks": [
"FilesTab/ActionsTab duplicate code from old pages (temporary; Slice 11 deletes old files).",
"ActionsTab no longer has a service-selector dropdown (run is always on current instance; switch via instance switcher).",
"No mobile layout (branch is on main, not mobile-responsive-parity)."
],
"noStagedFiles": true,
"diffSummary": "~967 lines: FilesTab.tsx (528, verbatim lift from FileBrowser.impl.tsx with instance wiring + ?path= deep-link), ActionsTab.tsx (308, lift from Actions.tsx with instance as fixed run service), 4 test files (112 lines), index.ts/stubs.tsx wiring (12 lines), MediaTab.tsx row-click fix (10 lines). Over 400-line budget due to mechanical lift of two large pages.",
"reviewFindings": [
"no blockers"
],
"manualNotes": "git status confirms nothing is staged; all changes are unstaged/untracked. The old FileBrowser.impl.tsx and Actions.tsx are kept (Slice 11 deletes them). Their existing tests still pass."
}