fix(ui): review round 2 — reveal floor, failed next page, count states, row Play

- DataTable: the reveal floor holds only in the view it was made for (Channels
  never clears its follow, so every later sort mounted rows up to it)
- Feed + Plex browse: a failed next page stops the read-ahead and shows a row
  that retries, instead of re-requesting it once a round-trip
- the YouTube Load more click uses nextPageOnClick; a contract pins NEXT_PAGE
  to the read-aheads and the click sites to nextPageOnClick
- ItemCount: a failed count says so; a stale one says updating to a screen reader
- the narrow-picture Play lift applies only where a hover row is there to clear
- PlayerModal: one description ladder for the popover and the panel, both tested
- plexImage contract reads every img src, any attribute order
- Tabs comment names who persists the sub-tab
This commit is contained in:
2026-10-03 02:25:15 +02:00
parent c4c442bc5b
commit b40440b825
17 changed files with 360 additions and 63 deletions
@@ -29,4 +29,34 @@ describe("an infinite list's read-ahead", () => {
it("the feed hands the grid the query's isFetching", () => {
expect(source("Feed.tsx")).toMatch(/isFetching=\{query\.isFetching\}/);
});
// Retry is off, so a failed page settles at once; a read-ahead that re-runs on the settle would
// request it again once a round-trip while the end is in view (E31 review 2).
it("stands down at a failed next page", () => {
expect(source("Feed.tsx")).toMatch(
/hasNextPage=\{!!hasNextPage && !query\.isFetchNextPageError\}/,
);
expect(source("PlexBrowse.tsx")).toMatch(
/const hasNextPage = browseQ\.hasNextPage && !isFetchNextPageError;/,
);
});
});
// A click joins an in-flight next page but cancels a background refetch (nextPageOnClick): through
// NEXT_PAGE it would join the refetch and load nothing. NEXT_PAGE is only for the read-aheads, so a
// click site that goes back to it fails here (E31 review 2: the YouTube "Load more" was missed).
describe("a click that loads the next page", () => {
const READ_AHEADS = new Set(["ui/VirtualGrid.tsx", "PlexBrowse.tsx"]);
it("uses nextPageOnClick; NEXT_PAGE only in the read-aheads", () => {
const users = Object.entries(files)
.filter(([, src]) => /fetchNextPage\(NEXT_PAGE\)/.test(src as string))
.map(([path]) => path.replace("../components/", ""));
expect(users.sort()).toEqual([...READ_AHEADS].sort());
for (const [file, sites] of [
["AdminLogs.tsx", 2],
["Feed.tsx", 2],
["PlexBrowse.tsx", 1],
] as const)
expect(source(file).match(/fetchNextPage\(nextPageOnClick\(/g)?.length, file).toBe(sites);
});
});