Fetch Request UI #9

Merged
aetos merged 1 commits from fetch-request-steps-ui into main 2026-05-31 09:28:27 +00:00
Owner

Summary

Add Fetch Request pipeline UI with real-time SSE progress tracking, ambiguity resolution, enhanced list page with filtering/retry, and detail page with stepper/event feed. Includes new API primitives (api.patch, usePatch hook) and extensive type definitions for SSE events, ambiguity resolution, and pipeline statuses.

Changes by file

react-openapi/api/client.ts

  • Added api.patch() method (delegates to AxiosInstance.patch)

react-openapi/hooks/useResource.ts

  • Added usePatch() mutation hook — sends PATCH /{endpoint}/{id} with partial data, invalidates list + detail query caches on success

src/FetchRequestDetail.tsx (new, +675 lines)

Full detail page for a single fetch request, composed of:

  • Header — status chip, account name, source type (File/Email), date range, created/completed timestamps
  • Progress barLinearProgress with percentage computed via computeProgressPercent():
    • Extract phase: snaps to 10% on first raw_lines/txn_blocks event
    • Raw Expense: ratio of displayParsedCount / txnBlockCount × 20%
    • Enrich: ratio of stepStats.enrich_count / txnDictCount × 50%
    • Save: ratio of stepStats.save_count / txnDictCount × 20%
  • Retry section — retry count bar (retryCount/RETRY_MAX) + "Retry" button if failed & not exhausted
  • Error/success alertserror_message display, max-retries info
  • Pipeline Stepper — 4-step (ExtractRaw ExpenseEnrichSave) with custom icons per state: completed (CheckCircle, green), active (CircularProgress, animating), paused (WarningAmber, amber), failed (ErrorIcon, red), inactive (step number, grey). Step count labels shown below each label (e.g. 150/246, 100/246)
  • Progress Events feed — auto-scrolling list of SSE events with deduplication:
    • Only latest progress event per step (txn_dicts, enrich, save_expenses)
    • started events hidden when a terminal event (completed/skipped/paused/failed) follows
    • load_content events excluded entirely
    • Connection status indicator (green dot / red dot)
  • Ambiguity Resolution — When pipeline is paused, shows ambiguity cards:
    • Raw line in monospace code block
    • OCR amount/balance (struck through), previous balance
    • Candidate buttons with credit/debit coloring (green for positive, red for negative)
    • Resolved state shows green alert with chosen values
    • "All resolved" vs "Pipeline paused" alerts
  • SSE connectionEventSource to {baseUrl}/fetch-requests/{id}/events:
    • Tracks progress, completed, paused, failed events
    • On paused: refetch request + ambiguities
    • On failed: refetch request + show error snackbar from message.error
    • On completed/resume_extract: refetch request
    • Cleans up on unmount
  • Snackbar — pipeline failure notification (6s, bottom-center)

src/FetchRequests.tsx (+347/−73 lines)

Major enhancement to the list page:

  • New filter bar (replaces plain list header):
    • Status multi-select (pending, processing, paused, raw_expenses_done, enriched_done, completed, failed)
    • Account name text filter
    • Source type toggle (All / File / Email)
    • Refresh button
  • Account autocomplete — fetches accounts list via useResourceByName("accounts"), provides dropdown
  • Format dropdown — driven by resourceOverrides config (fetchRes.fields.source.schema.format.options), fallback ["axis", "icici_ocr"]
  • Date pickers — changed from datetime-local to date, capped at today's date
  • Navigation — on create, navigates to /fetch-requests/{id} via useNavigate
  • Row actions: retry (failed, retry_count < 3), navigate to detail (paused), delete with confirmation dialog
  • Copy fingerprint — icon button copies to clipboard with snackbar confirmation
  • Sorting — table sorted by created_at descending
  • Table columns — changed from [Fingerprint, Source, Account, Status, Created, Actions] to [ID, Account, Source, Date Range, Status, Retries, Created, Actions]
  • Retry count display — shows retry_count/RETRY_MAX when >0, otherwise
  • Status tooltip — shows error_message on hover when present
  • Status icons — new statusIcons map: ScheduleIcon (pending), CircularProgress (processing), WarningAmber (paused), HourglassEmpty (raw_expenses_done/enriched_done), CheckCircle (completed), ErrorIcon (failed)
  • Error handling — 409 conflict detection (duplicate fingerprint), 422 validation via formatApiError()
  • handleRetry — PATCH {status: "pending"} on failed requests, success/error snackbar

src/features/fetch-requests/fetch-requests.models.ts (+97 lines)

New types and helpers:

  • Added "paused" to FetchRequestStatus
  • FileSource: added raw_lines, txn_blocks, txn_dicts, txn_dict_count, txn_dicts_count
  • EmailSource: added txn_dict_count, txn_dicts_count
  • FetchRequest added retry_count
  • New interfaces: FetchRequestUpdate, AmbiguityCandidate, PendingAmbiguity, ResolveAmbiguityPayload, FetchRequestFilters
  • SSE types:
    • SSEEventStep: load_content | raw_lines | txn_blocks | txn_dicts | resume_extract | extract | paused | complete | enrich | save_expenses | pipeline
    • SSEEventStatus: started | completed | skipped | paused | progress | failed
    • ProgressMessage: lines? | blocks? | count? | unit? | raw_ocr_line? | error?
    • SSEEvent: { step, status, message }
  • Helpers: formatApiError() — parses FastAPI 422 validation detail arrays ("Missing: field_name"), RETRY_MAX = 3

src/features/fetch-requests/index.ts (+13 lines)

Barrel exports for all new types (FetchRequestUpdate, FetchRequestFilters, PendingAmbiguity, AmbiguityCandidate, ResolveAmbiguityPayload, SSEEvent, SSEEventStep, SSEEventStatus, ProgressMessage), value exports (RETRY_MAX, formatApiError), and new hooks (useUpdateFetchRequest, useFetchRequestAmbiguities, useResolveAmbiguity)

src/features/fetch-requests/useFetchRequests.ts (+49 lines)

Added hooks:

  • useUpdateFetchRequest()usePatch("fetch-requests")
  • useFetchRequestAmbiguities(fetchRequestId)useQuery for GET /fetch-requests/{id}/ambiguities
  • useResolveAmbiguity()useMutation for POST /ambiguities/{id}/resolve with cache invalidation of both ambiguities and detail queries

src/main.jsx (+2 lines)

  • Added import for FetchRequestDetail
  • Added route { path: "/fetch-requests/:id", component: FetchRequestDetail, headerTitle: "Fetch Request" }
## Summary Add Fetch Request pipeline UI with real-time SSE progress tracking, ambiguity resolution, enhanced list page with filtering/retry, and detail page with stepper/event feed. Includes new API primitives (`api.patch`, `usePatch` hook) and extensive type definitions for SSE events, ambiguity resolution, and pipeline statuses. ## Changes by file ### `react-openapi/api/client.ts` - Added `api.patch()` method (delegates to `AxiosInstance.patch`) ### `react-openapi/hooks/useResource.ts` - Added `usePatch()` mutation hook — sends PATCH `/{endpoint}/{id}` with partial data, invalidates list + detail query caches on success ### `src/FetchRequestDetail.tsx` **(new, +675 lines)** Full detail page for a single fetch request, composed of: - **Header** — status chip, account name, source type (File/Email), date range, created/completed timestamps - **Progress bar** — `LinearProgress` with percentage computed via `computeProgressPercent()`: - Extract phase: snaps to 10% on first `raw_lines`/`txn_blocks` event - Raw Expense: ratio of `displayParsedCount` / `txnBlockCount` × 20% - Enrich: ratio of `stepStats.enrich_count` / `txnDictCount` × 50% - Save: ratio of `stepStats.save_count` / `txnDictCount` × 20% - **Retry section** — retry count bar (`retryCount/RETRY_MAX`) + "Retry" button if failed & not exhausted - **Error/success alerts** — `error_message` display, max-retries info - **Pipeline Stepper** — 4-step (`Extract` → `Raw Expense` → `Enrich` → `Save`) with custom icons per state: completed (CheckCircle, green), active (CircularProgress, animating), paused (WarningAmber, amber), failed (ErrorIcon, red), inactive (step number, grey). Step count labels shown below each label (e.g. `150/246`, `100/246`) - **Progress Events feed** — auto-scrolling list of SSE events with deduplication: - Only latest `progress` event per step (`txn_dicts`, `enrich`, `save_expenses`) - `started` events hidden when a terminal event (`completed`/`skipped`/`paused`/`failed`) follows - `load_content` events excluded entirely - Connection status indicator (green dot / red dot) - **Ambiguity Resolution** — When pipeline is `paused`, shows ambiguity cards: - Raw line in monospace code block - OCR amount/balance (struck through), previous balance - Candidate buttons with credit/debit coloring (green for positive, red for negative) - Resolved state shows green alert with chosen values - "All resolved" vs "Pipeline paused" alerts - **SSE connection** — `EventSource` to `{baseUrl}/fetch-requests/{id}/events`: - Tracks `progress`, `completed`, `paused`, `failed` events - On `paused`: refetch request + ambiguities - On `failed`: refetch request + show error snackbar from `message.error` - On `completed`/`resume_extract`: refetch request - Cleans up on unmount - **Snackbar** — pipeline failure notification (6s, bottom-center) ### `src/FetchRequests.tsx` **(+347/−73 lines)** Major enhancement to the list page: - **New filter bar** (replaces plain list header): - Status multi-select (pending, processing, paused, raw_expenses_done, enriched_done, completed, failed) - Account name text filter - Source type toggle (All / File / Email) - Refresh button - **Account autocomplete** — fetches accounts list via `useResourceByName("accounts")`, provides dropdown - **Format dropdown** — driven by `resourceOverrides` config (`fetchRes.fields.source.schema.format.options`), fallback `["axis", "icici_ocr"]` - **Date pickers** — changed from `datetime-local` to `date`, capped at today's date - **Navigation** — on create, navigates to `/fetch-requests/{id}` via `useNavigate` - **Row actions**: retry (failed, retry_count < 3), navigate to detail (paused), delete with confirmation dialog - **Copy fingerprint** — icon button copies to clipboard with snackbar confirmation - **Sorting** — table sorted by `created_at` descending - **Table columns** — changed from `[Fingerprint, Source, Account, Status, Created, Actions]` to `[ID, Account, Source, Date Range, Status, Retries, Created, Actions]` - **Retry count display** — shows `retry_count/RETRY_MAX` when >0, otherwise `—` - **Status tooltip** — shows `error_message` on hover when present - **Status icons** — new `statusIcons` map: ScheduleIcon (pending), CircularProgress (processing), WarningAmber (paused), HourglassEmpty (raw_expenses_done/enriched_done), CheckCircle (completed), ErrorIcon (failed) - **Error handling** — 409 conflict detection (duplicate fingerprint), 422 validation via `formatApiError()` - **`handleRetry`** — PATCH `{status: "pending"}` on failed requests, success/error snackbar ### `src/features/fetch-requests/fetch-requests.models.ts` **(+97 lines)** New types and helpers: - Added `"paused"` to `FetchRequestStatus` - `FileSource`: added `raw_lines`, `txn_blocks`, `txn_dicts`, `txn_dict_count`, `txn_dicts_count` - `EmailSource`: added `txn_dict_count`, `txn_dicts_count` - `FetchRequest` added `retry_count` - **New interfaces**: `FetchRequestUpdate`, `AmbiguityCandidate`, `PendingAmbiguity`, `ResolveAmbiguityPayload`, `FetchRequestFilters` - **SSE types**: - `SSEEventStep`: `load_content | raw_lines | txn_blocks | txn_dicts | resume_extract | extract | paused | complete | enrich | save_expenses | pipeline` - `SSEEventStatus`: `started | completed | skipped | paused | progress | failed` - `ProgressMessage`: `lines? | blocks? | count? | unit? | raw_ocr_line? | error?` - `SSEEvent: { step, status, message }` - **Helpers**: `formatApiError()` — parses FastAPI 422 validation detail arrays (`"Missing: field_name"`), `RETRY_MAX = 3` ### `src/features/fetch-requests/index.ts` **(+13 lines)** Barrel exports for all new types (`FetchRequestUpdate`, `FetchRequestFilters`, `PendingAmbiguity`, `AmbiguityCandidate`, `ResolveAmbiguityPayload`, `SSEEvent`, `SSEEventStep`, `SSEEventStatus`, `ProgressMessage`), value exports (`RETRY_MAX`, `formatApiError`), and new hooks (`useUpdateFetchRequest`, `useFetchRequestAmbiguities`, `useResolveAmbiguity`) ### `src/features/fetch-requests/useFetchRequests.ts` **(+49 lines)** Added hooks: - `useUpdateFetchRequest()` → `usePatch("fetch-requests")` - `useFetchRequestAmbiguities(fetchRequestId)` → `useQuery` for `GET /fetch-requests/{id}/ambiguities` - `useResolveAmbiguity()` → `useMutation` for `POST /ambiguities/{id}/resolve` with cache invalidation of both ambiguities and detail queries ### `src/main.jsx` **(+2 lines)** - Added import for `FetchRequestDetail` - Added route `{ path: "/fetch-requests/:id", component: FetchRequestDetail, headerTitle: "Fetch Request" }`
aetos added 1 commit 2026-05-30 16:10:22 +00:00
## Summary

Add Fetch Request pipeline UI with real-time SSE progress tracking, ambiguity resolution, list page with filtering/retry, and detail page with stepper/event feed.

## Changes

### New files

- **`src/FetchRequestDetail.tsx`** (+675 lines) — Full detail page for a single fetch request with:
  - SSE connection for real-time pipeline progress (`/fetch-requests/:id/events`)
  - 4-step stepper (Extract → Raw Expense → Enrich → Save) with active/completed/failed/paused states
  - Granular progress bar (10% Extract, 20% Raw Expense, 50% Enrich, 20% Save)
  - Progress event feed with auto-scroll and deduplication (only latest `progress` per step, hides `started` when terminal event follows)
  - Ambiguity resolution cards with candidate selection buttons
  - Retry support with retry-count progress bar
  - Failure/success snackbar notifications
  - Error display for failed fetch requests

### Modified files

- **`react-openapi/api/client.ts`** — added `api.patch()` method for PATCH requests
- **`react-openapi/hooks/useResource.ts`** — added `usePatch()` mutation hook for partial updates with cache invalidation
- **`src/FetchRequests.tsx`** (+347/−73 lines) — Major list page rewrite:
  - Row-level actions: retry (failed <3 retries), navigate to detail (paused), delete with confirmation dialog
  - Filter bar: status multi-select, account text filter, file/email source toggle
  - Account name autocomplete from API
  - Format dropdown driven by `resourceOverrides` config
  - Date pickers (changed from `datetime-local` to `date`)
  - Copy fingerprint button, retry count display, date range column
  - Row click navigates to detail, sorted by `created_at` desc
  - `pause` status support in `statusColors`
  - 409 conflict handling on duplicate fingerprint
  - `formatApiError()` for 422 validation error display
- **`src/features/fetch-requests/fetch-requests.models.ts`** — Added types:
  - `paused` to `FetchRequestStatus`
  - `FetchRequestUpdate` interface
  - `retry_count` to `FetchRequest` interface
  - `raw_lines`, `txn_blocks`, `txn_dicts`, `txn_dict_count`/`txn_dicts_count` to source types
  - `PendingAmbiguity`, `AmbiguityCandidate`, `ResolveAmbiguityPayload`
  - `SSEEvent`, `SSEEventStep`, `SSEEventStatus`, `ProgressMessage`
  - `FetchRequestFilters`
  - `formatApiError()` helper for FastAPI 422 error parsing
  - `RETRY_MAX = 3` constant
- **`src/features/fetch-requests/index.ts`** — Barrel exports for all new types, hooks, and helpers
- **`src/features/fetch-requests/useFetchRequests.ts`** — Added hooks:
  - `useUpdateFetchRequest()` — PATCH via `usePatch`
  - `useFetchRequestAmbiguities(id)` — queries `/fetch-requests/:id/ambiguities`
  - `useResolveAmbiguity()` — posts to `/ambiguities/:id/resolve` with cache invalidation
- **`src/main.jsx`** — Added route `/fetch-requests/:id` → `FetchRequestDetail`

## Key decisions

- SSE event stream is the single source of truth for progress; REST is only fallback for page load
- Stepper shows granular ratio-based progress counts (e.g. `150/246` for enrich)
- `pipeline/failed` SSE event triggers refetch + error snackbar
- `load_content` events excluded from event feed entirely
- Enrich/Save progress counts come only from SSE (no REST fallback since those phases don't pause)

Reviewed-on: #8
Co-authored-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
Co-committed-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
aetos changed title from WIP: fetch-request-steps-ui to Fetch Request UI 2026-05-31 09:26:56 +00:00
aetos merged commit 5cf2a4c3c4 into main 2026-05-31 09:28:27 +00:00
aetos deleted branch fetch-request-steps-ui 2026-05-31 09:28:27 +00:00
aetos referenced this issue from a commit 2026-05-31 09:28:29 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: apps/khata-ui#9
No description provided.