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

73 lines
4.9 KiB
Markdown

# 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.