Description
On /repositories, clicking "next page" or "last page" in the repositories table advances for one render and then snaps back to page 1. Direct loads of /repositories?page=N strip ?page on first paint and render page 1 instead. The bug only affects /repositories; other tables using the same search input do not snap back.
Steps to Reproduce
- Open
/repositories (default list view, 10 rows). The current registry has >10 entries so page 2 exists.
- Click the "next page" or "last page" button.
- Observe the URL briefly become
?page=1, then revert to bare. The table re-renders page 1.
Also reproducible by loading /repositories?page=1 directly.
Expected Behavior
Page advances and the URL retains ?page=N until another navigation action.
Actual Behavior
?page= is removed from the URL within one render tick and the table returns to page 1.
Root Cause
src/components/common/DebouncedSearchInput.tsx:67-69 runs the effect on onDebouncedChange identity changes, not only on debounced value changes. In TopRepositoriesTable, onDebouncedChange routes through useDataTableParams.setFilter, whose useCallback depends on react-router-dom's setSearchParams — a ref that changes on every URL update. So every setPage triggers setFilter('search', ''), which deletes ?page (its resetPageOnChange default is true).
Suggested Fix
Stabilize the callback in a ref and skip the initial-mount fire so direct ?page=N loads aren't stripped:
const callbackRef = useRef(onDebouncedChange);
useEffect(() => {
callbackRef.current = onDebouncedChange;
});
const didFireInitialRef = useRef(false);
useEffect(() => {
if (!didFireInitialRef.current) {
didFireInitialRef.current = true;
return;
}
callbackRef.current(debounced);
}, [debounced]);
Description
On
/repositories, clicking "next page" or "last page" in the repositories table advances for one render and then snaps back to page 1. Direct loads of/repositories?page=Nstrip?pageon first paint and render page 1 instead. The bug only affects/repositories; other tables using the same search input do not snap back.Steps to Reproduce
/repositories(default list view, 10 rows). The current registry has >10 entries so page 2 exists.?page=1, then revert to bare. The table re-renders page 1.Also reproducible by loading
/repositories?page=1directly.Expected Behavior
Page advances and the URL retains
?page=Nuntil another navigation action.Actual Behavior
?page=is removed from the URL within one render tick and the table returns to page 1.Root Cause
src/components/common/DebouncedSearchInput.tsx:67-69runs the effect ononDebouncedChangeidentity changes, not only ondebouncedvalue changes. InTopRepositoriesTable,onDebouncedChangeroutes throughuseDataTableParams.setFilter, whoseuseCallbackdepends onreact-router-dom'ssetSearchParams— a ref that changes on every URL update. So everysetPagetriggerssetFilter('search', ''), which deletes?page(itsresetPageOnChangedefault istrue).Suggested Fix
Stabilize the callback in a ref and skip the initial-mount fire so direct
?page=Nloads aren't stripped: