mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-01-04 03:25:30 +08:00
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:
@ -1,3 +1,7 @@
|
||||
import {
|
||||
ConfirmDeleteDialog,
|
||||
ConfirmDeleteDialogNode,
|
||||
} from '@/components/confirm-delete-dialog';
|
||||
import EditTag from '@/components/edit-tag';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
@ -7,6 +11,7 @@ import { Textarea } from '@/components/ui/textarea';
|
||||
import { Plus, Trash2 } from 'lucide-react';
|
||||
import { memo, useCallback, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MetadataType } from './hook';
|
||||
import { IManageValuesProps, IMetaDataTableData } from './interface';
|
||||
|
||||
// Create a separate input component, wrapped with memo to avoid unnecessary re-renders
|
||||
@ -63,17 +68,62 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
|
||||
onSave,
|
||||
addUpdateValue,
|
||||
addDeleteValue,
|
||||
existsKeys,
|
||||
type,
|
||||
} = props;
|
||||
const [metaData, setMetaData] = useState(data);
|
||||
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
|
||||
const handleChange = useCallback((field: string, value: any) => {
|
||||
setMetaData((prev) => ({
|
||||
...prev,
|
||||
[field]: value,
|
||||
}));
|
||||
}, []);
|
||||
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) => ({
|
||||
...prev,
|
||||
[field]: value,
|
||||
}));
|
||||
},
|
||||
[existsKeys, type, t],
|
||||
);
|
||||
|
||||
// Maintain separate state for each input box
|
||||
const [tempValues, setTempValues] = useState<string[]>([...data.values]);
|
||||
@ -89,6 +139,9 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
|
||||
}, [hideModal]);
|
||||
|
||||
const handleSave = useCallback(() => {
|
||||
if (type === MetadataType.Setting && valueError.field) {
|
||||
return;
|
||||
}
|
||||
if (!metaData.restrictDefinedValues && isShowValueSwitch) {
|
||||
const newMetaData = { ...metaData, values: [] };
|
||||
onSave(newMetaData);
|
||||
@ -96,17 +149,35 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
|
||||
onSave(metaData);
|
||||
}
|
||||
handleHideModal();
|
||||
}, [metaData, onSave, handleHideModal, isShowValueSwitch]);
|
||||
}, [metaData, onSave, handleHideModal, isShowValueSwitch, type, valueError]);
|
||||
|
||||
// Handle value changes, only update temporary state
|
||||
const handleValueChange = useCallback((index: number, value: string) => {
|
||||
setTempValues((prev) => {
|
||||
const newValues = [...prev];
|
||||
newValues[index] = value;
|
||||
const handleValueChange = useCallback(
|
||||
(index: number, value: string) => {
|
||||
setTempValues((prev) => {
|
||||
if (prev.includes(value)) {
|
||||
setValueError((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
values: t('knowledgeDetails.metadata.valueExists'),
|
||||
};
|
||||
});
|
||||
} else {
|
||||
setValueError((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
values: '',
|
||||
};
|
||||
});
|
||||
}
|
||||
const newValues = [...prev];
|
||||
newValues[index] = value;
|
||||
|
||||
return newValues;
|
||||
});
|
||||
}, []);
|
||||
return newValues;
|
||||
});
|
||||
},
|
||||
[t],
|
||||
);
|
||||
|
||||
// Handle blur event, synchronize to main state
|
||||
const handleValueBlur = useCallback(() => {
|
||||
@ -137,6 +208,27 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
|
||||
[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
|
||||
const handleAddValue = useCallback(() => {
|
||||
setTempValues((prev) => [...new Set([...prev, ''])]);
|
||||
@ -172,9 +264,13 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
|
||||
<Input
|
||||
value={metaData.field}
|
||||
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>
|
||||
)}
|
||||
@ -230,7 +326,11 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
|
||||
item={item}
|
||||
index={index}
|
||||
onValueChange={handleValueChange}
|
||||
onDelete={handleDelete}
|
||||
onDelete={(idx: number) => {
|
||||
showDeleteModal(item, () => {
|
||||
handleDelete(idx);
|
||||
});
|
||||
}}
|
||||
onBlur={handleValueBlur}
|
||||
/>
|
||||
);
|
||||
@ -240,11 +340,41 @@ export const ManageValuesModal = (props: IManageValuesProps) => {
|
||||
{!isVerticalShowValue && (
|
||||
<EditTag
|
||||
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>
|
||||
)}
|
||||
{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>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user