open-notebook/claude-goal.md

47 lines
2.8 KiB
Markdown

# Goal: Fix Source List Auto-Refresh After Adding New Source
## Issue Reference
GitHub Issue: #526
## Problem
When a user adds a new source to a notebook (via URL, file upload, or text), the source list in the notebook page does not auto-refresh. The user sees a toast notification saying "Source Queued" but must manually refresh the browser to see the new source appear in the list.
## Root Cause
The notebook page uses `useNotebookSources()` which queries with key `QUERY_KEYS.sourcesInfinite(notebookId)` = `['sources', 'infinite', notebookId]`.
However, the mutation hooks that create sources only invalidate different query keys:
- `useCreateSource` invalidates `QUERY_KEYS.sources(notebookId)` = `['sources', notebookId]`
- `useFileUpload` invalidates `QUERY_KEYS.sources(variables.notebookId)` = `['sources', notebookId]`
React Query's prefix matching does NOT cascade from `['sources', notebookId]` to `['sources', 'infinite', notebookId]` because the second element differs (`notebookId` vs `'infinite'`).
Note: Other hooks like `useDeleteSource`, `useUpdateSource`, etc. correctly use `queryClient.invalidateQueries({ queryKey: ['sources'] })` which IS a prefix of all source queries and does cascade properly.
## Fix
Add `sourcesInfinite` query key invalidation in both `useCreateSource` and `useFileUpload` hooks in `frontend/src/lib/hooks/use-sources.ts`.
### Key Files
- `frontend/src/lib/hooks/use-sources.ts` - Contains all source mutation hooks (main fix location)
- `frontend/src/lib/api/query-client.ts` - Defines `QUERY_KEYS` including `sourcesInfinite`
- `frontend/src/app/(dashboard)/notebooks/[id]/page.tsx` - Notebook page that uses `useNotebookSources`
- `frontend/src/app/(dashboard)/notebooks/components/SourcesColumn.tsx` - Source list UI component
### Implementation Details
**In `useCreateSource` (line ~89-139)**:
After each `QUERY_KEYS.sources(notebookId)` invalidation, also invalidate `QUERY_KEYS.sourcesInfinite(notebookId)`.
**In `useFileUpload` (line ~195-220)**:
After `QUERY_KEYS.sources(variables.notebookId)` invalidation, also invalidate `QUERY_KEYS.sourcesInfinite(variables.notebookId)`.
### Why This Works
- The backend creates the source record immediately (even for async processing, with title "Processing...")
- The source is linked to the notebook immediately
- So invalidating the query will refetch and show the new source
- `SourceCard` already has `useSourceStatus()` that polls every 2 seconds during processing, so the status will auto-update
### Gotchas
- No need for polling/delays - the source record exists in DB when the API returns
- No need for WebSocket/SSE - simple cache invalidation is sufficient
- The async path creates a minimal source with "Processing..." title that gets updated when processing completes
- `SourceCard` already handles status polling via `useSourceStatus()` hook