diff --git a/web/src/hooks/use-dataset-nav-request.ts b/web/src/hooks/use-dataset-nav-request.ts index 9bed7ddc06..578be4a553 100644 --- a/web/src/hooks/use-dataset-nav-request.ts +++ b/web/src/hooks/use-dataset-nav-request.ts @@ -19,26 +19,32 @@ import { DatasetNavList } from '@/interfaces/database/dataset-nav'; import i18n from '@/locales/config'; import datasetNavService from '@/services/dataset-nav-service'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { trim } from 'lodash'; import { useKnowledgeBaseId } from './use-knowledge-request'; export const DatasetNavKeys = { all: (kbId: string) => ['dataset_nav', kbId] as const, - list: (kbId: string) => ['dataset_nav', kbId, 'list'] as const, + list: (kbId: string, keywords = '') => + ['dataset_nav', kbId, 'list', keywords] as const, children: (kbId: string, name: string) => ['dataset_nav', kbId, 'children', name] as const, }; -export function useFetchDatasetNav() { +export function useFetchDatasetNav(keywords = '') { const kbId = useKnowledgeBaseId(); + const trimmedKeywords = trim(keywords); const { data, isFetching: loading } = useQuery({ - queryKey: DatasetNavKeys.list(kbId), + queryKey: DatasetNavKeys.list(kbId, trimmedKeywords), initialData: null, enabled: !!kbId, gcTime: 0, queryFn: async () => { - const { data } = await datasetNavService.getNav({ datasetId: kbId }); + const { data } = await datasetNavService.getNav({ + datasetId: kbId, + keywords: trimmedKeywords, + }); return data?.data ?? null; }, }); diff --git a/web/src/pages/dataset/compilation/hooks/use-compilation-nav.ts b/web/src/pages/dataset/compilation/hooks/use-compilation-nav.ts index e30562bb07..c499f8b436 100644 --- a/web/src/pages/dataset/compilation/hooks/use-compilation-nav.ts +++ b/web/src/pages/dataset/compilation/hooks/use-compilation-nav.ts @@ -8,6 +8,7 @@ import { useFetchDocumentStructureGraphById } from '@/hooks/use-document-request import { useKnowledgeBaseId } from '@/hooks/use-knowledge-request'; import { DatasetNavNode } from '@/interfaces/database/dataset-nav'; import { IStructureGraphTemplate } from '@/interfaces/database/document-structure'; +import { useDebounce } from 'ahooks'; import { useCallback, useEffect, useState } from 'react'; export interface SelectedNavNode { @@ -23,7 +24,10 @@ export interface SelectedNavNode { export function useCompilationNav() { const kbId = useKnowledgeBaseId(); - const { data: navList, loading: navLoading } = useFetchDatasetNav(); + const [keywords, setKeywords] = useState(''); + const debouncedKeywords = useDebounce(keywords, { wait: 500 }); + const { data: navList, loading: navLoading } = + useFetchDatasetNav(debouncedKeywords); const { deleteNav, loading: deleteNavLoading } = useDeleteDatasetNav(); const { deleteNavNode, loading: deleteNodeLoading } = useDeleteDatasetNavNode(); @@ -125,8 +129,13 @@ export function useCompilationNav() { setLoadingDocId(null); }, []); - // Row click selects the node and shows its description on the right, - // same as a leaf; expansion is handled separately via handleNodeExpand. + const handleKeywordsChange = useCallback( + (e: React.ChangeEvent) => { + setKeywords(e.target.value); + }, + [], + ); + const handleNodeClick = useCallback( (node: DatasetNavNode, parentName: string | null) => { setSelectedNode({ @@ -214,11 +223,13 @@ export function useCompilationNav() { return { navList, navLoading, + keywords, childrenMap, structureMap, selectedNode, deleteNavLoading, deleteNodeLoading, + handleKeywordsChange, handleNodeClick, handleNodeExpand, handleEntityClick, diff --git a/web/src/pages/dataset/compilation/nav-tree-left-panel.tsx b/web/src/pages/dataset/compilation/nav-tree-left-panel.tsx index 49e9f373e4..8e206f663b 100644 --- a/web/src/pages/dataset/compilation/nav-tree-left-panel.tsx +++ b/web/src/pages/dataset/compilation/nav-tree-left-panel.tsx @@ -1,5 +1,6 @@ import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog'; import { Button } from '@/components/ui/button'; +import { SearchInput } from '@/components/ui/input'; import { Spin } from '@/components/ui/spin'; import { TreeView } from '@/components/ui/tree-view'; import { @@ -65,10 +66,12 @@ function NavNodeDeleteAction({ type NavTreeLeftPanelProps = { navList: DatasetNavList | null; navLoading: boolean; + keywords: string; childrenMap: Record; structureMap: Record; deleteNavLoading: boolean; deleteNodeLoading: boolean; + onKeywordsChange: (e: React.ChangeEvent) => void; onNodeClick: (node: DatasetNavNode, parentName: string | null) => void; onNodeExpand: (node: DatasetNavNode) => void; onEntityClick: NavEntityClickHandler; @@ -79,10 +82,12 @@ type NavTreeLeftPanelProps = { export function NavTreeLeftPanel({ navList, navLoading, + keywords, childrenMap, structureMap, deleteNavLoading, deleteNodeLoading, + onKeywordsChange, onNodeClick, onNodeExpand, onEntityClick, @@ -150,6 +155,10 @@ export function NavTreeLeftPanel({ )} +
+ +
+
{navLoading && treeData.length === 0 ? (
diff --git a/web/src/pages/dataset/compilation/nav-tree-view.tsx b/web/src/pages/dataset/compilation/nav-tree-view.tsx index 07bc1c102b..d4166aff23 100644 --- a/web/src/pages/dataset/compilation/nav-tree-view.tsx +++ b/web/src/pages/dataset/compilation/nav-tree-view.tsx @@ -14,11 +14,13 @@ export function NavTreeView() { const { navList, navLoading, + keywords, childrenMap, structureMap, selectedNode, deleteNavLoading, deleteNodeLoading, + handleKeywordsChange, handleNodeClick, handleNodeExpand, handleEntityClick, @@ -33,10 +35,12 @@ export function NavTreeView() { - request.get(api.getDatasetNav(params.datasetId)), + getNav: (params: { datasetId: string; keywords?: string }) => + request.get(api.getDatasetNav(params.datasetId), { + params: { keywords: params.keywords || undefined }, + }), getNavChildren: (params: { datasetId: string; name: string }) => request.get(api.getDatasetNavChildren(params.datasetId, params.name)), deleteNav: (params: { datasetId: string }) =>