mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-02-02 08:35:08 +08:00
### What problem does this PR solve? Fix: Optimize the metadata code structure to implement metadata list structure functionality. #11564 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
297 lines
7.6 KiB
TypeScript
297 lines
7.6 KiB
TypeScript
import { useCallback, useEffect, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import {
|
|
MetadataDeleteMap,
|
|
MetadataType,
|
|
metadataValueTypeEnum,
|
|
} from '../constant';
|
|
import { IManageValuesProps, IMetaDataTableData } from '../interface';
|
|
|
|
export const useManageValues = (props: IManageValuesProps) => {
|
|
const {
|
|
data,
|
|
isAddValueMode,
|
|
hideModal,
|
|
onSave,
|
|
addUpdateValue,
|
|
addDeleteValue,
|
|
existsKeys,
|
|
type,
|
|
} = props;
|
|
const { t } = useTranslation();
|
|
const [metaData, setMetaData] = useState<IMetaDataTableData>({
|
|
...data,
|
|
valueType: data.valueType || metadataValueTypeEnum.string,
|
|
values: data.values || [''],
|
|
});
|
|
const [valueError, setValueError] = useState<Record<string, string>>({
|
|
field: '',
|
|
values: '',
|
|
});
|
|
const [deleteDialogContent, setDeleteDialogContent] = useState({
|
|
visible: false,
|
|
title: '',
|
|
name: '',
|
|
warnText: '',
|
|
onOk: () => {},
|
|
onCancel: () => {},
|
|
});
|
|
|
|
const [shouldSave, setShouldSave] = useState(false);
|
|
const hideDeleteModal = () => {
|
|
setDeleteDialogContent({
|
|
visible: false,
|
|
title: '',
|
|
name: '',
|
|
warnText: '',
|
|
onOk: () => {},
|
|
onCancel: () => {},
|
|
});
|
|
};
|
|
|
|
// Use functional update to avoid closure issues
|
|
const handleChange = useCallback(
|
|
async (field: string, value: any) => {
|
|
if (field === 'field' && existsKeys.includes(value)) {
|
|
setValueError((prev) => {
|
|
return {
|
|
...prev,
|
|
field: MetadataDeleteMap(t)[type as MetadataType].warnFieldName,
|
|
// 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) => {
|
|
if (field === 'valueType') {
|
|
const nextValueType = (value ||
|
|
'string') as IMetaDataTableData['valueType'];
|
|
|
|
// const supportsEnum = isMetadataValueTypeWithEnum(nextValueType);
|
|
// if (!supportsEnum) {
|
|
// setTempValues([]);
|
|
// }
|
|
return {
|
|
...prev,
|
|
valueType: nextValueType,
|
|
values: prev.values || [],
|
|
restrictDefinedValues: prev.restrictDefinedValues,
|
|
};
|
|
}
|
|
const newMetadata = {
|
|
...prev,
|
|
[field]: value,
|
|
};
|
|
return newMetadata;
|
|
});
|
|
return true;
|
|
},
|
|
[existsKeys, type, t],
|
|
);
|
|
|
|
// Maintain separate state for each input box
|
|
const [tempValues, setTempValues] = useState<string[]>(['']);
|
|
|
|
useEffect(() => {
|
|
setTempValues([...data.values]);
|
|
setMetaData({
|
|
...data,
|
|
valueType: data.valueType || metadataValueTypeEnum.string,
|
|
});
|
|
}, [data]);
|
|
|
|
const handleHideModal = useCallback(() => {
|
|
hideModal();
|
|
setMetaData({} as IMetaDataTableData);
|
|
}, [hideModal]);
|
|
|
|
const handleSave = useCallback(() => {
|
|
if (type === MetadataType.Setting && valueError.field) {
|
|
return;
|
|
}
|
|
// const supportsEnum = isMetadataValueTypeWithEnum(metaData.valueType);
|
|
// if (!supportsEnum) {
|
|
// onSave({
|
|
// ...metaData,
|
|
// values: [],
|
|
// restrictDefinedValues: false,
|
|
// });
|
|
// handleHideModal();
|
|
// return;
|
|
// }
|
|
if (isAddValueMode) {
|
|
addUpdateValue(
|
|
metaData.field,
|
|
undefined,
|
|
metaData.values,
|
|
metaData.valueType,
|
|
);
|
|
}
|
|
// onSave(metaData);
|
|
setShouldSave(true);
|
|
}, [
|
|
metaData,
|
|
// onSave,
|
|
// handleHideModal,
|
|
type,
|
|
valueError,
|
|
isAddValueMode,
|
|
addUpdateValue,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
if (shouldSave) {
|
|
const timer = setTimeout(() => {
|
|
onSave(metaData);
|
|
setShouldSave(false);
|
|
clearTimeout(timer);
|
|
handleHideModal();
|
|
}, 100);
|
|
}
|
|
}, [shouldSave, onSave, handleHideModal, metaData]);
|
|
|
|
// Handle blur event, synchronize to main state
|
|
const handleValueBlur = useCallback(
|
|
(values?: string[]) => {
|
|
const newValues = values || tempValues;
|
|
if (data.values.length > 0 && !isAddValueMode) {
|
|
newValues.forEach((newValue, index) => {
|
|
if (index < data.values.length) {
|
|
const originalValue = data.values[index];
|
|
if (originalValue !== newValue) {
|
|
addUpdateValue(
|
|
metaData.field,
|
|
originalValue,
|
|
newValue,
|
|
metaData.valueType,
|
|
);
|
|
}
|
|
} else {
|
|
if (newValue) {
|
|
addUpdateValue(metaData.field, '', newValue, metaData.valueType);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
handleChange('values', [...new Set([...newValues])]);
|
|
},
|
|
[handleChange, tempValues, metaData, data, addUpdateValue, isAddValueMode],
|
|
);
|
|
|
|
// Handle value changes, only update temporary state
|
|
const handleValueChange = useCallback(
|
|
(index: number, value: string, isUpdate: boolean = false) => {
|
|
setTempValues((prev) => {
|
|
if (prev.includes(value)) {
|
|
setValueError((prev) => {
|
|
return {
|
|
...prev,
|
|
values: MetadataDeleteMap(t)[type as MetadataType].warnValueName,
|
|
// t('knowledgeDetails.metadata.valueExists'),
|
|
};
|
|
});
|
|
} else {
|
|
setValueError((prev) => {
|
|
return {
|
|
...prev,
|
|
values: '',
|
|
};
|
|
});
|
|
}
|
|
const newValues = [...prev];
|
|
newValues[index] = value;
|
|
if (isUpdate) {
|
|
handleValueBlur(newValues);
|
|
}
|
|
return newValues;
|
|
});
|
|
},
|
|
[t, type, handleValueBlur],
|
|
);
|
|
|
|
// Handle delete operation
|
|
const handleDelete = useCallback(
|
|
(index: number) => {
|
|
setTempValues((prev) => {
|
|
const newTempValues = [...prev];
|
|
addDeleteValue(metaData.field, newTempValues[index]);
|
|
newTempValues.splice(index, 1);
|
|
return newTempValues;
|
|
});
|
|
|
|
// Synchronize to main state
|
|
setMetaData((prev) => {
|
|
const newMetaDataValues = [...prev.values];
|
|
newMetaDataValues.splice(index, 1);
|
|
return {
|
|
...prev,
|
|
values: newMetaDataValues,
|
|
};
|
|
});
|
|
},
|
|
[addDeleteValue, metaData],
|
|
);
|
|
|
|
const handleClearValues = useCallback(
|
|
(isClearInitialValues = false) => {
|
|
setTempValues(isClearInitialValues ? [] : ['']);
|
|
setMetaData((prev) => ({
|
|
...prev,
|
|
values: isClearInitialValues ? [] : [''],
|
|
}));
|
|
},
|
|
[setTempValues, setMetaData],
|
|
);
|
|
|
|
const showDeleteModal = (item: string, callback: () => void) => {
|
|
setDeleteDialogContent({
|
|
visible: true,
|
|
title: t('common.delete') + ' ' + t('knowledgeDetails.metadata.value'),
|
|
name: item,
|
|
warnText: MetadataDeleteMap(t)[type as MetadataType].warnValueText,
|
|
onOk: () => {
|
|
hideDeleteModal();
|
|
callback();
|
|
},
|
|
onCancel: () => {
|
|
hideDeleteModal();
|
|
},
|
|
});
|
|
};
|
|
|
|
// Handle adding new value
|
|
const handleAddValue = useCallback(() => {
|
|
setTempValues((prev) => [...new Set([...prev, ''])]);
|
|
|
|
// Synchronize to main state
|
|
setMetaData((prev) => ({
|
|
...prev,
|
|
values: [...new Set([...prev.values, ''])],
|
|
}));
|
|
}, []);
|
|
|
|
return {
|
|
metaData,
|
|
handleClearValues,
|
|
tempValues,
|
|
valueError,
|
|
deleteDialogContent,
|
|
handleChange,
|
|
handleValueChange,
|
|
handleValueBlur,
|
|
handleDelete,
|
|
handleAddValue,
|
|
showDeleteModal,
|
|
handleSave,
|
|
handleHideModal,
|
|
};
|
|
};
|