Conversation
📝 WalkthroughWalkthroughThis PR implements cursor-based pagination for the transactions list endpoint, replacing offset-based pagination. Changes include backend handler updates with new cursor parameters ( Changes
Sequence DiagramsequenceDiagram
actor User
participant TransactionsPage as TransactionsPage
participant GetTransactions as getTransactions()
participant BackendAPI as Backend API
participant Database as Database
User->>TransactionsPage: Click Next/Prev/First/Last
activate TransactionsPage
TransactionsPage->>TransactionsPage: Update cursor state<br/>(block_number, block_index)
TransactionsPage->>GetTransactions: Call with cursor params<br/>(after_block, after_index, etc.)
deactivate TransactionsPage
activate GetTransactions
GetTransactions->>BackendAPI: POST /transactions<br/>with cursor parameters
deactivate GetTransactions
activate BackendAPI
alt after_block & after_index provided
BackendAPI->>Database: SELECT * WHERE<br/>(block_number, block_index) > (?, ?)<br/>ORDER BY ASC
else before_block & before_index provided
BackendAPI->>Database: SELECT * WHERE<br/>(block_number, block_index) < (?, ?)<br/>ORDER BY DESC
else last_page = true
BackendAPI->>Database: SELECT * (oldest)<br/>ORDER BY ASC then reverse
else default
BackendAPI->>Database: SELECT * (newest)<br/>ORDER BY DESC
end
deactivate BackendAPI
activate Database
Database-->>BackendAPI: Return transactions<br/>with limit ≤ 100
deactivate Database
activate BackendAPI
BackendAPI-->>GetTransactions: JSON response with<br/>paginated results
deactivate BackendAPI
activate GetTransactions
GetTransactions-->>TransactionsPage: Transactions data
deactivate GetTransactions
activate TransactionsPage
TransactionsPage->>TransactionsPage: Extract first/last<br/>block coordinates
TransactionsPage->>TransactionsPage: Render updated<br/>transaction list
deactivate TransactionsPage
TransactionsPage-->>User: Display transactions
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
📝 Coding Plan
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
backend/crates/atlas-server/src/api/handlers/transactions.rs (1)
49-79: Consider validating partial cursor parameters.If a client sends
before_blockwithoutbefore_index(or vice versa), the current logic silently falls through to the next branch, potentially returning unexpected results. While the frontend always sends both or neither, the API could be more defensive.🛡️ Optional: reject partial cursor parameters
// At the start of list_transactions, after getting `limit`: let has_before = params.before_block.is_some() || params.before_index.is_some(); let has_after = params.after_block.is_some() || params.after_index.is_some(); if has_before && (params.before_block.is_none() || params.before_index.is_none()) { return Err(AtlasError::BadRequest("Both before_block and before_index are required".into()).into()); } if has_after && (params.after_block.is_none() || params.after_index.is_none()) { return Err(AtlasError::BadRequest("Both after_block and after_index are required".into()).into()); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/crates/atlas-server/src/api/handlers/transactions.rs` around lines 49 - 79, In list_transactions validate partial cursor parameters: detect when either params.before_block or params.before_index is present without its partner (and likewise for params.after_block/params.after_index) and return an AtlasError::BadRequest (or appropriate error) instead of falling through; add checks after computing limit that compute has_before/has_after from params and if has_before && (params.before_block.is_none() || params.before_index.is_none()) or similarly for has_after then return Err(AtlasError::BadRequest("Both before_block and before_index are required".into()).into()) so the SQL branches only run when both cursor components are provided.frontend/src/pages/TransactionsPage.tsx (1)
148-162: Consider guarding against rapid navigation race conditions.The navigation handlers correctly derive cursor values from the current result set. The guards (
if (f),if (l),if (pagination)) handle empty states well.One edge case to consider: if the user clicks navigation buttons rapidly before results load, the cursor derived from stale
transactionsdata could cause unexpected jumps. This is a minor UX concern rather than a correctness bug, since the state will eventually stabilize.🛡️ Optional: disable nav buttons while loading
const goFirst = () => { setCursor({}); setPage(1); }; const goPrev = () => { + if (loading) return; const f = transactions[0]; if (f) setCursor({ afterBlock: f.block_number, afterIndex: f.block_index }); setPage((p) => Math.max(1, p - 1)); }; const goNext = () => { + if (loading) return; const l = transactions[transactions.length - 1]; if (l) setCursor({ beforeBlock: l.block_number, beforeIndex: l.block_index }); setPage((p) => p + 1); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/pages/TransactionsPage.tsx` around lines 148 - 162, Navigation handlers (goFirst/goPrev/goNext/goLast) can derive stale cursors if clicked rapidly before new results load; guard them with the component's loading state (e.g., transactionsLoading or isLoading) so they no-op while a fetch is in-flight. Update goPrev/goNext/goFirst/goLast to early-return when loading is true, and keep using setCursor and setPage only when not loading; reference the existing handlers (goPrev, goNext, goFirst, goLast), the transactions array, pagination object, and setCursor/setPage to locate where to add the guard. Ensure the loading boolean used matches the query hook/state already in this component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@backend/crates/atlas-server/src/api/handlers/transactions.rs`:
- Around line 49-79: In list_transactions validate partial cursor parameters:
detect when either params.before_block or params.before_index is present without
its partner (and likewise for params.after_block/params.after_index) and return
an AtlasError::BadRequest (or appropriate error) instead of falling through; add
checks after computing limit that compute has_before/has_after from params and
if has_before && (params.before_block.is_none() ||
params.before_index.is_none()) or similarly for has_after then return
Err(AtlasError::BadRequest("Both before_block and before_index are
required".into()).into()) so the SQL branches only run when both cursor
components are provided.
In `@frontend/src/pages/TransactionsPage.tsx`:
- Around line 148-162: Navigation handlers (goFirst/goPrev/goNext/goLast) can
derive stale cursors if clicked rapidly before new results load; guard them with
the component's loading state (e.g., transactionsLoading or isLoading) so they
no-op while a fetch is in-flight. Update goPrev/goNext/goFirst/goLast to
early-return when loading is true, and keep using setCursor and setPage only
when not loading; reference the existing handlers (goPrev, goNext, goFirst,
goLast), the transactions array, pagination object, and setCursor/setPage to
locate where to add the guard. Ensure the loading boolean used matches the query
hook/state already in this component.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8d454fcb-6a99-4ed9-aa23-5598e99714b3
📒 Files selected for processing (4)
backend/crates/atlas-server/src/api/handlers/transactions.rsbackend/migrations/20240109000001_cursor_pagination_indexes.sqlfrontend/src/api/transactions.tsfrontend/src/pages/TransactionsPage.tsx
Overview
Summary by CodeRabbit
New Features
Performance Improvements