Fix #14801 to allow search dataset list when add (#14841)

### What problem does this PR solve?

Fix #14801 to allow search dataset list when add, following on #14825

<img width="2172" height="857" alt="image"
src="https://github.com/user-attachments/assets/65ea7647-56f4-4c16-8437-121b834811f0"
/>


### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
Wang Qi
2026-05-12 19:36:23 +08:00
committed by GitHub
parent 3f41f8cfae
commit 76d5240fb5
3 changed files with 88 additions and 15 deletions

View File

@@ -2,8 +2,9 @@ import { DocumentParserType } from '@/constants/knowledge';
import { useFetchKnowledgeList } from '@/hooks/use-knowledge-request';
import { IDataset } from '@/interfaces/database/dataset';
import { useBuildQueryVariableOptions } from '@/pages/agent/hooks/use-get-begin-query';
import { useDebounce } from 'ahooks';
import { toLower } from 'lodash';
import { useMemo } from 'react';
import { type ReactNode, useCallback, useMemo, useRef, useState } from 'react';
import { useFormContext, useWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { RAGFlowAvatar } from './ragflow-avatar';
@@ -23,17 +24,43 @@ function DatasetLabel({ text }: { text: string }) {
}
export function useDisableDifferenceEmbeddingDataset(name: string) {
const { list: datasetListOrigin } = useFetchKnowledgeList(true);
const form = useFormContext();
const datasetId = useWatch({ name, control: form.control });
const [searchString, setSearchString] = useState('');
const debouncedSearchString = useDebounce(searchString, { wait: 500 });
const { list: datasetListOrigin, loading } = useFetchKnowledgeList(
true,
debouncedSearchString,
);
const datasetCacheRef = useRef(new Map<string, IDataset>());
const selectedEmbedId = useMemo(() => {
const data = datasetListOrigin?.find((item) => item.id === datasetId?.[0]);
return data?.embedding_model ?? '';
const datasetList = useMemo(() => {
datasetListOrigin.forEach((dataset) => {
datasetCacheRef.current.set(dataset.id, dataset);
});
const selectedDatasetIds = Array.isArray(datasetId) ? datasetId : [];
const selectedDatasets = selectedDatasetIds
.map((id) => datasetCacheRef.current.get(id))
.filter(Boolean) as IDataset[];
return Array.from(
new Map(
[...datasetListOrigin, ...selectedDatasets].map((dataset) => [
dataset.id,
dataset,
]),
).values(),
);
}, [datasetId, datasetListOrigin]);
const selectedEmbedId = useMemo(() => {
const data = datasetList?.find((item) => item.id === datasetId?.[0]);
return data?.embedding_model ?? '';
}, [datasetId, datasetList]);
const nextOptions = useMemo(() => {
const datasetListMap = datasetListOrigin
const datasetListMap = datasetList
.filter((x) => x.chunk_method !== DocumentParserType.Tag)
.map((item: IDataset) => {
return {
@@ -58,10 +85,17 @@ export function useDisableDifferenceEmbeddingDataset(name: string) {
});
return datasetListMap;
}, [datasetListOrigin, selectedEmbedId]);
}, [datasetList, selectedEmbedId]);
const handleSearchChange = useCallback((value: string) => {
setSearchString(value);
}, []);
return {
datasetOptions: nextOptions,
handleSearchChange,
loading,
searchString,
};
}
@@ -76,7 +110,8 @@ export function KnowledgeBaseFormField({
}) {
const { t } = useTranslation();
const { datasetOptions } = useDisableDifferenceEmbeddingDataset(name);
const { datasetOptions, handleSearchChange, loading, searchString } =
useDisableDifferenceEmbeddingDataset(name);
const nextOptions = buildQueryVariableOptionsByShowVariable(showVariable)();
@@ -89,17 +124,26 @@ export function KnowledgeBaseFormField({
options: knowledgeOptions,
},
...nextOptions.map((x) => {
const groupLabel = (('label' in x
? x.label
: 'title' in x
? x.title
: '') ?? '') as ReactNode;
return {
...x,
label: groupLabel,
options: x.options
.filter((y) => toLower(y.type).includes('string'))
.map((x) => ({
...x,
label: x.label ?? x.value ?? '',
value: x.value ?? '',
icon: () => (
<RAGFlowAvatar
className="size-4 mr-2"
avatar={x.label}
name={x.label}
avatar={String(x.label ?? '')}
name={String(x.label ?? '')}
/>
),
})),
@@ -130,6 +174,10 @@ export function KnowledgeBaseFormField({
showSelectAll={false}
popoverTestId="datasets-options"
optionTestIdPrefix="datasets"
searchValue={searchString}
onSearchChange={handleSearchChange}
isSearching={loading}
shouldFilter={false}
{...field}
/>
)}

View File

@@ -188,6 +188,10 @@ interface MultiSelectProps
showSelectAll?: boolean;
popoverTestId?: string;
optionTestIdPrefix?: string;
searchValue?: string;
onSearchChange?: (value: string) => void;
isSearching?: boolean;
shouldFilter?: boolean;
}
export const MultiSelect = React.forwardRef<
@@ -209,6 +213,10 @@ export const MultiSelect = React.forwardRef<
showSelectAll = true,
popoverTestId,
optionTestIdPrefix,
searchValue,
onSearchChange,
isSearching = false,
shouldFilter,
...props
},
ref,
@@ -434,15 +442,19 @@ export const MultiSelect = React.forwardRef<
onEscapeKeyDown={() => setIsPopoverOpen(false)}
data-testid={popoverTestId}
>
<Command className="p-5 pb-8">
{options && options.length > 0 && (
<Command className="p-5 pb-8" shouldFilter={shouldFilter}>
{((options && options.length > 0) || onSearchChange) && (
<CommandInput
placeholder={t('common.search') + '...'}
onKeyDown={handleInputKeyDown}
value={searchValue}
onValueChange={onSearchChange}
/>
)}
<CommandList className="mt-2">
<CommandEmpty>No results found.</CommandEmpty>
<CommandEmpty>
{isSearching ? t('common.searching') : t('common.noDataFound')}
</CommandEmpty>
<CommandGroup>
{showSelectAll && options && options.length > 0 && (
<CommandItem

View File

@@ -424,16 +424,29 @@ export const useRemoveKnowledgeGraph = () => {
export const useFetchKnowledgeList = (
shouldFilterListWithoutDocument: boolean = false,
keywords = '',
): {
list: IDataset[];
loading: boolean;
} => {
const { data, isFetching: loading } = useQuery({
queryKey: [KnowledgeApiAction.FetchKnowledgeList],
queryKey: [
KnowledgeApiAction.FetchKnowledgeList,
shouldFilterListWithoutDocument,
keywords,
],
initialData: [],
gcTime: 0, // https://tanstack.com/query/latest/docs/framework/react/guides/caching?from=reactQueryV3
queryFn: async () => {
const { data } = await listDataset();
const { data } = await listDataset(
keywords
? {
ext: {
keywords,
},
}
: undefined,
);
const list = data?.data ?? [];
return shouldFilterListWithoutDocument
? list.filter((x: IDataset) => x.chunk_count > 0)