fix(nav): the address keeps what the app rewrites around it (review round 3)

- The Feed press over a live search ends only the search: the feed's own view stays named.
- Leaving a search steps back only off an entry the app pushed (_ytOwn); one a link or a reload
  opened is cleared in place, also where the Navigation API is missing.
- useUrlMirror rewrites a changed view through replaceView, so a reload's overlay marks go; its
  first write and its landing writes keep them for an overlay that reopens.
- Files and Playlists: a box emptied and filled again settles at once, never naming the ended search.
- Playlists: a linked player is scoped to the playlist the store started with, and only the rail's
  own move to the first playlist is no pick.
- Contract: writer objects are scanned to their matching brace, a computed or shorthand key is
  refused, and every useHistorySubview call hands a named definition.
- Lint: playwright/no-skipped-test also refuses fixme (gate snapshot regenerated).
- FEED_DEFAULT_SORT at the three remaining sites; linkedNotListed says to search by name.
This commit is contained in:
2026-10-27 23:33:22 +01:00
parent 66e427dfa4
commit 02906d0acb
18 changed files with 282 additions and 53 deletions
+9 -2
View File
@@ -20,13 +20,14 @@ import {
} from "./features/navigation/navigationContext";
import { ModuleStores } from "./features/navigation/ModuleStores";
import { useChannels } from "./modules/channels/channelsContext";
import { useFiles } from "./modules/files/filesContext";
import { usePlaylists } from "./modules/playlists/playlistsContext";
import { useFiles, useFilesActions } from "./modules/files/filesContext";
import { usePlaylists, usePlaylistsActions } from "./modules/playlists/playlistsContext";
import { usePlex } from "./modules/plex/plexContext";
import { claimLocalData, getAccountRaw, LS, setAccountRaw } from "./lib/storage";
const seen: { current: Record<string, string> } = { current: {} };
const nav: { current: NavigationActions | null } = { current: null };
const typeIn: { current: Record<string, (q: string) => void> } = { current: {} };
function Probe() {
const channels = useChannels();
@@ -34,8 +35,11 @@ function Probe() {
const playlists = usePlaylists();
const plex = usePlex();
const actions = useNavigationActions();
const filesActions = useFilesActions();
const playlistsActions = usePlaylistsActions();
useEffect(() => {
nav.current = actions;
typeIn.current = { files: filesActions.setSearch, playlists: playlistsActions.setSearch };
seen.current = {
channels: channels.search,
files: files.search,
@@ -115,5 +119,8 @@ describe.each([
await waitFor(() => expect(seen.current[page]).toBe(""));
// At once, not after the typing pause: a reload right after the return opens it unsearched.
expect(search().get(key)).toBeNull();
// Typing again within the pause names the new text or nothing, never the ended search.
act(() => typeIn.current[page]!("x"));
expect(search().get(key)).not.toBe(value);
});
});