feat(frontend): slice 7b — Media on TanStack Table (server pagination)

Web UI rework. Completes the DataGrid migration (7a + 7b):
- pages/Media.tsx off @mui/x-data-grid + @mui/material onto DataTable:
  15 locked columns (title/series/season/episode/type/year/runtime_min/
  size/bitrate/hdr/video/resolution/date_added/library/path);
  enablePagination + manualPagination + rowCount from queryResult.total;
  page state (pageIndex/pageSize) -> offset/limit into useMediaQuery;
  onRowClick -> navigate('/files?path=...') preserved; stable path-derived
  getRowId so selection survives server paging; column-visibility toggle.
  Hard rule honored: NO sorting, NO resizing (visibility-only).
- Migrate Media shell (Select/Input/Progress/Card/grid/Typography/Tabs).
- Media component tests (column set + row-click nav).
- Harness fix: polyfill ResizeObserver in test/setup.ts — jsdom lacks it
  and Radix primitives (Select/ScrollArea/etc.) reference it; was causing
  cross-test failures once Media pulled shadcn Select into the pool.

Gate: build + lint + test green (23 files / 64 tests).
This commit is contained in:
Developer
2026-06-17 18:33:59 +00:00
parent e8b0f1144b
commit 3dc1b31fc3
5 changed files with 852 additions and 317 deletions
+19
View File
@@ -3,3 +3,22 @@
// The `/vitest` entry both registers the matchers at runtime and provides the
// TypeScript module augmentation for vitest's `expect` so tsc typechecks them.
import "@testing-library/jest-dom/vitest";
// jsdom does not implement ResizeObserver, but several Radix primitives that
// shadcn wraps (ScrollArea, Select via react-popper/react-use-size, DropdownMenu,
// Tabs, etc.) reference it at module-load or render time. Without a stub, any
// component test whose render tree pulls one of these in fails with
// `ReferenceError: ResizeObserver is not defined`. Stub a no-op observer so the
// whole suite (and future component tests) is resilient to cross-test module
// loading in the Vitest pool.
class ResizeObserverStub {
observe() {}
unobserve() {}
disconnect() {}
}
globalThis.ResizeObserver = ResizeObserverStub as unknown as typeof ResizeObserver;
// Radix popper also probes `requestAnimationFrame`; jsdom provides it, but some
// primitives defer layout reads through rAF that never flush in jsdom. Keep the
// default rAF; this guard is intentionally minimal.