[P2] Pagination & deep result access for exchanges #111

Open
opened 2026-04-01 22:54:58 +02:00 by claude · 1 comment
Owner

Parent Epic

#100

Problem

The exchange list caps at 50 results fetched from the server, paginated client-side in pages of 25. The total is 2,096+ but there's no way to access results beyond the initial 50. For debugging, developers often need to find a specific exchange from hours ago.

Current State

  • Server returns 50 results max
  • Client-side pagination: 25 rows per page, 2 pages (50 rows)
  • Total shows 50 of 2,096 exchanges
  • No "Load more" or server-side pagination
  • Only mechanism to find older exchanges: narrow the time range
  • No sort options beyond column header toggles

Proposed Solution

1. Server-Side Pagination

Replace client-side pagination with proper server-side pagination:

1–25 of 2,096    Rows: [25 ▾]   ‹  1 / 84  ›

Backend needs: GET /api/v1/executions?offset=0&limit=25&sort=started_desc

2. Virtual Scrolling (alternative)

Instead of page numbers, use infinite scroll with virtualized rendering:

  • Load 50 results initially
  • As user scrolls down, fetch next batch
  • Virtual rendering keeps DOM lightweight
  • "Jump to top" button when scrolled deep

3. Cursor-Based Pagination

For live-updating data, cursor-based pagination is more stable than offset-based:

GET /api/v1/executions?before=2026-04-01T22:31:33Z&limit=25

This prevents items shifting between pages as new exchanges arrive.

The existing Ctrl+K command palette can search exchanges, but the exchanges table itself needs inline search that queries ClickHouse:

┌─ Search exchanges ──────────────────────────────────┐
│ 🔍 orderId=4521                                     │
│    [Route ▾]  [App ▾]  [Duration > ▾]  [Status ▾]  │
└─────────────────────────────────────────────────────┘

Recommendation

Cursor-based pagination (Option 3) is the best fit because:

  • Live data means offset pagination has jumping/duplication issues
  • Cursor = timestamp of last row, simple and efficient
  • Pairs well with the existing "LIVE" auto-refresh mode

Acceptance Criteria

  • Server-side pagination with configurable page size
  • Can navigate to any page, not just first 2
  • Total count shown accurately
  • Pagination state preserved in URL (for shareable links, see #103)
  • "Jump to" page number input for large datasets
## Parent Epic #100 ## Problem The exchange list caps at 50 results fetched from the server, paginated client-side in pages of 25. The total is 2,096+ but there's no way to access results beyond the initial 50. For debugging, developers often need to find a specific exchange from hours ago. ## Current State - Server returns 50 results max - Client-side pagination: 25 rows per page, 2 pages (50 rows) - Total shows `50 of 2,096 exchanges` - No "Load more" or server-side pagination - Only mechanism to find older exchanges: narrow the time range - No sort options beyond column header toggles ## Proposed Solution ### 1. Server-Side Pagination Replace client-side pagination with proper server-side pagination: ``` 1–25 of 2,096 Rows: [25 ▾] ‹ 1 / 84 › ``` Backend needs: `GET /api/v1/executions?offset=0&limit=25&sort=started_desc` ### 2. Virtual Scrolling (alternative) Instead of page numbers, use infinite scroll with virtualized rendering: - Load 50 results initially - As user scrolls down, fetch next batch - Virtual rendering keeps DOM lightweight - "Jump to top" button when scrolled deep ### 3. Cursor-Based Pagination For live-updating data, cursor-based pagination is more stable than offset-based: ``` GET /api/v1/executions?before=2026-04-01T22:31:33Z&limit=25 ``` This prevents items shifting between pages as new exchanges arrive. ### 4. Better Search The existing Ctrl+K command palette can search exchanges, but the exchanges table itself needs inline search that queries ClickHouse: ``` ┌─ Search exchanges ──────────────────────────────────┐ │ 🔍 orderId=4521 │ │ [Route ▾] [App ▾] [Duration > ▾] [Status ▾] │ └─────────────────────────────────────────────────────┘ ``` ## Recommendation **Cursor-based pagination** (Option 3) is the best fit because: - Live data means offset pagination has jumping/duplication issues - Cursor = timestamp of last row, simple and efficient - Pairs well with the existing "LIVE" auto-refresh mode ## Acceptance Criteria - [ ] Server-side pagination with configurable page size - [ ] Can navigate to any page, not just first 2 - [ ] Total count shown accurately - [ ] Pagination state preserved in URL (for shareable links, see #103) - [ ] "Jump to" page number input for large datasets
claude added the uiux labels 2026-04-01 22:54:58 +02:00
Author
Owner

Design Specification

Cursor-based pagination: before param (ISO timestamp) replaces OFFSET. Query: WHERE start_time < {before} ORDER BY start_time DESC LIMIT N+1. Extra row determines hasMore.

Backend changes: Add before field to SearchRequest, nextCursor field to SearchResult. Backward compatible (absent before = OFFSET mode).

Frontend: Cursor stack in component state for Previous navigation. Page indicator Page {n} of ~{total/pageSize}. Rows-per-page pill bar: 25|50|100.

LIVE mode: active on page 1 only. Paging forward pauses auto-refresh with banner: "Auto-refresh paused while browsing history. [Return to latest]".

## Design Specification **Cursor-based pagination**: `before` param (ISO timestamp) replaces OFFSET. Query: `WHERE start_time < {before} ORDER BY start_time DESC LIMIT N+1`. Extra row determines `hasMore`. Backend changes: Add `before` field to `SearchRequest`, `nextCursor` field to `SearchResult`. Backward compatible (absent `before` = OFFSET mode). Frontend: Cursor stack in component state for Previous navigation. Page indicator `Page {n} of ~{total/pageSize}`. Rows-per-page pill bar: 25|50|100. LIVE mode: active on page 1 only. Paging forward pauses auto-refresh with banner: "Auto-refresh paused while browsing history. [Return to latest]".
Sign in to join this conversation.