mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-08-17 22:08:29 +08:00
Feat: The dataset-level tree view supports search. (#18138)
This commit is contained in:
@@ -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;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 }) =>
|
||||
|
||||
Reference in New Issue
Block a user