Refactor knowledge browser state and dialog#1122
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Refactors the global knowledge browser by splitting orchestration logic into focused hooks and decomposing the knowledge detail dialog into smaller tab components.
Changes:
- Extracted list/detail/delete concerns into
useKnowledgeList,useKnowledgeDetail, anduseKnowledgeDelete(plus a shareduseDebouncedValue). - Simplified
useKnowledgeBrowserto mostly compose the new hooks and manage selection/refresh. - Broke
KnowledgeDetailDialogintoOverviewandGraphtab subcomponents (including a reusable graph preview).
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/features/knowledge/hooks/useKnowledgeList.ts | New list hook w/ debounced query and pagination support. |
| src/features/knowledge/hooks/useKnowledgeDetail.ts | New detail hook for fetching selected knowledge entry details. |
| src/features/knowledge/hooks/useKnowledgeDelete.ts | New delete hook coordinating delete flow + dialog state. |
| src/features/knowledge/hooks/useKnowledgeBrowser.ts | Refactored to compose new hooks and centralize selection handling. |
| src/features/knowledge/hooks/useDebouncedValue.ts | New generic debounce hook used by the list hook. |
| src/features/knowledge/components/knowledge-detail/KnowledgeGraphPreview.tsx | Extracted graph preview rendering for the graph tab. |
| src/features/knowledge/components/knowledge-detail/KnowledgeDetailOverviewTab.tsx | Extracted overview tab UI from the dialog. |
| src/features/knowledge/components/knowledge-detail/KnowledgeDetailGraphTab.tsx | Extracted graph tab UI + relationship list (local entity-name mapping). |
| src/features/knowledge/components/KnowledgeDetailDialog.tsx | Simplified dialog to delegate to the new tab subcomponents. |
| src/features/knowledge/KnowledgePage.tsx | Updated usage to match the refactored dialog/browser state. |
| const loadMore = useCallback(async () => { | ||
| if (isListLoading || isLoadingMore || nextCursor === null) { | ||
| return; | ||
| } | ||
|
|
||
| setIsLoadingMore(true); | ||
| try { | ||
| const response = await listGlobalKnowledge({ | ||
| query: normalizedQuery || undefined, | ||
| assistantId: assistantFilter === 'all' ? undefined : assistantFilter, | ||
| cursor: nextCursor, | ||
| limit: KNOWLEDGE_PAGE_SIZE, | ||
| }); | ||
|
|
||
| setItems((current) => { | ||
| const seenIds = new Set(current.map((item) => item.id)); | ||
| const appendedItems = response.items.filter( | ||
| (item) => !seenIds.has(item.id), | ||
| ); | ||
| return [...current, ...appendedItems]; | ||
| }); | ||
| setNextCursor(response.nextCursor ?? null); |
There was a problem hiding this comment.
loadMore doesn’t have any staleness/cancellation guard. If the user clicks “Load more” and then changes query, assistantFilter, or hits refresh while the request is in-flight, the old response will still append into the new list state, mixing results from different filters. Capture a request key (e.g., {assistantFilter, normalizedQuery}) at invocation and ignore the response if it no longer matches current filters (via a useRef of the latest key), or otherwise prevent filter changes while isLoadingMore is true.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Validation