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).
73 lines
5.5 KiB
Markdown
73 lines
5.5 KiB
Markdown
# 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.
|