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

5.5 KiB

Slice 3 — Media table mobile layout (worker output)

Files changed

File Status Lines
frontend/src/pages/Media.tsx modified +190 / -27
frontend/src/pages/__tests__/Media.test.tsx modified +93 / -0

Total: ~256 changed lines (283 insertions, 27 deletions). Under the 400-line budget.

What was implemented

3.1 — Mobile fields + card render

Below md (isMobile === true), the page renders <MobileCardRow> inside the same rounded-lg border bg-card wrapper, followed by a standalone MediaMobilePagination component. Desktop renders the existing <DataTable> unchanged.

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

Field Key Rationale
Title (primary) title Primary identifier — bold card title
Size size Already human-readable ("12.4 GB"); helps identify large files at a glance
HDR hdr Shows HDR format string ("HDR10", "Dolby Vision") or "-" for SDR — key tech quality indicator
Library library Which Jellyfin library the item belongs to — context for multi-library setups
Year year Quick identification; number rendered as string, "-" if null

Runtime, bitrate, resolution, video codec, series/season/episode, date_added, and path are omitted from the mobile card — they're available on desktop and would make the card too tall for phone scanning.

Preserved behaviors:

  • Row click → navigate("/files?path=...") — wired via MobileCardRow onRowClick.
  • Pagination — a new MediaMobilePagination component mirrors the DataTable's internal DataTablePagination (rows count, page-size select, page indicator, prev/next buttons) but works off the raw PaginationState instead of a TanStack table instance.
  • Build index / status controls above the table — unchanged.
  • Column-visibility toggle — automatically hidden (DataTable is not rendered below md).
  • Desktop (md+) — byte-for-byte identical: the isMobile === false branch renders the exact same <DataTable> with the same props.

3.2 — Tests

Added a setMatchMedia(matches) helper to stub window.matchMedia for jsdom (same pattern as Dashboard.test.tsx). Called setMatchMedia(false) in beforeEach so existing desktop tests are unaffected. 5 new tests in a describe("Media (mobile card layout — slice 3)") block:

  1. Cards render with title as primary below md — asserts card titles and field labels render, desktop column headers do NOT.
  2. Column-visibility toggle is hidden below md — asserts no "Columns" button.
  3. Pagination controls render below cards on mobile — asserts "2 rows", page indicator, and prev/next buttons.
  4. Card tap navigates to file browser — clicks "Inception" card, asserts navigate called with the encoded path.
  5. DataTable renders at desktop width — asserts column headers present + "Columns" button present.

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 / 94 tests passed (was 89; +5 new)

Deviations from design

  1. Standalone MediaMobilePagination component instead of reusing DataTable's pagination. The DataTable renders pagination internally (not as a separate export). Extracting a shared pagination component would touch data-table.tsx (out of scope for this slice). The inline MediaMobilePagination mirrors DataTablePagination exactly (same labels, same controls, same aria-labels) so the mobile UX is consistent. A future refactor can extract both into a shared <TablePagination>.

  2. setMatchMedia mock added to existing test file. The existing Media tests didn't mock window.matchMedia because the old usePrefersSmallScreen hook guarded against it (typeof window.matchMedia === "function"). The new useIsMobile hook calls window.matchMedia unconditionally (it's the standardized hook from Slice 1). The mock defaults to desktop (matches: false) so all 6 existing tests pass unchanged.

  3. mediaCardFields is a module-level constant. This mirrors the existing mediaColumns pattern (module-level for TanStack stability). MobileCardRow doesn't require it, but keeping it stable avoids per-render allocation and is consistent with the codebase's existing style.

skill_resolution

none — no project/user SKILL.md paths were injected by the parent, and no .atl/skill-registry.md was found.

Residual risks

  • MediaMobilePagination duplicates DataTablePagination. If the desktop pagination UI changes (labels, aria attributes), the mobile version won't auto-update. A shared component extraction in a later refactor would fix this. Low priority since the pagination UI is stable.
  • jsdom matchMedia is not reactive. The setMatchMedia mock sets the initial matches value but addEventListener is a no-op (no resize events fire). This is adequate for breakpoint-branch tests but cannot test responsive transitions. Same limitation as Dashboard.test.tsx.
  • Row selection (enableRowSelection) is desktop-only on mobile. The mobile card layout has no selection checkboxes (the card itself is the tap target for navigation). This is consistent with the spec (R3.5 says the card picks the fields; R3.3 preserves "row click / selection semantics" but on mobile the primary interaction is navigation, not batch selection). If batch selection is needed on mobile later, the actions slot can hold a checkbox.