Skip to content

fix: Keep a deep-linked page on the Library table - #384

Merged
frankieramirez merged 1 commit into
mainfrom
fix/deep-linked-library-page
Jul 28, 2026
Merged

fix: Keep a deep-linked page on the Library table#384
frankieramirez merged 1 commit into
mainfrom
fix/deep-linked-library-page

Conversation

@frankieramirez

@frankieramirez frankieramirez commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Resolves Ship the deep-linked-page pre-fix on SeriesTable on map Wayfinder: One useTableState hook for every table. Mechanism was established on #372; this ships it ahead of the useTableState seam.

The bug

A cold load of /library?page=2 rendered page 0 and stripped page from the URL. Bookmarks and shared links to any page but the first silently lost the page.

Two causes, both live, neither sufficient alone

1. The clamp effect wrote on empty data (SeriesTable.tsx:280). Before rows arrive, pageCount is 0, so maxPage is 0 and any requested page clamps to 0 — the effect then writes page: null. It now returns early while data is empty; once rows are known the clamp is meaningful again.

2. Auto-reset lands one microtask too late. _autoResetPageIndex queues onto a microtask that runs after the render which consumed the row model. By then the render-time clamp has already raised pageIndex to the requested page, so the reset's 0 differs from it, passes onPaginationChange's guard, and writes page: null.

autoResetPageIndex is now armed one render after data first becomes non-empty:

const seenData = useRef(false);
useEffect(() => {
  if (data.length > 0) seenData.current = true;
});
// ...
autoResetPageIndex: seenData.current,

This preserves today's reset-on-data-change, which autoResetPageIndex: false would silently drop. Gating on a ref read during render is sound because table.options.autoResetPageIndex is read synchronously inside _autoResetPageIndex (table-core/features/RowPagination.js:49), not inside the queued microtask.

I verified independently that each half alone leaves the regression test failing — reverting either one reproduces the bug.

Why pre-fix rather than fix during the migration

The autoResetPageIndex line transfers verbatim into useTableState; only the effect guard is throwaway (the effect is deleted outright at migration). And the regression test can only be written against working code, which makes it the concrete parity artifact #365 needs while still blocked.

Behaviour note

An out-of-range ?page=99 renders the last page and the URL is rewritten to ?page=3. #372's no URL tidying describes the post-migration state, where the effect is gone entirely; while the effect survives as the throwaway half, this stays as it is today. Captured as a test so the change is visible when the effect is deleted.

Tests

Three cases in frontend/tests/components/SeriesTable.test.tsx:

  • deep-linked ?page=2 with rows arriving after mount — page 2 renders and page is never stripped from any URL the app commits
  • out-of-range ?page=99 settles onto the last page
  • a later row-set change still resets to page 0

Full frontend suite: 143 passed / 27 files. typecheck, lint:frontend, lint:modern and lint:backend all clean.

Scope

Deliberately excluded, per #372: IssuesTable's stale-key decode and ActivityPage.tsx:590's index-embedded row id. Those stay under the map's Where the two identity fixes ship.

🤖 Generated with Claude Code

https://claude.ai/code/session_019TGrvFNfYXfV5U1aMMZvHb

Summary by CodeRabbit

  • Bug Fixes
    • Fixed Library pagination for deep links, preserving URLs such as /library?page=2 after reload.
    • Out-of-range page numbers now settle on the last available page.
    • When the underlying results change, pagination correctly returns to the first page.

A cold load of /library?page=2 rendered page 0 and stripped `page` from
the URL. Two independent causes, both live, and guarding either alone
leaves the bug standing:

- The page-clamp effect ran while `data` was still empty, where
  `pageCount` is 0 and says nothing about whether the requested page
  exists. It now returns early until rows arrive.
- TanStack's `_autoResetPageIndex` queues onto a microtask that runs
  after the render which consumed the row model — by then the
  render-time clamp has already raised `pageIndex` to the requested
  page, so the reset's 0 differs from it, passes the pagination
  handler's guard, and writes `page: null`. `autoResetPageIndex` is now
  armed one render after `data` first becomes non-empty, which keeps
  today's reset-on-data-change while letting the initial arrival
  through. Gating on a ref read during render works because the option
  is read synchronously in `_autoResetPageIndex`, not inside the
  microtask.

Adds a deep-link regression test plus coverage for the two behaviours
that must survive: an out-of-range `?page=99` settles onto the last
page, and a later row-set change still resets to page 0.

Wayfinder #381 (map #353); mechanism established on #372.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019TGrvFNfYXfV5U1aMMZvHb
@changeset-bot

changeset-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1557dc0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
comicarr Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f55c2491-d5ea-4e4b-9532-87c79d3b1637

📥 Commits

Reviewing files that changed from the base of the PR and between f7359ea and 1557dc0.

📒 Files selected for processing (3)
  • .changeset/keep-deep-linked-library-page.md
  • frontend/src/components/series/SeriesTable.tsx
  • frontend/tests/components/SeriesTable.test.tsx

📝 Walkthrough

Walkthrough

Changes

Library pagination

Layer / File(s) Summary
Pagination lifecycle handling
.changeset/keep-deep-linked-library-page.md, frontend/src/components/series/SeriesTable.tsx
SeriesTable delays automatic page resets until data arrives and skips clamping while the row set is empty, preserving deep-linked pages during initial loading.
Pagination regression coverage
frontend/tests/components/SeriesTable.test.tsx
Tests verify deep-link preservation, out-of-range clamping, and resetting to the first page after the row set changes.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant SeriesTable
  participant TanStackTable
  Browser->>SeriesTable: Load deep-linked page parameter
  SeriesTable->>TanStackTable: Render with empty data without resetting page
  SeriesTable->>TanStackTable: Apply pagination after data arrives
  TanStackTable->>Browser: Preserve or clamp the page URL
  Browser->>SeriesTable: Update the underlying row set
  SeriesTable->>Browser: Reset the page query parameter
Loading

Possibly related issues

Possibly related PRs

Poem

A rabbit hopped to page two,
The rows arrived—its place stayed true.
Too far? The last page marks the end,
New rows? Back to one again.
No query lost along the way—
Hop, hop, ship the patch today!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: preserving a deep-linked Library table page.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/deep-linked-library-page

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ship the deep-linked-page pre-fix on SeriesTable

1 participant