Skip to content

Commit ffedb2c

Browse files
authored
Feat: The MetadataFilterConditions component supports adding values ​​via search. (#12585)
### What problem does this PR solve? Feat: The MetadataFilterConditions component supports adding values ​​via search. ### Type of change - [x] New Feature (non-breaking change which adds functionality)
1 parent 947e63c commit ffedb2c

3 files changed

Lines changed: 411 additions & 77 deletions

File tree

web/src/components/metadata-filter/metadata-filter-conditions.tsx

Lines changed: 93 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ import { useBuildSwitchOperatorOptions } from '@/hooks/logic-hooks/use-build-ope
2020
import { useFetchKnowledgeMetadata } from '@/hooks/use-knowledge-request';
2121
import { PromptEditor } from '@/pages/agent/form/components/prompt-editor';
2222
import { Plus, X } from 'lucide-react';
23-
import { useCallback } from 'react';
24-
import { useFieldArray, useFormContext } from 'react-hook-form';
23+
import { useCallback, useMemo } from 'react';
24+
import { useFieldArray, useFormContext, useWatch } from 'react-hook-form';
2525
import { useTranslation } from 'react-i18next';
2626
import { LogicalOperator } from '../logical-operator';
27+
import { InputSelect } from '../ui/input-select';
2728

2829
export function MetadataFilterConditions({
2930
kbIds,
@@ -61,6 +62,94 @@ export function MetadataFilterConditions({
6162
[append, fields.length, form, logic],
6263
);
6364

65+
const RenderField = ({
66+
fieldName,
67+
index,
68+
}: {
69+
fieldName: string;
70+
index: number;
71+
}) => {
72+
const form = useFormContext();
73+
const key = useWatch({ name: fieldName });
74+
const valueOptions = useMemo(() => {
75+
if (!key || !metadata?.data || !metadata?.data[key]) return [];
76+
if (typeof metadata?.data[key] === 'object') {
77+
return Object.keys(metadata?.data[key]).map((item: string) => ({
78+
value: item,
79+
label: item,
80+
}));
81+
}
82+
return [];
83+
}, [key]);
84+
85+
return (
86+
<section className="flex gap-2">
87+
<div className="flex-1 flex flex-col gap-2 min-w-0">
88+
<div className="flex items-center gap-1">
89+
<FormField
90+
control={form.control}
91+
name={fieldName}
92+
render={({ field }) => (
93+
<FormItem className="flex-1 overflow-hidden min-w-0">
94+
<FormControl>
95+
<Input
96+
{...field}
97+
placeholder={t('common.pleaseInput')}
98+
></Input>
99+
</FormControl>
100+
<FormMessage />
101+
</FormItem>
102+
)}
103+
/>
104+
<Separator className="w-1 text-text-secondary" />
105+
<FormField
106+
control={form.control}
107+
name={`${name}.${index}.op`}
108+
render={({ field }) => (
109+
<FormItem className="flex-1 overflow-hidden min-w-0">
110+
<FormControl>
111+
<SelectWithSearch
112+
{...field}
113+
options={switchOperatorOptions}
114+
></SelectWithSearch>
115+
</FormControl>
116+
<FormMessage />
117+
</FormItem>
118+
)}
119+
/>
120+
</div>
121+
<FormField
122+
control={form.control}
123+
name={`${name}.${index}.value`}
124+
render={({ field: valueField }) => (
125+
<FormItem className="flex-1 overflow-hidden min-w-0">
126+
<FormControl>
127+
{canReference ? (
128+
<PromptEditor
129+
{...valueField}
130+
multiLine={false}
131+
showToolbar={false}
132+
></PromptEditor>
133+
) : (
134+
<InputSelect
135+
placeholder={t('common.pleaseInput')}
136+
{...valueField}
137+
options={valueOptions}
138+
className="w-full"
139+
/>
140+
)}
141+
</FormControl>
142+
<FormMessage />
143+
</FormItem>
144+
)}
145+
/>
146+
</div>
147+
<Button variant={'ghost'} onClick={() => remove(index)}>
148+
<X className="text-text-sub-title-invert " />
149+
</Button>
150+
</section>
151+
);
152+
};
64153
return (
65154
<section className="flex flex-col gap-2">
66155
<div className="flex items-center justify-between">
@@ -84,73 +173,11 @@ export function MetadataFilterConditions({
84173
</div>
85174
<section className="flex">
86175
{fields.length > 1 && <LogicalOperator name={logic}></LogicalOperator>}
87-
<div className="space-y-5 flex-1">
176+
<div className="space-y-5 flex-1 w-[calc(100%-56px)]">
88177
{fields.map((field, index) => {
89178
const typeField = `${name}.${index}.key`;
90179
return (
91-
<section key={field.id} className="flex gap-2">
92-
<div className="w-full space-y-2">
93-
<div className="flex items-center gap-1">
94-
<FormField
95-
control={form.control}
96-
name={typeField}
97-
render={({ field }) => (
98-
<FormItem className="flex-1 overflow-hidden">
99-
<FormControl>
100-
<Input
101-
{...field}
102-
placeholder={t('common.pleaseInput')}
103-
></Input>
104-
</FormControl>
105-
<FormMessage />
106-
</FormItem>
107-
)}
108-
/>
109-
<Separator className="w-1 text-text-secondary" />
110-
<FormField
111-
control={form.control}
112-
name={`${name}.${index}.op`}
113-
render={({ field }) => (
114-
<FormItem className="flex-1 overflow-hidden">
115-
<FormControl>
116-
<SelectWithSearch
117-
{...field}
118-
options={switchOperatorOptions}
119-
></SelectWithSearch>
120-
</FormControl>
121-
<FormMessage />
122-
</FormItem>
123-
)}
124-
/>
125-
</div>
126-
<FormField
127-
control={form.control}
128-
name={`${name}.${index}.value`}
129-
render={({ field }) => (
130-
<FormItem className="flex-1 overflow-hidden">
131-
<FormControl>
132-
{canReference ? (
133-
<PromptEditor
134-
{...field}
135-
multiLine={false}
136-
showToolbar={false}
137-
></PromptEditor>
138-
) : (
139-
<Input
140-
placeholder={t('common.pleaseInput')}
141-
{...field}
142-
/>
143-
)}
144-
</FormControl>
145-
<FormMessage />
146-
</FormItem>
147-
)}
148-
/>
149-
</div>
150-
<Button variant={'ghost'} onClick={() => remove(index)}>
151-
<X className="text-text-sub-title-invert " />
152-
</Button>
153-
</section>
180+
<RenderField key={field.id} fieldName={typeField} index={index} />
154181
);
155182
})}
156183
</div>

0 commit comments

Comments
 (0)