fix(sort): address R13 S1 review findings

- PlexSidebar activeCount now compares the HEALED sort, so an out-of-scope key
  (movie "duration" after switching to shows) no longer inflates the
  active-filter badge while the control + grid show the default.
- PlexProvider strips the legacy `sortDir` from the filters blob, so it stops
  leaking into the facets query key and being re-persisted on every change.
- PlexProvider sort migration guards the fall-through: valid JSON that isn't a
  SortState now falls back instead of using the raw JSON string as the key.
- New shared healPlexSort(sort, scope) is the single heal both PlexBrowse and
  PlexSidebar use (removes the noop-label plexSortOptions call + the duplication).
- Tests: useSortState.dom.test.ts (hydrate/persist/heal round-trip via renderHook)
  and SortControl.dom.test.tsx (options, pick, direction toggle, directionless,
  trailing). vitest 94 -> 105.

Gate green: tsc/eslint(0 err)/prettier/knip clean, vitest 105.
This commit is contained in:
2026-08-14 00:00:31 +02:00
parent 45bd588af7
commit 02c8c71c53
6 changed files with 164 additions and 15 deletions
+2 -7
View File
@@ -9,8 +9,7 @@ import {
type ReactNode,
} from "react";
import { qk } from "../lib/queryKeys";
import { healSort } from "../lib/columnSort";
import { plexSortOptions, PLEX_SORT_FALLBACK } from "../lib/plexSort";
import { healPlexSort } from "../lib/plexSort";
import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next";
import {
@@ -94,11 +93,7 @@ export default function PlexBrowse() {
const dq = useDebounced(q.trim(), 350);
// The provider holds sort scope-agnostically; heal it against THIS scope's options so a movie-only
// key (e.g. duration) left over from before a switch to shows doesn't ask for an unavailable sort.
const sortState = healSort(
sort,
plexSortOptions(scope, () => ""),
PLEX_SORT_FALLBACK,
);
const sortState = healPlexSort(sort, scope);
const sub = useHistorySubview<Sub>({ kind: "grid" });
// Sidebar asked to open a playlist → push it as a subview (browser Back returns to the grid), then