Feat: The dataset-level tree view supports search. (#18138)

This commit is contained in:
balibabu
2026-08-12 15:34:11 +08:00
committed by GitHub
parent 4a6bed802b
commit 0a7ba32e77
5 changed files with 41 additions and 9 deletions

View File

@@ -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<DatasetNavList | null>({
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;
},
});

View File

@@ -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<HTMLInputElement>) => {
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,

View File

@@ -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<string, DatasetNavNode[]>;
structureMap: Record<string, IStructureGraphTemplate[]>;
deleteNavLoading: boolean;
deleteNodeLoading: boolean;
onKeywordsChange: (e: React.ChangeEvent<HTMLInputElement>) => 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({
)}
</section>
<div className="px-3 pt-2">
<SearchInput value={keywords} onChange={onKeywordsChange} />
</div>
<div className="flex-1 min-h-0 overflow-y-auto px-1 pt-2 pb-3">
{navLoading && treeData.length === 0 ? (
<div className="py-8 flex justify-center">

View File

@@ -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() {
<NavTreeLeftPanel
navList={navList}
navLoading={navLoading}
keywords={keywords}
childrenMap={childrenMap}
structureMap={structureMap}
deleteNavLoading={deleteNavLoading}
deleteNodeLoading={deleteNodeLoading}
onKeywordsChange={handleKeywordsChange}
onNodeClick={handleNodeClick}
onNodeExpand={handleNodeExpand}
onEntityClick={handleEntityClick}

View File

@@ -18,8 +18,10 @@ import api from '@/utils/api';
import request from '@/utils/next-request';
const datasetNavService = {
getNav: (params: { datasetId: string }) =>
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 }) =>