Files
manage/.pi-tmp/slice4-worker-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

4.9 KiB

Slice 4 — FileBrowser table mobile layout (worker output)

Files changed

File Status Lines
frontend/src/pages/FileBrowser.impl.tsx modified +40 / -2
frontend/src/pages/__tests__/FileBrowser.test.tsx modified +78 / -2

Total: ~114 changed lines (118 insertions, 4 deletions). Well under the 400-line budget.

What was implemented

4.1 — Mobile fields + card render

Below md (isMobile === true), the file table renders as <MobileCardRow> cards inside the existing <div className="rounded-lg border bg-card"> wrapper (with p-4 padding, matching the Media pattern). Desktop renders the existing <DataTable> byte-for-byte identical.

Mobile card field list (module-level fileCardFields constant):

Field Key Rationale
Name (primary) name Primary identifier — file or directory name
Type type "dir" / "file" / "up" — distinguishes the row kind at a glance
Size size Already human-readable via formatSize; "-" for dirs
Modified modified Already formatted via formatTime; "-" when empty

4 fields total (1 primary + 3). The ext column was omitted because the extension is already visible in the filename itself — redundant on mobile.

Preserved behaviors:

  • Whole-card tap = handleRowClick(row) — the same handler the desktop DataTable uses. Dir/up rows navigate into the directory; file rows select the file for ffprobe preview.
  • Directory navigation works on mobile — tapping a folder card navigates into it (status caption updates to show the new cwd).
  • Path bar / breadcrumbs (Remote path input + Open/Refresh buttons) render outside the table in the SectionCard, so they are unaffected by the isMobile branch. The existing flex flex-col gap-2 md:flex-row already stacks them on mobile.
  • ffprobe and Jobs sections live outside the table and are unchanged.
  • No pagination — FileBrowser does not paginate (the task confirmed this).
  • Desktop (md+) — byte-for-byte identical: the isMobile === false branch renders the exact same <DataTable> with the same props.

4.2 — Tests

Added a setMatchMedia(matches) helper (mirrors the Media.test.tsx pattern) and called setMatchMedia(false) in beforeEach so the 3 existing desktop tests pass unchanged. Added 4 new tests in a describe("FileBrowser (mobile card layout — slice 4)") block:

  1. Cards render with file/dir name as primary below md — asserts card titles render ("movies", "video.mkv", "notes.txt") and no table column headers leak.
  2. Tapping a directory card navigates into it — clicks "movies", asserts status shows "Current: /movies" with no "Selected:" segment.
  3. Path/breadcrumb controls still render on mobile — asserts "Remote path" input, Open and Refresh buttons are present.
  4. DataTable renders at desktop width — asserts column headers (Type/Name/Ext/Size/Modified) present at desktop width.

Validation

npm run lint   → 0 errors, 2 pre-existing warnings (UsersPage.impl.tsx, unrelated)
npm run build  → ✓ built (tsc -b + vite)
npm run test   → 25 files / 98 tests passed (was 94; +4 new)

Deviations from design

  1. ext field omitted from mobile card. The task said "Fields (3-5): size, modified time, and type/extension (file vs directory)." I interpreted "type/extension" as a single concept (dir vs file vs up) and used the type field to cover it. The ext column is redundant because the filename already contains the extension (e.g. "video.mkv"). Including it would waste card space. This is a per-table field choice, which the design explicitly delegates to the consuming page (§trade-offs).

  2. No deviations from the established Media.tsx pattern. Module-level MobileCardField<DisplayRow>[] constant, isMobile from useIsMobile(), getRowId wired to row.id, onRowClick wired to the existing handleRowClick. Same p-4 wrapper inside the bordered container.

skill_resolution

none — no project/user SKILL.md paths were injected by the parent, and no .atl/skill-registry.md was found. The task was self-contained against the OpenSpec design/tasks docs and the Media.tsx reference pattern.

Residual risks

  • enableRowSelection on mobile. The mobile card has no selection checkbox — the whole card is the tap target for navigation/selection via handleRowClick. This matches R3.3's "tap target = the whole card where applicable" and the FileBrowser's existing behavior where clicking a file row selects it. The checkbox-based selection is desktop-only, consistent with the Media slice.
  • The ".." (up) row renders as a card with name "..", type "up", size "-", modified "-". This is the universal convention for "go to parent directory" and is tappable. Functionally correct.

Review findings

No blockers identified during self-review. All validation commands green. No staged files.