Fix: Add prompts when merging or deleting metadata. (#12138)

### What problem does this PR solve?

Fix: Add prompts when merging or deleting metadata.

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)

---------

Co-authored-by: Kevin Hu <kevinhu.sh@gmail.com>
This commit is contained in:
chanx
2025-12-24 09:32:41 +08:00
committed by GitHub
parent c33134ea2c
commit d72debf0db
11 changed files with 322 additions and 100 deletions

View File

@ -35,6 +35,7 @@ import { cn } from '@/lib/utils';
import { t } from 'i18next'; import { t } from 'i18next';
import { Loader } from 'lucide-react'; import { Loader } from 'lucide-react';
import { MultiSelect, MultiSelectOptionType } from './ui/multi-select'; import { MultiSelect, MultiSelectOptionType } from './ui/multi-select';
import { Switch } from './ui/switch';
// Field type enumeration // Field type enumeration
export enum FormFieldType { export enum FormFieldType {
@ -46,6 +47,7 @@ export enum FormFieldType {
Select = 'select', Select = 'select',
MultiSelect = 'multi-select', MultiSelect = 'multi-select',
Checkbox = 'checkbox', Checkbox = 'checkbox',
Switch = 'switch',
Tag = 'tag', Tag = 'tag',
Custom = 'custom', Custom = 'custom',
} }
@ -154,6 +156,7 @@ export const generateSchema = (fields: FormFieldConfig[]): ZodSchema<any> => {
} }
break; break;
case FormFieldType.Checkbox: case FormFieldType.Checkbox:
case FormFieldType.Switch:
fieldSchema = z.boolean(); fieldSchema = z.boolean();
break; break;
case FormFieldType.Tag: case FormFieldType.Tag:
@ -193,6 +196,8 @@ export const generateSchema = (fields: FormFieldConfig[]): ZodSchema<any> => {
if ( if (
field.type !== FormFieldType.Number && field.type !== FormFieldType.Number &&
field.type !== FormFieldType.Checkbox && field.type !== FormFieldType.Checkbox &&
field.type !== FormFieldType.Switch &&
field.type !== FormFieldType.Custom &&
field.type !== FormFieldType.Tag && field.type !== FormFieldType.Tag &&
field.required field.required
) { ) {
@ -289,7 +294,10 @@ const generateDefaultValues = <T extends FieldValues>(
const lastKey = keys[keys.length - 1]; const lastKey = keys[keys.length - 1];
if (field.defaultValue !== undefined) { if (field.defaultValue !== undefined) {
current[lastKey] = field.defaultValue; current[lastKey] = field.defaultValue;
} else if (field.type === FormFieldType.Checkbox) { } else if (
field.type === FormFieldType.Checkbox ||
field.type === FormFieldType.Switch
) {
current[lastKey] = false; current[lastKey] = false;
} else if (field.type === FormFieldType.Tag) { } else if (field.type === FormFieldType.Tag) {
current[lastKey] = []; current[lastKey] = [];
@ -299,7 +307,10 @@ const generateDefaultValues = <T extends FieldValues>(
} else { } else {
if (field.defaultValue !== undefined) { if (field.defaultValue !== undefined) {
defaultValues[field.name] = field.defaultValue; defaultValues[field.name] = field.defaultValue;
} else if (field.type === FormFieldType.Checkbox) { } else if (
field.type === FormFieldType.Checkbox ||
field.type === FormFieldType.Switch
) {
defaultValues[field.name] = false; defaultValues[field.name] = false;
} else if ( } else if (
field.type === FormFieldType.Tag || field.type === FormFieldType.Tag ||
@ -502,6 +513,32 @@ export const RenderField = ({
)} )}
/> />
); );
case FormFieldType.Switch:
return (
<RAGFlowFormItem
{...field}
labelClassName={labelClassName || field.labelClassName}
>
{(fieldProps) => {
const finalFieldProps = field.onChange
? {
...fieldProps,
onChange: (checked: boolean) => {
fieldProps.onChange(checked);
field.onChange?.(checked);
},
}
: fieldProps;
return (
<Switch
checked={finalFieldProps.value as boolean}
onCheckedChange={(checked) => finalFieldProps.onChange(checked)}
disabled={field.disabled}
/>
);
}}
</RAGFlowFormItem>
);
case FormFieldType.Tag: case FormFieldType.Tag:
return ( return (

View File

@ -31,14 +31,16 @@ const handleCheckChange = ({
(value: string) => value !== item.id.toString(), (value: string) => value !== item.id.toString(),
); );
const newValue = { const newValue = newParentValues?.length
? {
...currentValue, ...currentValue,
[parentId]: newParentValues, [parentId]: newParentValues,
};
if (newValue[parentId].length === 0) {
delete newValue[parentId];
} }
: { ...currentValue };
// if (newValue[parentId].length === 0) {
// delete newValue[parentId];
// }
return field.onChange(newValue); return field.onChange(newValue);
} else { } else {
@ -66,20 +68,31 @@ const FilterItem = memo(
}) => { }) => {
return ( return (
<div <div
className={`flex items-center justify-between text-text-primary text-xs ${level > 0 ? 'ml-4' : ''}`} className={`flex items-center justify-between text-text-primary text-xs ${level > 0 ? 'ml-1' : ''}`}
> >
<FormItem className="flex flex-row space-x-3 space-y-0 items-center "> <FormItem className="flex flex-row space-x-3 space-y-0 items-center ">
<FormControl> <FormControl>
<div className="flex space-x-3">
<Checkbox <Checkbox
checked={field.value?.includes(item.id.toString())} checked={field.value?.includes(item.id.toString())}
onCheckedChange={(checked: boolean) => onCheckedChange={(checked: boolean) =>
handleCheckChange({ checked, field, item }) handleCheckChange({ checked, field, item })
} }
// className="hidden group-hover:block"
/> />
</FormControl> <FormLabel
<FormLabel onClick={(e) => e.stopPropagation()}> onClick={() =>
handleCheckChange({
checked: !field.value?.includes(item.id.toString()),
field,
item,
})
}
>
{item.label} {item.label}
</FormLabel> </FormLabel>
</div>
</FormControl>
</FormItem> </FormItem>
{item.count !== undefined && ( {item.count !== undefined && (
<span className="text-sm">{item.count}</span> <span className="text-sm">{item.count}</span>
@ -107,11 +120,11 @@ export const FilterField = memo(
<FormField <FormField
key={item.id} key={item.id}
control={form.control} control={form.control}
name={parent.field as string} name={parent.field?.toString() as string}
render={({ field }) => { render={({ field }) => {
if (hasNestedList) { if (hasNestedList) {
return ( return (
<div className={`flex flex-col gap-2 ${level > 0 ? 'ml-4' : ''}`}> <div className={`flex flex-col gap-2 ${level > 0 ? 'ml-1' : ''}`}>
<div <div
className="flex items-center justify-between cursor-pointer" className="flex items-center justify-between cursor-pointer"
onClick={() => { onClick={() => {
@ -138,23 +151,6 @@ export const FilterField = memo(
}} }}
level={level + 1} level={level + 1}
/> />
// <FilterItem key={child.id} item={child} field={child.field} level={level+1} />
// <div
// className="flex flex-row space-x-3 space-y-0 items-center"
// key={child.id}
// >
// <FormControl>
// <Checkbox
// checked={field.value?.includes(child.id.toString())}
// onCheckedChange={(checked) =>
// handleCheckChange({ checked, field, item: child })
// }
// />
// </FormControl>
// <FormLabel onClick={(e) => e.stopPropagation()}>
// {child.label}
// </FormLabel>
// </div>
))} ))}
</div> </div>
); );

View File

@ -11,7 +11,7 @@ import {
useMemo, useMemo,
useState, useState,
} from 'react'; } from 'react';
import { useForm } from 'react-hook-form'; import { FieldPath, useForm } from 'react-hook-form';
import { ZodArray, ZodString, z } from 'zod'; import { ZodArray, ZodString, z } from 'zod';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
@ -178,7 +178,9 @@ function CheckboxFormMultiple({
<FormField <FormField
key={x.field} key={x.field}
control={form.control} control={form.control}
name={x.field} name={
x.field.toString() as FieldPath<z.infer<typeof FormSchema>>
}
render={() => ( render={() => (
<FormItem className="space-y-4"> <FormItem className="space-y-4">
<div> <div>
@ -186,7 +188,8 @@ function CheckboxFormMultiple({
{x.label} {x.label}
</FormLabel> </FormLabel>
</div> </div>
{x.list.map((item) => { {x.list?.length &&
x.list.map((item) => {
return ( return (
<FilterField <FilterField
key={item.id} key={item.id}

View File

@ -176,6 +176,11 @@ Procedural Memory: Learned skills, habits, and automated procedures.`,
}, },
knowledgeDetails: { knowledgeDetails: {
metadata: { metadata: {
valueExists:
'Value already exists. Confirm to merge duplicates and combine all associated files.',
fieldNameExists:
'Field name already exists. Confirm to merge duplicates and combine all associated files.',
fieldExists: 'Field already exists.',
fieldSetting: 'Field settings', fieldSetting: 'Field settings',
changesAffectNewParses: 'Changes affect new parses only.', changesAffectNewParses: 'Changes affect new parses only.',
editMetadataForDataset: 'View and edit metadata for ', editMetadataForDataset: 'View and edit metadata for ',
@ -190,6 +195,7 @@ Procedural Memory: Learned skills, habits, and automated procedures.`,
description: 'Description', description: 'Description',
fieldName: 'Field name', fieldName: 'Field name',
editMetadata: 'Edit metadata', editMetadata: 'Edit metadata',
deleteWarn: 'This {{field}} will be removed from all associated files',
}, },
metadataField: 'Metadata field', metadataField: 'Metadata field',
systemAttribute: 'System attribute', systemAttribute: 'System attribute',

View File

@ -182,6 +182,10 @@ export default {
description: '描述', description: '描述',
fieldName: '字段名', fieldName: '字段名',
editMetadata: '编辑元数据', editMetadata: '编辑元数据',
valueExists: '值已存在。确认合并重复项并组合所有关联文件。',
fieldNameExists: '字段名已存在。确认合并重复项并组合所有关联文件。',
fieldExists: '字段名已存在。',
deleteWarn: '此 {{field}} 将从所有关联文件中移除',
}, },
localUpload: '本地上传', localUpload: '本地上传',
fileSize: '文件大小', fileSize: '文件大小',

View File

@ -1,11 +1,14 @@
import message from '@/components/ui/message'; import message from '@/components/ui/message';
import { useSetModalState } from '@/hooks/common-hooks'; import { useSetModalState } from '@/hooks/common-hooks';
import { useSetDocumentMeta } from '@/hooks/use-document-request'; import {
DocumentApiAction,
useSetDocumentMeta,
} from '@/hooks/use-document-request';
import kbService, { import kbService, {
getMetaDataService, getMetaDataService,
updateMetaData, updateMetaData,
} from '@/services/knowledge-service'; } from '@/services/knowledge-service';
import { useQuery } from '@tanstack/react-query'; import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useParams } from 'umi'; import { useParams } from 'umi';
@ -191,7 +194,7 @@ export const useManageMetaDataModal = (
const { data, loading } = useFetchMetaDataManageData(type); const { data, loading } = useFetchMetaDataManageData(type);
const [tableData, setTableData] = useState<IMetaDataTableData[]>(metaData); const [tableData, setTableData] = useState<IMetaDataTableData[]>(metaData);
const queryClient = useQueryClient();
const { operations, addDeleteRow, addDeleteValue, addUpdateValue } = const { operations, addDeleteRow, addDeleteValue, addUpdateValue } =
useMetadataOperations(); useMetadataOperations();
@ -259,11 +262,14 @@ export const useManageMetaDataModal = (
data: operations, data: operations,
}); });
if (res.code === 0) { if (res.code === 0) {
queryClient.invalidateQueries({
queryKey: [DocumentApiAction.FetchDocumentList],
});
message.success(t('message.operated')); message.success(t('message.operated'));
callback(); callback();
} }
}, },
[operations, id, t], [operations, id, t, queryClient],
); );
const handleSaveUpdateSingle = useCallback( const handleSaveUpdateSingle = useCallback(

View File

@ -39,6 +39,7 @@ export type IManageModalProps = {
export interface IManageValuesProps { export interface IManageValuesProps {
title: ReactNode; title: ReactNode;
existsKeys: string[];
visible: boolean; visible: boolean;
isEditField?: boolean; isEditField?: boolean;
isAddValue?: boolean; isAddValue?: boolean;
@ -46,6 +47,7 @@ export interface IManageValuesProps {
isShowValueSwitch?: boolean; isShowValueSwitch?: boolean;
isVerticalShowValue?: boolean; isVerticalShowValue?: boolean;
data: IMetaDataTableData; data: IMetaDataTableData;
type: MetadataType;
hideModal: () => void; hideModal: () => void;
onSave: (data: IMetaDataTableData) => void; onSave: (data: IMetaDataTableData) => void;
addUpdateValue: (key: string, value: string | string[]) => void; addUpdateValue: (key: string, value: string | string[]) => void;

View File

@ -54,6 +54,7 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
values: [], values: [],
}); });
const [currentValueIndex, setCurrentValueIndex] = useState<number>(0);
const [deleteDialogContent, setDeleteDialogContent] = useState({ const [deleteDialogContent, setDeleteDialogContent] = useState({
visible: false, visible: false,
title: '', title: '',
@ -94,12 +95,12 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
description: '', description: '',
values: [], values: [],
}); });
// setCurrentValueIndex(tableData.length || 0); setCurrentValueIndex(tableData.length || 0);
showManageValuesModal(); showManageValuesModal();
}; };
const handleEditValueRow = useCallback( const handleEditValueRow = useCallback(
(data: IMetaDataTableData) => { (data: IMetaDataTableData, index: number) => {
// setCurrentValueIndex(index); setCurrentValueIndex(index);
setValueData(data); setValueData(data);
showManageValuesModal(); showManageValuesModal();
}, },
@ -153,10 +154,33 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
variant={'delete'} variant={'delete'}
className="p-0 bg-transparent" className="p-0 bg-transparent"
onClick={() => { onClick={() => {
setDeleteDialogContent({
visible: true,
title:
t('common.delete') +
' ' +
t('knowledgeDetails.metadata.metadata'),
name: row.getValue('field') + '/' + value,
warnText: t(
'knowledgeDetails.metadata.deleteWarn',
{
field:
t('knowledgeDetails.metadata.field') +
'/' +
t('knowledgeDetails.metadata.values'),
},
),
onOk: () => {
hideDeleteModal();
handleDeleteSingleValue( handleDeleteSingleValue(
row.getValue('field'), row.getValue('field'),
value, value,
); );
},
onCancel: () => {
hideDeleteModal();
},
});
}} }}
> >
<Trash2 /> <Trash2 />
@ -185,7 +209,7 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
variant={'ghost'} variant={'ghost'}
className="bg-transparent px-1 py-0" className="bg-transparent px-1 py-0"
onClick={() => { onClick={() => {
handleEditValueRow(row.original); handleEditValueRow(row.original, row.index);
}} }}
> >
<Settings /> <Settings />
@ -201,7 +225,9 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
' ' + ' ' +
t('knowledgeDetails.metadata.metadata'), t('knowledgeDetails.metadata.metadata'),
name: row.getValue('field'), name: row.getValue('field'),
warnText: t('knowledgeDetails.metadata.deleteWarn'), warnText: t('knowledgeDetails.metadata.deleteWarn', {
field: t('knowledgeDetails.metadata.field'),
}),
onOk: () => { onOk: () => {
hideDeleteModal(); hideDeleteModal();
handleDeleteSingleRow(row.getValue('field')); handleDeleteSingleRow(row.getValue('field'));
@ -243,12 +269,26 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
const handleSaveValues = (data: IMetaDataTableData) => { const handleSaveValues = (data: IMetaDataTableData) => {
setTableData((prev) => { setTableData((prev) => {
//If the keys are the same, they need to be merged. let newData;
const fieldMap = new Map<string, any>(); if (currentValueIndex >= prev.length) {
// Add operation
newData = [...prev, data];
} else {
// Edit operation
newData = prev.map((item, index) => {
if (index === currentValueIndex) {
return data;
}
return item;
});
}
prev.forEach((item) => { // Deduplicate by field and merge values
const fieldMap = new Map<string, IMetaDataTableData>();
newData.forEach((item) => {
if (fieldMap.has(item.field)) { if (fieldMap.has(item.field)) {
const existingItem = fieldMap.get(item.field); // Merge values if field exists
const existingItem = fieldMap.get(item.field)!;
const mergedValues = [ const mergedValues = [
...new Set([...existingItem.values, ...item.values]), ...new Set([...existingItem.values, ...item.values]),
]; ];
@ -258,20 +298,14 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
} }
}); });
if (fieldMap.has(data.field)) {
const existingItem = fieldMap.get(data.field);
const mergedValues = [
...new Set([...existingItem.values, ...data.values]),
];
fieldMap.set(data.field, { ...existingItem, values: mergedValues });
} else {
fieldMap.set(data.field, data);
}
return Array.from(fieldMap.values()); return Array.from(fieldMap.values());
}); });
}; };
const existsKeys = useMemo(() => {
return tableData.map((item) => item.field);
}, [tableData]);
return ( return (
<> <>
<Modal <Modal
@ -357,6 +391,8 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
: t('knowledgeDetails.metadata.editMetadata')} : t('knowledgeDetails.metadata.editMetadata')}
</div> </div>
} }
type={metadataType}
existsKeys={existsKeys}
visible={manageValuesVisible} visible={manageValuesVisible}
hideModal={hideManageValuesModal} hideModal={hideManageValuesModal}
data={valueData} data={valueData}

View File

@ -1,3 +1,7 @@
import {
ConfirmDeleteDialog,
ConfirmDeleteDialogNode,
} from '@/components/confirm-delete-dialog';
import EditTag from '@/components/edit-tag'; import EditTag from '@/components/edit-tag';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
@ -7,6 +11,7 @@ import { Textarea } from '@/components/ui/textarea';
import { Plus, Trash2 } from 'lucide-react'; import { Plus, Trash2 } from 'lucide-react';
import { memo, useCallback, useEffect, useState } from 'react'; import { memo, useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { MetadataType } from './hook';
import { IManageValuesProps, IMetaDataTableData } from './interface'; import { IManageValuesProps, IMetaDataTableData } from './interface';
// Create a separate input component, wrapped with memo to avoid unnecessary re-renders // Create a separate input component, wrapped with memo to avoid unnecessary re-renders
@ -63,17 +68,62 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
onSave, onSave,
addUpdateValue, addUpdateValue,
addDeleteValue, addDeleteValue,
existsKeys,
type,
} = props; } = props;
const [metaData, setMetaData] = useState(data); const [metaData, setMetaData] = useState(data);
const { t } = useTranslation(); const { t } = useTranslation();
const [valueError, setValueError] = useState<Record<string, string>>({
field: '',
values: '',
});
const [deleteDialogContent, setDeleteDialogContent] = useState({
visible: false,
title: '',
name: '',
warnText: '',
onOk: () => {},
onCancel: () => {},
});
const hideDeleteModal = () => {
setDeleteDialogContent({
visible: false,
title: '',
name: '',
warnText: '',
onOk: () => {},
onCancel: () => {},
});
};
// Use functional update to avoid closure issues // Use functional update to avoid closure issues
const handleChange = useCallback((field: string, value: any) => { const handleChange = useCallback(
(field: string, value: any) => {
if (field === 'field' && existsKeys.includes(value)) {
setValueError((prev) => {
return {
...prev,
field:
type === MetadataType.Setting
? t('knowledgeDetails.metadata.fieldExists')
: t('knowledgeDetails.metadata.fieldNameExists'),
};
});
} else if (field === 'field' && !existsKeys.includes(value)) {
setValueError((prev) => {
return {
...prev,
field: '',
};
});
}
setMetaData((prev) => ({ setMetaData((prev) => ({
...prev, ...prev,
[field]: value, [field]: value,
})); }));
}, []); },
[existsKeys, type, t],
);
// Maintain separate state for each input box // Maintain separate state for each input box
const [tempValues, setTempValues] = useState<string[]>([...data.values]); const [tempValues, setTempValues] = useState<string[]>([...data.values]);
@ -89,6 +139,9 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
}, [hideModal]); }, [hideModal]);
const handleSave = useCallback(() => { const handleSave = useCallback(() => {
if (type === MetadataType.Setting && valueError.field) {
return;
}
if (!metaData.restrictDefinedValues && isShowValueSwitch) { if (!metaData.restrictDefinedValues && isShowValueSwitch) {
const newMetaData = { ...metaData, values: [] }; const newMetaData = { ...metaData, values: [] };
onSave(newMetaData); onSave(newMetaData);
@ -96,17 +149,35 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
onSave(metaData); onSave(metaData);
} }
handleHideModal(); handleHideModal();
}, [metaData, onSave, handleHideModal, isShowValueSwitch]); }, [metaData, onSave, handleHideModal, isShowValueSwitch, type, valueError]);
// Handle value changes, only update temporary state // Handle value changes, only update temporary state
const handleValueChange = useCallback((index: number, value: string) => { const handleValueChange = useCallback(
(index: number, value: string) => {
setTempValues((prev) => { setTempValues((prev) => {
if (prev.includes(value)) {
setValueError((prev) => {
return {
...prev,
values: t('knowledgeDetails.metadata.valueExists'),
};
});
} else {
setValueError((prev) => {
return {
...prev,
values: '',
};
});
}
const newValues = [...prev]; const newValues = [...prev];
newValues[index] = value; newValues[index] = value;
return newValues; return newValues;
}); });
}, []); },
[t],
);
// Handle blur event, synchronize to main state // Handle blur event, synchronize to main state
const handleValueBlur = useCallback(() => { const handleValueBlur = useCallback(() => {
@ -137,6 +208,27 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
[addDeleteValue, metaData], [addDeleteValue, metaData],
); );
const showDeleteModal = (item: string, callback: () => void) => {
setDeleteDialogContent({
visible: true,
title: t('common.delete') + ' ' + t('knowledgeDetails.metadata.metadata'),
name: metaData.field + '/' + item,
warnText: t('knowledgeDetails.metadata.deleteWarn', {
field:
t('knowledgeDetails.metadata.field') +
'/' +
t('knowledgeDetails.metadata.values'),
}),
onOk: () => {
hideDeleteModal();
callback();
},
onCancel: () => {
hideDeleteModal();
},
});
};
// Handle adding new value // Handle adding new value
const handleAddValue = useCallback(() => { const handleAddValue = useCallback(() => {
setTempValues((prev) => [...new Set([...prev, ''])]); setTempValues((prev) => [...new Set([...prev, ''])]);
@ -172,9 +264,13 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
<Input <Input
value={metaData.field} value={metaData.field}
onChange={(e) => { onChange={(e) => {
handleChange('field', e.target?.value || ''); const value = e.target?.value || '';
if (/^[a-zA-Z_]*$/.test(value)) {
handleChange('field', value);
}
}} }}
/> />
<div className="text-state-error text-sm">{valueError.field}</div>
</div> </div>
</div> </div>
)} )}
@ -230,7 +326,11 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
item={item} item={item}
index={index} index={index}
onValueChange={handleValueChange} onValueChange={handleValueChange}
onDelete={handleDelete} onDelete={(idx: number) => {
showDeleteModal(item, () => {
handleDelete(idx);
});
}}
onBlur={handleValueBlur} onBlur={handleValueBlur}
/> />
); );
@ -240,11 +340,41 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
{!isVerticalShowValue && ( {!isVerticalShowValue && (
<EditTag <EditTag
value={metaData.values} value={metaData.values}
onChange={(value) => handleChange('values', value)} onChange={(value) => {
// find deleted value
const item = metaData.values.find(
(item) => !value.includes(item),
);
if (item) {
showDeleteModal(item, () => {
// handleDelete(idx);
handleChange('values', value);
});
} else {
handleChange('values', value);
}
}}
/> />
)} )}
<div className="text-state-error text-sm">{valueError.values}</div>
</div> </div>
)} )}
{deleteDialogContent.visible && (
<ConfirmDeleteDialog
open={deleteDialogContent.visible}
onCancel={deleteDialogContent.onCancel}
onOk={deleteDialogContent.onOk}
title={deleteDialogContent.title}
content={{
node: (
<ConfirmDeleteDialogNode
name={deleteDialogContent.name}
warnText={deleteDialogContent.warnText}
/>
),
}}
/>
)}
</div> </div>
</Modal> </Modal>
); );

View File

@ -17,6 +17,7 @@ import {
} from '@/components/ui/form'; } from '@/components/ui/form';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { FormLayout } from '@/constants/form'; import { FormLayout } from '@/constants/form';
import { useFetchTenantInfo } from '@/hooks/use-user-setting-request';
import { IModalProps } from '@/interfaces/common'; import { IModalProps } from '@/interfaces/common';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { useEffect } from 'react'; import { useEffect } from 'react';
@ -33,6 +34,7 @@ const FormId = 'dataset-creating-form';
export function InputForm({ onOk }: IModalProps<any>) { export function InputForm({ onOk }: IModalProps<any>) {
const { t } = useTranslation(); const { t } = useTranslation();
const { data: tenantInfo } = useFetchTenantInfo();
const FormSchema = z const FormSchema = z
.object({ .object({
@ -80,7 +82,7 @@ export function InputForm({ onOk }: IModalProps<any>) {
name: '', name: '',
parseType: 1, parseType: 1,
parser_id: '', parser_id: '',
embd_id: '', embd_id: tenantInfo?.embd_id,
}, },
}); });

View File

@ -263,7 +263,7 @@ export const documentFilter = (kb_id: string) =>
export const getMetaDataService = ({ kb_id }: { kb_id: string }) => export const getMetaDataService = ({ kb_id }: { kb_id: string }) =>
request.post(api.getMetaData, { data: { kb_id } }); request.post(api.getMetaData, { data: { kb_id } });
export const updateMetaData = ({ kb_id, data }: { kb_id: string; data: any }) => export const updateMetaData = ({ kb_id, data }: { kb_id: string; data: any }) =>
request.post(api.updateMetaData, { data: { kb_id, data } }); request.post(api.updateMetaData, { data: { kb_id, ...data } });
export const listDataPipelineLogDocument = ( export const listDataPipelineLogDocument = (
params?: IFetchKnowledgeListRequestParams, params?: IFetchKnowledgeListRequestParams,