Skip to content

Conversation

@kernelwhisperer
Copy link
Contributor

@kernelwhisperer kernelwhisperer commented Nov 26, 2025

Summary

Fixes https://linear.app/cowswap/issue/COW-120

Related PR: cowprotocol/cow-sdk#713

The downside to this implementation is that you can't see the number of pages. (totalResults missing)

image image

To Test

The backend change has been merged to base-staging, but Ilya searched the database and the highest number of fills in a single order is 3.

The change is live in production.

Example orders with many fills:

Base prod: 0x3c8a1b22e804935157767226acf931dc7443b5df4d98b4ee1a1a3017c90d0b51711429b3fdf0e76cf7288e8e4078dfdc5366026467d39719

Background

The API latency spikes when this explorer page is loaded, the solution is to use pagination.

Break-down

  1. Extract the useTable call: from OrderDetails to the parent OrderWidget
  2. Use the same "limit plus one" strategy in useOrderTrades, similar to accountOrderUtils.ts
  3. Upgrade cow-sdk to fix a type error when building the explorer:
Type 'import("/home/daniel/repos/cow/cowswap/node_modules/@cowprotocol/cow-sdk/node_modules/@cowprotocol/sdk-order-book/dist/index").OrderBookApi' is not assignable to type 'import("/home/daniel/repos/cow/cowswap/node_modules/@cowprotocol/sdk-order-book/dist/index").OrderBookApi'.
  Types have separate declarations of a private property 'rateLimiter'.ts(2322)

Summary by CodeRabbit

  • New Features

    • Added table-based pagination for order fills with offset/limit controls and hasNextPage support for browsing large trade lists.
    • OrderDetails and OrderWidget now expose and accept pagination state and navigation handlers.
  • Refactor

    • Internal pagination state moved from child components to external tableState props; rendering now respects multi-trade logic.
  • Tests

    • Updated fixtures to include pagination props for OrderDetails.
  • Chores

    • Build configuration path updated.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Nov 26, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
cowfi Ready Ready Preview Dec 22, 2025 11:03am
explorer-dev Ready Ready Preview Dec 22, 2025 11:03am
swap-dev Ready Ready Preview Dec 22, 2025 11:03am
widget-configurator Ready Ready Preview Dec 22, 2025 11:03am
2 Skipped Deployments
Project Deployment Review Updated (UTC)
cosmos Ignored Ignored Dec 22, 2025 11:03am
sdk-tools Ignored Ignored Preview Dec 22, 2025 11:03am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2025

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately and concisely summarizes the main change: adding offset and limit parameters to the getTrades function for pagination support.
Description check ✅ Passed The PR description includes a summary with issue link and context, testing instructions with examples, and background explanation. It covers the key aspects required by the template.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/trades-pagination

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 and usage tips.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 26, 2025

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@kernelwhisperer kernelwhisperer marked this pull request as ready for review December 3, 2025 11:03
@kernelwhisperer kernelwhisperer self-assigned this Dec 3, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
apps/explorer/src/components/orders/OrderDetails/OrderDetails.fixture.tsx (1)

393-405: Fixture pagination props are wired correctly

Centralizing pagination props in mockTableProps and spreading them into all OrderDetails fixtures is a clean way to adapt to the new API. The no‑op handlers and tableState shape align with the component’s expectations; totalResults: 0 is a reasonable placeholder until/if the backend exposes real totals.

Also applies to: 411-577, 581-727

apps/explorer/src/hooks/useOperatorTrades.ts (1)

11-16: Pagination logic in useOrderTrades is correct and matches the “limit+1” pattern

The hook changes look coherent:

  • Accepting (order, offset, limit) and passing { offset, limit: limit + 1 } to getTrades is the right way to detect a next page.
  • Computing hasNext from trades.length > limit and then slicing to limit gives consumers exactly one page plus a reliable hasNextPage flag.
  • Including offset and limit in the fetchTrades callback deps ensures refetch on page/size changes.

If you ever want to simplify state, hasNextPage could be derived from rawTrades and limit inside the effect instead of being stored separately, but what you have is already fine.

Also applies to: 51-57, 69-84, 118-124, 144-147

apps/explorer/src/explorer/components/OrderWidget/index.tsx (1)

9-12: OrderWidget pagination wiring is coherent; consider avoiding direct state mutation

Using useTable for { pageOffset, pageSize } and feeding those into useOrderTrades (with RESULTS_PER_PAGE = 10) gives you a clear pagination flow, and passing tableState and handlers down to OrderDetails via props is a good separation of concerns.

The only smell is:

// eslint-disable-next-line react-hooks/immutability
tableState['hasNextPage'] = hasNextPage

Mutating the state object coming from a hook is generally discouraged. It works here because other state changes trigger re‑renders and consumers only read hasNextPage, but longer‑term it would be cleaner to have useTable expose a setter (e.g. setHasNextPage) or accept hasNextPage as part of its own state update function.

Also applies to: 17-24, 31-37, 38-40, 51-62

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78a28d9 and 41105e2.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (8)
  • apps/explorer/cosmos.config.json (1 hunks)
  • apps/explorer/src/api/operator/operatorApi.ts (2 hunks)
  • apps/explorer/src/api/operator/types.ts (1 hunks)
  • apps/explorer/src/components/orders/OrderDetails/OrderDetails.fixture.tsx (26 hunks)
  • apps/explorer/src/components/orders/OrderDetails/index.tsx (3 hunks)
  • apps/explorer/src/explorer/components/OrderWidget/index.tsx (2 hunks)
  • apps/explorer/src/hooks/useOperatorTrades.ts (6 hunks)
  • package.json (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: cowdan
Repo: cowprotocol/cowswap PR: 6285
File: apps/cowswap-frontend/src/modules/swap/updaters/index.tsx:37-39
Timestamp: 2025-09-24T14:51:43.087Z
Learning: SwapUpdaters component doesn't have pagination functionality - it processes a fixed number (10) of the most recent pending orders, not paginated results.
📚 Learning: 2025-10-10T20:28:16.565Z
Learnt from: fairlighteth
Repo: cowprotocol/cowswap PR: 6347
File: apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/index.tsx:49-49
Timestamp: 2025-10-10T20:28:16.565Z
Learning: In apps/cowswap-frontend/src/modules/trade, TradeConfirmation follows a two-layer architecture: TradeConfirmationView (pure/stateless) in pure/TradeConfirmation/index.tsx renders the UI, while TradeConfirmation (container) in containers/TradeConfirmation/index.tsx wraps it to freeze props during pending trades (via useStableTradeConfirmationProps), wire in signing state (useSigningStep), and inject trade confirmation state (useTradeConfirmState). Consuming modules should import the container TradeConfirmation from 'modules/trade' to preserve this stateful behavior.
<!-- [add_learning]
When reviewing component refactoring in apps/cowswap-frontend/src/modules/trade, recognize the pattern where a pure view component (e.g., TradeConfirmationView) is separated from a stateful container (e.g., TradeConfirmation) that wraps it. The container adds runtime state management (prop stabilization, signing state, etc.) while the view remains testable and composable. Do not flag usages that import th...

Applied to files:

  • apps/explorer/src/explorer/components/OrderWidget/index.tsx
  • apps/explorer/src/components/orders/OrderDetails/index.tsx
📚 Learning: 2025-09-24T14:51:43.087Z
Learnt from: cowdan
Repo: cowprotocol/cowswap PR: 6285
File: apps/cowswap-frontend/src/modules/swap/updaters/index.tsx:37-39
Timestamp: 2025-09-24T14:51:43.087Z
Learning: SwapUpdaters component doesn't have pagination functionality - it processes a fixed number (10) of the most recent pending orders, not paginated results.

Applied to files:

  • apps/explorer/src/explorer/components/OrderWidget/index.tsx
📚 Learning: 2025-09-25T08:48:53.495Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6299
File: apps/cowswap-frontend/src/entities/bridgeProvider/useBridgeSupportedNetworks.test.tsx:58-60
Timestamp: 2025-09-25T08:48:53.495Z
Learning: In the cowswap-frontend codebase, when writing SWR tests, the team prefers maximum test isolation by using `provider: () => new Map()` in SWRConfig wrappers, even if it recreates cache on every render, to ensure tests don't share any state.

Applied to files:

  • apps/explorer/src/components/orders/OrderDetails/OrderDetails.fixture.tsx
📚 Learning: 2025-09-25T08:49:32.256Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6299
File: apps/cowswap-frontend/src/entities/bridgeProvider/useBridgeSupportedNetworks.test.tsx:62-67
Timestamp: 2025-09-25T08:49:32.256Z
Learning: In the cowswap-frontend codebase, when testing hooks that use multiple bridge providers, both providers are always properly mocked as complete jest.Mocked<BridgeProvider<BridgeQuoteResult>> objects with all required methods stubbed, ensuring no undefined returns that could break the hook logic.

Applied to files:

  • apps/explorer/src/components/orders/OrderDetails/OrderDetails.fixture.tsx
🧬 Code graph analysis (3)
apps/explorer/src/hooks/useOperatorTrades.ts (3)
apps/explorer/src/types/index.ts (1)
  • UiError (17-20)
apps/explorer/src/api/operator/types.ts (2)
  • Trade (86-100)
  • RawTrade (81-81)
apps/explorer/src/api/operator/operatorApi.ts (1)
  • getTrades (56-79)
apps/explorer/src/explorer/components/OrderWidget/index.tsx (2)
apps/explorer/src/hooks/useOperatorOrder.ts (1)
  • useOrderAndErc20s (119-150)
apps/explorer/src/hooks/useOperatorTrades.ts (1)
  • useOrderTrades (51-148)
apps/explorer/src/components/orders/OrderDetails/index.tsx (1)
apps/explorer/src/state/network/hooks.ts (1)
  • useNetworkId (6-10)
🔇 Additional comments (5)
package.json (1)

81-81: cow-sdk bump to 7.1.6 looks aligned with new getTrades usage

The version bump is consistent with introducing paginated getTrades calls; no issues spotted here. Please just confirm this SDK version indeed supports { offset, limit } on getTrades and that no other breaking changes affect explorer.

apps/explorer/cosmos.config.json (1)

25-27: Updated Vite config path to .mts

Pointing Cosmos at vite.config.mts makes sense with an ESM Vite config. Just verify that this file exists in apps/explorer and that nx run explorer:cosmos:run still works as expected.

apps/explorer/src/api/operator/types.ts (1)

125-130: GetTradesParams pagination fields are consistent with usage

Adding optional offset and limit here matches how getTrades and useOrderTrades now work; the shape looks correct and backward‑compatible for existing callers that don’t pass these fields.

apps/explorer/src/api/operator/operatorApi.ts (1)

3-3: getTrades now correctly exposes paginated params to the SDK

Switching to GetTradesParams and forwarding { owner, orderUid, offset, limit } to orderBookSDK.getTrades (for both PROD and BARN) aligns the API layer with the new hook and types. The logging changes are also helpful for debugging pagination.

Please double‑check against the cow‑sdk typings/docs that offset and limit have the same semantics you expect (especially when combining PROD + staging results) and that leaving them undefined for legacy callers remains valid.

Also applies to: 56-79

apps/explorer/src/components/orders/OrderDetails/index.tsx (1)

14-15: OrderDetails now cleanly consumes external table pagination state

Importing TableState, extending Props with tableState and pagination callbacks, and passing them through FillsTableContext is a solid refactor: pagination logic lives in the container (OrderWidget) while OrderDetails stays focused on rendering and tab behavior. The tab selection and redirect logic remain unchanged, so this should be a non‑breaking UI change aside from enabling pagination.

Also applies to: 35-46, 140-156, 216-225

@kernelwhisperer kernelwhisperer requested a review from a team December 3, 2025 11:12
@kernelwhisperer
Copy link
Contributor Author

The backend is live in prod on all networks.
@elena-zh not sure if you want to test other networks too...

Before merging we need a new cow-sdk deployment. Waiting on cowprotocol/cow-sdk#752

@elena-zh
Copy link
Contributor

@kernelwhisperer , tested on this order on Mainnet: also looks good

As for other chains, not sure how to find orders with so many fills..

@shoom3301
Copy link
Collaborator

@kernelwhisperer the SDK changes were released to NPM

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/explorer/src/hooks/useOperatorTrades.ts (1)

118-123: Minor inefficiency: timestamps fetched for the extra record.

The fetchTradesTimestamps call on line 90 processes all rawTrades including the limit+1 record that gets discarded. This results in one unnecessary getBlock call per page when more results exist. Consider slicing before fetching timestamps if this becomes a performance concern.

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8876e87 and 3a7d1bf.

📒 Files selected for processing (8)
  • apps/explorer/cosmos.config.json
  • apps/explorer/src/api/operator/operatorApi.ts
  • apps/explorer/src/api/operator/types.ts
  • apps/explorer/src/components/orders/OrderDetails/FillsTable.tsx
  • apps/explorer/src/components/orders/OrderDetails/OrderDetails.fixture.tsx
  • apps/explorer/src/components/orders/OrderDetails/index.tsx
  • apps/explorer/src/explorer/components/OrderWidget/index.tsx
  • apps/explorer/src/hooks/useOperatorTrades.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/explorer/src/api/operator/types.ts
  • apps/explorer/src/components/orders/OrderDetails/OrderDetails.fixture.tsx
  • apps/explorer/src/components/orders/OrderDetails/FillsTable.tsx
  • apps/explorer/src/api/operator/operatorApi.ts
  • apps/explorer/cosmos.config.json
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: cowdan
Repo: cowprotocol/cowswap PR: 6285
File: apps/cowswap-frontend/src/modules/swap/updaters/index.tsx:37-39
Timestamp: 2025-09-24T14:51:43.087Z
Learning: SwapUpdaters component doesn't have pagination functionality - it processes a fixed number (10) of the most recent pending orders, not paginated results.
📚 Learning: 2025-10-10T20:28:16.565Z
Learnt from: fairlighteth
Repo: cowprotocol/cowswap PR: 6347
File: apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/index.tsx:49-49
Timestamp: 2025-10-10T20:28:16.565Z
Learning: In apps/cowswap-frontend/src/modules/trade, TradeConfirmation follows a two-layer architecture: TradeConfirmationView (pure/stateless) in pure/TradeConfirmation/index.tsx renders the UI, while TradeConfirmation (container) in containers/TradeConfirmation/index.tsx wraps it to freeze props during pending trades (via useStableTradeConfirmationProps), wire in signing state (useSigningStep), and inject trade confirmation state (useTradeConfirmState). Consuming modules should import the container TradeConfirmation from 'modules/trade' to preserve this stateful behavior.
<!-- [add_learning]
When reviewing component refactoring in apps/cowswap-frontend/src/modules/trade, recognize the pattern where a pure view component (e.g., TradeConfirmationView) is separated from a stateful container (e.g., TradeConfirmation) that wraps it. The container adds runtime state management (prop stabilization, signing state, etc.) while the view remains testable and composable. Do not flag usages that import th...

Applied to files:

  • apps/explorer/src/explorer/components/OrderWidget/index.tsx
  • apps/explorer/src/components/orders/OrderDetails/index.tsx
📚 Learning: 2025-10-13T19:41:31.440Z
Learnt from: limitofzero
Repo: cowprotocol/cowswap PR: 6351
File: apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.ts:87-121
Timestamp: 2025-10-13T19:41:31.440Z
Learning: In apps/cowswap-frontend/src/modules/erc20Approve, useApproveCallback returns Promise<TransactionResponse | undefined> and is distinct from useApproveCurrency, which can return Promise<TransactionReceipt | SafeMultisigTransactionResponse>. When reviewing approval flows, verify which hook is actually being used before flagging Safe wallet concerns.

Applied to files:

  • apps/explorer/src/components/orders/OrderDetails/index.tsx
📚 Learning: 2025-11-19T10:18:23.717Z
Learnt from: limitofzero
Repo: cowprotocol/cowswap PR: 6537
File: apps/cowswap-frontend/src/modules/trade/pure/PartnerFeeRow/index.tsx:33-35
Timestamp: 2025-11-19T10:18:23.717Z
Learning: In apps/cowswap-frontend/src/modules/trade/pure/PartnerFeeRow/index.tsx, when there is no partner fee (amount is null/undefined, bps is missing, or amount equals 0), FreeFeeRow is rendered with withTimelineDot={false} hardcoded. This is intentional design—free fee rows should not show the timeline dot regardless of what the parent component passes, as they have a distinct visual treatment from actual fee rows.

Applied to files:

  • apps/explorer/src/components/orders/OrderDetails/index.tsx
🧬 Code graph analysis (3)
apps/explorer/src/hooks/useOperatorTrades.ts (3)
apps/explorer/src/types/index.ts (1)
  • UiError (17-20)
apps/explorer/src/api/operator/types.ts (2)
  • Trade (86-100)
  • RawTrade (81-81)
apps/explorer/src/api/operator/operatorApi.ts (1)
  • getTrades (56-79)
apps/explorer/src/explorer/components/OrderWidget/index.tsx (3)
apps/explorer/src/explorer/components/OrdersTableWidget/useTable.tsx (1)
  • useTable (32-71)
apps/explorer/src/hooks/useOperatorOrder.ts (1)
  • useOrderAndErc20s (119-150)
apps/explorer/src/hooks/useOperatorTrades.ts (1)
  • useOrderTrades (51-148)
apps/explorer/src/components/orders/OrderDetails/index.tsx (2)
apps/explorer/src/explorer/components/OrdersTableWidget/useTable.tsx (1)
  • TableState (5-10)
apps/explorer/src/components/orders/OrdersUserDetailsTable/index.tsx (1)
  • Props (57-62)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Cypress
  • GitHub Check: Setup
🔇 Additional comments (10)
apps/explorer/src/hooks/useOperatorTrades.ts (3)

51-56: LGTM - Pagination parameters and state properly added.

The hook signature correctly defaults offset to 0 and limit to 10, and the new hasNextPage state is appropriately initialized.


68-84: LGTM - "Limit plus one" pattern correctly implemented.

The limit + 1 fetch strategy is a standard, efficient approach for detecting additional pages without requiring a separate count query. The callback dependencies are correctly updated.


144-147: LGTM - Return value properly memoized with new dependency.

The hasNextPage is correctly included in the memoization dependencies and returned result.

apps/explorer/src/explorer/components/OrderWidget/index.tsx (2)

17-36: LGTM - Pagination state setup and hook integration.

The table state initialization with pageOffset: 0 and pageSize: RESULTS_PER_PAGE is correct, and the hook is properly invoked with the pagination parameters.


9-9: No action needed. The import path is correct. OrderWidget requires setPageOffset, which is only exported by TokensTableWidget/useTable. The OrdersTableWidget/useTable variant does not export this function, making the current import the only viable option.

apps/explorer/src/components/orders/OrderDetails/index.tsx (5)

41-45: LGTM - Props interface properly extended for external pagination control.

The new props correctly expose the pagination state and handlers needed for external state management.


75-81: LGTM - hasMultipleTrades properly integrated.

The hasMultipleTrades parameter is correctly used to determine both showFills logic and getOrderWithTxHash behavior.


138-143: LGTM - getOrderWithTxHash logic correctly updated.

The condition trades.length === 1 && !hasMultipleTrades correctly ensures txHash is only attached when there's truly a single trade across all pages, preventing the edge case where pagination would incorrectly assign the first trade's hash.


246-246: LGTM - Edge case for hasMultipleTrades correctly addressed.

The condition now includes !!tableState.hasNextPage, which handles the scenario where there's only one trade visible but more exist on subsequent pages. This addresses the concern from the previous review.


223-232: LGTM - Context provider correctly wired with external state.

The FillsTableContext.Provider properly passes all pagination controls from the parent, enabling child components to access consistent pagination state.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/explorer/src/api/operator/operatorApi.ts (1)

62-78: Critical: PROD/BARN merge breaks "limit plus one" pagination strategy.

The current implementation passes the same offset and limit to both PROD and BARN environments, then merges the results. This breaks the "limit plus one" strategy used in useOrderTrades:

The problem:

  1. useOrderTrades requests limit + 1 trades (e.g., 11 when limit=10)
  2. This function requests 11 from PROD → returns up to 11 trades
  3. This function requests 11 from BARN → returns up to 11 trades
  4. Merged result: up to 22 trades
  5. Hook checks trades.length (22) > limit (10) → true
  6. Hook sets hasNextPage = true and slices to 10 trades
  7. Result: 12 trades are lost, and hasNextPage may be incorrectly true

Impact:

  • Trades from one environment could be systematically hidden
  • Page navigation will skip records
  • hasNextPage logic is unreliable when both environments return data

Potential solutions:

  1. Apply pagination post-merge (fetch all from both, merge, then paginate)
  2. Fetch limit+1 from PROD, check length; if < limit+1, fetch remaining from BARN
  3. Choose primary environment for pagination and treat BARN as supplementary
  4. Have backend handle the merge with pagination
🧹 Nitpick comments (1)
apps/explorer/src/components/orders/OrderDetails/FillsTable.tsx (1)

19-19: Consider removing unused tableState prop.

The tableState prop is defined in the type but never destructured or used in the component. Since pagination is now managed externally, this prop appears to be vestigial.

🔎 Proposed cleanup
 type FillsTableProps = SimpleTableProps & {
   trades: Trade[] | undefined
   order: Order | null
-  tableState: TableState
   isPriceInverted: boolean
   invertPrice: Command
 }

Also applies to: 25-25

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3a7d1bf and 1b4f953.

📒 Files selected for processing (8)
  • apps/explorer/cosmos.config.json
  • apps/explorer/src/api/operator/operatorApi.ts
  • apps/explorer/src/api/operator/types.ts
  • apps/explorer/src/components/orders/OrderDetails/FillsTable.tsx
  • apps/explorer/src/components/orders/OrderDetails/OrderDetails.fixture.tsx
  • apps/explorer/src/components/orders/OrderDetails/index.tsx
  • apps/explorer/src/explorer/components/OrderWidget/index.tsx
  • apps/explorer/src/hooks/useOperatorTrades.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/explorer/src/explorer/components/OrderWidget/index.tsx
  • apps/explorer/src/api/operator/types.ts
  • apps/explorer/src/components/orders/OrderDetails/OrderDetails.fixture.tsx
  • apps/explorer/cosmos.config.json
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-10-10T20:28:16.565Z
Learnt from: fairlighteth
Repo: cowprotocol/cowswap PR: 6347
File: apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/index.tsx:49-49
Timestamp: 2025-10-10T20:28:16.565Z
Learning: In apps/cowswap-frontend/src/modules/trade, TradeConfirmation follows a two-layer architecture: TradeConfirmationView (pure/stateless) in pure/TradeConfirmation/index.tsx renders the UI, while TradeConfirmation (container) in containers/TradeConfirmation/index.tsx wraps it to freeze props during pending trades (via useStableTradeConfirmationProps), wire in signing state (useSigningStep), and inject trade confirmation state (useTradeConfirmState). Consuming modules should import the container TradeConfirmation from 'modules/trade' to preserve this stateful behavior.
<!-- [add_learning]
When reviewing component refactoring in apps/cowswap-frontend/src/modules/trade, recognize the pattern where a pure view component (e.g., TradeConfirmationView) is separated from a stateful container (e.g., TradeConfirmation) that wraps it. The container adds runtime state management (prop stabilization, signing state, etc.) while the view remains testable and composable. Do not flag usages that import th...

Applied to files:

  • apps/explorer/src/components/orders/OrderDetails/FillsTable.tsx
  • apps/explorer/src/components/orders/OrderDetails/index.tsx
📚 Learning: 2025-11-19T10:18:23.717Z
Learnt from: limitofzero
Repo: cowprotocol/cowswap PR: 6537
File: apps/cowswap-frontend/src/modules/trade/pure/PartnerFeeRow/index.tsx:33-35
Timestamp: 2025-11-19T10:18:23.717Z
Learning: In apps/cowswap-frontend/src/modules/trade/pure/PartnerFeeRow/index.tsx, when there is no partner fee (amount is null/undefined, bps is missing, or amount equals 0), FreeFeeRow is rendered with withTimelineDot={false} hardcoded. This is intentional design—free fee rows should not show the timeline dot regardless of what the parent component passes, as they have a distinct visual treatment from actual fee rows.

Applied to files:

  • apps/explorer/src/components/orders/OrderDetails/FillsTable.tsx
  • apps/explorer/src/components/orders/OrderDetails/index.tsx
📚 Learning: 2025-10-13T19:41:31.440Z
Learnt from: limitofzero
Repo: cowprotocol/cowswap PR: 6351
File: apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.ts:87-121
Timestamp: 2025-10-13T19:41:31.440Z
Learning: In apps/cowswap-frontend/src/modules/erc20Approve, useApproveCallback returns Promise<TransactionResponse | undefined> and is distinct from useApproveCurrency, which can return Promise<TransactionReceipt | SafeMultisigTransactionResponse>. When reviewing approval flows, verify which hook is actually being used before flagging Safe wallet concerns.

Applied to files:

  • apps/explorer/src/components/orders/OrderDetails/index.tsx
🧬 Code graph analysis (4)
apps/explorer/src/api/operator/operatorApi.ts (2)
apps/explorer/src/api/operator/types.ts (2)
  • GetTradesParams (125-130)
  • RawTrade (81-81)
apps/explorer/src/cowSdk.ts (1)
  • orderBookSDK (11-14)
apps/explorer/src/hooks/useOperatorTrades.ts (3)
apps/explorer/src/types/index.ts (1)
  • UiError (17-20)
apps/explorer/src/api/operator/types.ts (2)
  • Trade (86-100)
  • RawTrade (81-81)
apps/explorer/src/api/operator/operatorApi.ts (1)
  • getTrades (56-79)
apps/explorer/src/components/orders/OrderDetails/FillsTable.tsx (1)
apps/explorer/src/components/orders/OrderDetails/FillsTableRow.tsx (1)
  • FillsTableRow (30-93)
apps/explorer/src/components/orders/OrderDetails/index.tsx (2)
apps/explorer/src/explorer/components/OrdersTableWidget/useTable.tsx (1)
  • TableState (5-10)
apps/explorer/src/api/operator/types.ts (2)
  • Order (38-76)
  • Trade (86-100)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Setup
  • GitHub Check: Cypress
🔇 Additional comments (11)
apps/explorer/src/components/orders/OrderDetails/FillsTable.tsx (1)

29-37: LGTM - Pagination externalization complete.

The component now correctly renders the trades array directly without internal pagination logic, delegating pagination control to the parent component as intended by this PR.

apps/explorer/src/api/operator/operatorApi.ts (1)

3-3: LGTM - Type extraction and parameter handling.

The refactoring to use GetTradesParams improves maintainability, and the logging correctly includes the new pagination parameters.

Also applies to: 57-60

apps/explorer/src/hooks/useOperatorTrades.ts (4)

11-16: LGTM - Pagination parameters and return type.

The addition of hasNextPage to the result and default pagination parameters (offset=0, limit=10) are well-designed and consistent with standard pagination patterns.

Also applies to: 51-51


62-84: "Limit plus one" strategy implemented correctly.

The fetch logic correctly requests limit + 1 records to detect if more pages exist (Line 69). The dependency array (Line 83) appropriately includes offset and limit to trigger refetch when pagination parameters change.

Note: This implementation assumes getTrades returns properly paginated results. The PROD/BARN merge issue flagged in operatorApi.ts may affect the correctness of this strategy.


118-123: LGTM - hasNextPage detection and result memoization.

The "limit plus one" detection logic is correctly implemented:

  • Checks if trades.length > limit to determine if more pages exist (Line 119)
  • Conditionally slices to limit when there are more results (Line 122)
  • Properly memoizes the result including hasNextPage (Lines 144-147)

Also applies to: 144-147


111-117: Client-side sorting only affects the current page; verify backend returns trades in consistent order.

The getTrades API call passes no sort parameters, and each paginated batch is sorted independently on the client (lines 111-117). If the backend doesn't guarantee a consistent sort order across all results, users could see trades in different chronological order when navigating pages.

Consider either:

  • Passing an orderBy parameter to the backend (if supported by the API)
  • Documenting the expected sort order behavior
  • Removing client-side sort if backend already returns sorted results
apps/explorer/src/components/orders/OrderDetails/index.tsx (5)

35-46: LGTM - Pagination props structure.

The addition of tableState and pagination handlers (setPageSize, setPageOffset, handleNextPage, handlePreviousPage) follows a clear external pagination pattern, properly typing all new props.


138-143: LGTM - Correct handling of single trade with pagination.

The updated logic correctly handles the edge case where the current page shows only one trade, but other trades exist on different pages. By checking both trades.length === 1 and !hasMultipleTrades, it ensures txHash is only attached when there's truly a single trade for the entire order.


75-81: LGTM - Consistent hasMultipleTrades usage.

The hasMultipleTrades parameter is properly threaded through tabItems and used consistently in:

  • getOrderWithTxHash call (Line 77)
  • showFills condition (Line 81)

This ensures the Fills tab and order details rendering respect pagination state.


246-246: LGTM - hasMultipleTrades computation correctly handles pagination edge cases.

The boolean expression correctly determines if multiple trades exist across all pages by checking:

  1. trades.length > 1 - Multiple trades on current page
  2. tableState.pageIndex > 1 - Previous pages exist with trades
  3. tableState.hasNextPage - Subsequent pages exist with trades

This addresses the edge case previously flagged where a single trade on the current page but more on other pages would incorrectly set hasMultipleTrades = false.


223-232: LGTM - Context provider properly wired with pagination state.

The FillsTableContext.Provider correctly supplies all pagination state and handlers to child components, enabling the external pagination pattern implemented in this PR.

@kernelwhisperer kernelwhisperer merged commit 57d738d into develop Dec 22, 2025
16 checks passed
@kernelwhisperer kernelwhisperer deleted the feat/trades-pagination branch December 22, 2025 11:04
@github-actions github-actions bot locked and limited conversation to collaborators Dec 22, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants