refactor(miner-ui): extract shared client-side table pagination hook and pager - #8492
Conversation
…SONbored#8306) The client-side table pagination logic was independently duplicated three ways across five miner-ui routes: run-history and ranked-candidates inlined the page-state computation plus the full Pagination JSX, ledgers and portfolio each defined their own local TablePagination and repeated the page-state twice per file, and attempts had already generalized it into a local usePagedRows hook. Extract attempts.tsx's usePagedRows shape into a shared lib/paged-rows.ts module and a shared components/table-pagination.tsx built on the existing @loopover/ui-kit pagination primitives, then convert all five routes to consume them. Behavior is preserved exactly (PAGE_SIZE = 20 default, page clamping via Math.min(page, pageCount - 1), aria-disabled on the boundary controls). Adds dedicated unit tests for the hook (empty, single-page, multi-page, and page-clamping when rows shrink) and the pager component.
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
|
Tip ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-24 15:40:07 UTC
Review summary Nits — 4 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. Visual previewClick any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy. Scroll preview
A short scroll-through clip (desktop) — click either thumbnail to open the full animation. Evidence for scroll-linked behavior a single screenshot can't show. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|




What
Client-side table pagination in
apps/loopover-miner-uiwas independently duplicated three different ways across five routes. This PR extracts a single shared hook + pager component and converts all five call sites to consume it, so the logic lives in exactly one place.The three prior shapes:
run-history.tsxandranked-candidates.tsxeach inlined the 5-linepage/pageCount/isPaginated/safePage/visiblecomputation and hand-rolled the fullPagination/PaginationContent/… JSX directly in the component.ledgers.tsxandportfolio.tsxeach defined their own localTablePaginationcomponent (byte-identical between the two files) and repeated the page-state computation twice per file (once per table).attempts.tsxhad already generalized the page-state into a localusePagedRows<T>hook plus a localTablePagination— the closest-to-canonical shape — but it stayed private to that one route.Change
attempts.tsx'susePagedRowsshape into a sharedsrc/lib/paged-rows.tsmodule, generalized tousePagedRows<T>(rows: T[], pageSize?: number)with the existingPAGE_SIZE = 20as the default. The returnedpageis clamped viaMath.min(page, pageCount - 1), so it stays valid whenrowsshrinks below the current page's start index.src/components/table-pagination.tsx, built on the existing@loopover/ui-kitpagination primitives (the primitive itself is left unchanged, per the separatearia-disabledstyling issue).attempts,run-history,ranked-candidates,ledgers,portfolio) to import and use the shared hook + component, removing every local/inline duplicate. Net: +233 / −344 lines across 9 files.This is a pure refactor — behavior is preserved exactly:
PAGE_SIZE = 20, page clamping,aria-disabledon the boundary Previous/Next controls, and "paginate only past the first page" all unchanged. The five routes' existing integration-style tests continue to pass against the shared implementation.Tests
Adds dedicated unit tests for the extracted code so it carries direct coverage rather than relying solely on the routes' integration tests:
src/lib/paged-rows.test.ts— empty rows, rows within a single page (the exclusive> pageSizeboundary), rows spanning multiple pages withsetPage, page-clamping whenrowsshrink below the current page, and thePAGE_SIZEdefault.src/components/table-pagination.test.tsx— numbered/Previous/Next rendering,aria-disabledat both boundaries, and the low/high clamping arms of every click handler.Every added line in all nine changed files has 0 uncovered statements and 0 uncovered branches under
vitest --coverage(v8), keepingapps/loopover-miner-ui's local coverage floor intact.Closes #8306