From 1e9374a373afd4953a867bf9e8a558feb7a27a49 Mon Sep 17 00:00:00 2001 From: chanx <1243304602@qq.com> Date: Wed, 24 Dec 2025 17:21:36 +0800 Subject: [PATCH] =?UTF-8?q?Fix=EF=BC=9AMetadata=20saving,=20copywriting=20?= =?UTF-8?q?and=20other=20related=20issues=20(#12169)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What problem does this PR solve? Fix:Bugs Fixed - Text overflow issues that caused rendering problems - Metadata saving, copywriting and other related issues ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue) --- .../components/chunk-method-dialog/index.tsx | 19 ++ .../use-default-parser-values.ts | 4 +- web/src/components/file-uploader.tsx | 18 +- web/src/interfaces/database/document.ts | 12 + web/src/locales/en.ts | 9 + web/src/locales/zh.ts | 6 + .../{hook.ts => hooks/use-manage-modal.ts} | 138 ++++++++++-- .../metedata/hooks/use-manage-values-modal.ts | 208 ++++++++++++++++++ .../dataset/components/metedata/interface.ts | 9 +- .../components/metedata/manage-modal.tsx | 61 +++-- .../metedata/manage-values-modal.tsx | 194 ++-------------- .../configuration/common-item.tsx | 24 +- .../dataset/dataset-setting/form-schema.ts | 2 +- web/src/pages/dataset/dataset/index.tsx | 5 +- .../dataset/use-dataset-table-columns.tsx | 5 +- web/src/pages/dataset/process-log-modal.tsx | 16 +- web/src/services/knowledge-service.ts | 6 +- web/src/utils/api.ts | 1 + 18 files changed, 497 insertions(+), 240 deletions(-) rename web/src/pages/dataset/components/metedata/{hook.ts => hooks/use-manage-modal.ts} (71%) create mode 100644 web/src/pages/dataset/components/metedata/hooks/use-manage-values-modal.ts diff --git a/web/src/components/chunk-method-dialog/index.tsx b/web/src/components/chunk-method-dialog/index.tsx index f9af844fc..ce3a3c3ef 100644 --- a/web/src/components/chunk-method-dialog/index.tsx +++ b/web/src/components/chunk-method-dialog/index.tsx @@ -18,7 +18,9 @@ import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-reques import { IModalProps } from '@/interfaces/common'; import { IParserConfig } from '@/interfaces/database/document'; import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; +import { MetadataType } from '@/pages/dataset/components/metedata/hooks/use-manage-modal'; import { + AutoMetadata, ChunkMethodItem, EnableTocToggle, ImageContextWindow, @@ -86,6 +88,7 @@ export function ChunkMethodDialog({ visible, parserConfig, loading, + documentId, }: IProps) { const { t } = useTranslation(); @@ -142,6 +145,18 @@ export function ChunkMethodDialog({ pages: z .array(z.object({ from: z.coerce.number(), to: z.coerce.number() })) .optional(), + metadata: z + .array( + z + .object({ + key: z.string().optional(), + description: z.string().optional(), + enum: z.array(z.string().optional()).optional(), + }) + .optional(), + ) + .optional(), + enable_metadata: z.boolean().optional(), }), }) .superRefine((data, ctx) => { @@ -373,6 +388,10 @@ export function ChunkMethodDialog({ )} {showAutoKeywords(selectedTag) && ( <> + diff --git a/web/src/components/chunk-method-dialog/use-default-parser-values.ts b/web/src/components/chunk-method-dialog/use-default-parser-values.ts index a82a32621..47af38771 100644 --- a/web/src/components/chunk-method-dialog/use-default-parser-values.ts +++ b/web/src/components/chunk-method-dialog/use-default-parser-values.ts @@ -36,9 +36,11 @@ export function useDefaultParserValues() { // }, entity_types: [], pages: [], + metadata: [], + enable_metadata: false, }; - return defaultParserValues; + return defaultParserValues as IParserConfig; }, [t]); return defaultParserValues; diff --git a/web/src/components/file-uploader.tsx b/web/src/components/file-uploader.tsx index 43b4fcc8d..d957d834e 100644 --- a/web/src/components/file-uploader.tsx +++ b/web/src/components/file-uploader.tsx @@ -15,6 +15,7 @@ import { Progress } from '@/components/ui/progress'; import { useControllableState } from '@/hooks/use-controllable-state'; import { cn, formatBytes } from '@/lib/utils'; import { useTranslation } from 'react-i18next'; +import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip'; function isFileWithPreview(file: File): file is File & { preview: string } { return 'preview' in file && typeof file.preview === 'string'; @@ -58,10 +59,17 @@ function FileCard({ file, progress, onRemove }: FileCardProps) {
-

- {file.name} -

-

+ + +

+ {file.name} +

+ + + {file.name} + + +

{formatBytes(file.size)}

@@ -311,7 +319,7 @@ export function FileUploader(props: FileUploaderProps) { />
-

+

{title || t('knowledgeDetails.uploadTitle')}

diff --git a/web/src/interfaces/database/document.ts b/web/src/interfaces/database/document.ts index 7eab0672e..5ee1394de 100644 --- a/web/src/interfaces/database/document.ts +++ b/web/src/interfaces/database/document.ts @@ -43,6 +43,18 @@ export interface IParserConfig { task_page_size?: number; raptor?: Raptor; graphrag?: GraphRag; + image_context_window?: number; + mineru_parse_method?: 'auto' | 'txt' | 'ocr'; + mineru_formula_enable?: boolean; + mineru_table_enable?: boolean; + mineru_lang?: string; + entity_types?: string[]; + metadata?: Array<{ + key?: string; + description?: string; + enum?: string[]; + }>; + enable_metadata?: boolean; } interface Raptor { diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 6ef6d2a72..7877cd8a2 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -190,12 +190,21 @@ Procedural Memory: Learned skills, habits, and automated procedures.`, manageMetadata: 'Manage metadata', metadata: 'Metadata', values: 'Values', + value: 'Value', action: 'Action', field: 'Field', description: 'Description', fieldName: 'Field name', editMetadata: 'Edit metadata', deleteWarn: 'This {{field}} will be removed from all associated files', + deleteManageFieldAllWarn: + 'This field and all its corresponding values will be deleted from all associated files.', + deleteManageValueAllWarn: + 'This value will be deleted from from all associated files.', + deleteManageFieldSingleWarn: + 'This field and all its corresponding values will be deleted from this files.', + deleteManageValueSingleWarn: + 'This value will be deleted from this files.', }, metadataField: 'Metadata field', systemAttribute: 'System attribute', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index 4225a5aa8..51d231f98 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -177,6 +177,7 @@ export default { manageMetadata: '管理元数据', metadata: '元数据', values: '值', + value: '值', action: '操作', field: '字段', description: '描述', @@ -186,6 +187,11 @@ export default { fieldNameExists: '字段名已存在。确认合并重复项并组合所有关联文件。', fieldExists: '字段名已存在。', deleteWarn: '此 {{field}} 将从所有关联文件中移除', + deleteManageFieldAllWarn: + '此字段及其所有对应值将从所有关联的文件中删除。', + deleteManageValueAllWarn: '此值将从所有关联的文件中删除。', + deleteManageFieldSingleWarn: '此字段及其所有对应值将从此文件中删除。', + deleteManageValueSingleWarn: '此值将从此文件中删除。', }, localUpload: '本地上传', fileSize: '文件大小', diff --git a/web/src/pages/dataset/components/metedata/hook.ts b/web/src/pages/dataset/components/metedata/hooks/use-manage-modal.ts similarity index 71% rename from web/src/pages/dataset/components/metedata/hook.ts rename to web/src/pages/dataset/components/metedata/hooks/use-manage-modal.ts index 38aae43c9..3d2b7defd 100644 --- a/web/src/pages/dataset/components/metedata/hook.ts +++ b/web/src/pages/dataset/components/metedata/hooks/use-manage-modal.ts @@ -9,6 +9,7 @@ import kbService, { updateMetaData, } from '@/services/knowledge-service'; import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { TFunction } from 'i18next'; import { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useParams } from 'umi'; @@ -19,12 +20,43 @@ import { IMetaDataTableData, MetadataOperations, ShowManageMetadataModalProps, -} from './interface'; +} from '../interface'; export enum MetadataType { Manage = 1, UpdateSingle = 2, Setting = 3, + SingleFileSetting = 4, } + +export const MetadataDeleteMap = ( + t: TFunction<'translation', undefined>, +): Record< + MetadataType, + { title: string; warnFieldText: string; warnValueText: string } +> => { + return { + [MetadataType.Manage]: { + title: t('common.delete') + ' ' + t('knowledgeDetails.metadata.metadata'), + warnFieldText: t('knowledgeDetails.metadata.deleteManageFieldAllWarn'), + warnValueText: t('knowledgeDetails.metadata.deleteManageValueAllWarn'), + }, + [MetadataType.Setting]: { + title: t('common.delete') + ' ' + t('knowledgeDetails.metadata.metadata'), + warnFieldText: t('knowledgeDetails.metadata.deleteManageFieldAllWarn'), + warnValueText: t('knowledgeDetails.metadata.deleteManageValueAllWarn'), + }, + [MetadataType.UpdateSingle]: { + title: t('common.delete') + ' ' + t('knowledgeDetails.metadata.metadata'), + warnFieldText: t('knowledgeDetails.metadata.deleteManageFieldSingleWarn'), + warnValueText: t('knowledgeDetails.metadata.deleteManageValueSingleWarn'), + }, + [MetadataType.SingleFileSetting]: { + title: t('common.delete') + ' ' + t('knowledgeDetails.metadata.metadata'), + warnFieldText: t('knowledgeDetails.metadata.deleteManageFieldSingleWarn'), + warnValueText: t('knowledgeDetails.metadata.deleteManageValueSingleWarn'), + }, + }; +}; export const util = { changeToMetaDataTableData(data: IMetaDataReturnType): IMetaDataTableData[] { return Object.entries(data).map(([key, value]) => { @@ -42,10 +74,21 @@ export const util = { data: Record, ): IMetaDataTableData[] { return Object.entries(data).map(([key, value]) => { + let thisValue = [] as string[]; + if (value && Array.isArray(value)) { + thisValue = value; + } else if (value && typeof value === 'string') { + thisValue = [value]; + } else if (value && typeof value === 'object') { + thisValue = [JSON.stringify(value)]; + } else if (value) { + thisValue = [value.toString()]; + } + return { field: key, description: '', - values: value, + values: thisValue, } as IMetaDataTableData; }); }, @@ -103,12 +146,42 @@ export const useMetadataOperations = () => { })); }, []); + // const addUpdateValue = useCallback( + // (key: string, value: string | string[]) => { + // setOperations((prev) => ({ + // ...prev, + // updates: [...prev.updates, { key, value }], + // })); + // }, + // [], + // ); const addUpdateValue = useCallback( - (key: string, value: string | string[]) => { - setOperations((prev) => ({ - ...prev, - updates: [...prev.updates, { key, value }], - })); + (key: string, originalValue: string, newValue: string) => { + setOperations((prev) => { + const existsIndex = prev.updates.findIndex( + (update) => update.key === key && update.match === originalValue, + ); + + if (existsIndex > -1) { + const updatedUpdates = [...prev.updates]; + updatedUpdates[existsIndex] = { + key, + match: originalValue, + value: newValue, + }; + return { + ...prev, + updates: updatedUpdates, + }; + } + return { + ...prev, + updates: [ + ...prev.updates, + { key, match: originalValue, value: newValue }, + ], + }; + }); }, [], ); @@ -195,8 +268,13 @@ export const useManageMetaDataModal = ( const [tableData, setTableData] = useState(metaData); const queryClient = useQueryClient(); - const { operations, addDeleteRow, addDeleteValue, addUpdateValue } = - useMetadataOperations(); + const { + operations, + addDeleteRow, + addDeleteValue, + addUpdateValue, + resetOperations, + } = useMetadataOperations(); const { setDocumentMeta } = useSetDocumentMeta(); @@ -265,11 +343,12 @@ export const useManageMetaDataModal = ( queryClient.invalidateQueries({ queryKey: [DocumentApiAction.FetchDocumentList], }); + resetOperations(); message.success(t('message.operated')); callback(); } }, - [operations, id, t, queryClient], + [operations, id, t, queryClient, resetOperations], ); const handleSaveUpdateSingle = useCallback( @@ -303,7 +382,26 @@ export const useManageMetaDataModal = ( return data; }, - [tableData, id], + [tableData, id, t], + ); + + const handleSaveSingleFileSettings = useCallback( + async (callback: () => void) => { + const data = util.tableDataToMetaDataSettingJSON(tableData); + if (otherData?.documentId) { + const { data: res } = await kbService.documentUpdateMetaData({ + doc_id: otherData.documentId, + metadata: data, + }); + if (res.code === 0) { + message.success(t('message.operated')); + callback?.(); + } + } + + return data; + }, + [tableData, t, otherData], ); const handleSave = useCallback( @@ -317,12 +415,20 @@ export const useManageMetaDataModal = ( break; case MetadataType.Setting: return handleSaveSettings(callback); + case MetadataType.SingleFileSetting: + return handleSaveSingleFileSettings(callback); default: handleSaveManage(callback); break; } }, - [handleSaveManage, type, handleSaveUpdateSingle, handleSaveSettings], + [ + handleSaveManage, + type, + handleSaveUpdateSingle, + handleSaveSettings, + handleSaveSingleFileSettings, + ], ); return { @@ -377,11 +483,3 @@ export const useManageMetadata = () => { config, }; }; - -export const useManageValues = () => { - const [updateValues, setUpdateValues] = useState<{ - field: string; - values: string[]; - } | null>(null); - return { updateValues, setUpdateValues }; -}; diff --git a/web/src/pages/dataset/components/metedata/hooks/use-manage-values-modal.ts b/web/src/pages/dataset/components/metedata/hooks/use-manage-values-modal.ts new file mode 100644 index 000000000..459077a29 --- /dev/null +++ b/web/src/pages/dataset/components/metedata/hooks/use-manage-values-modal.ts @@ -0,0 +1,208 @@ +import { useCallback, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { MetadataDeleteMap, MetadataType } from '../hooks/use-manage-modal'; +import { IManageValuesProps, IMetaDataTableData } from '../interface'; + +export const useManageValues = (props: IManageValuesProps) => { + const { + data, + + isShowValueSwitch, + hideModal, + onSave, + addUpdateValue, + addDeleteValue, + existsKeys, + type, + } = props; + const { t } = useTranslation(); + const [metaData, setMetaData] = useState(data); + const [valueError, setValueError] = useState>({ + 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) => { + 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([...data.values]); + + useEffect(() => { + setTempValues([...data.values]); + setMetaData(data); + }, [data]); + + const handleHideModal = useCallback(() => { + hideModal(); + setMetaData({} as IMetaDataTableData); + }, [hideModal]); + + const handleSave = useCallback(() => { + if (type === MetadataType.Setting && valueError.field) { + return; + } + if (!metaData.restrictDefinedValues && isShowValueSwitch) { + const newMetaData = { ...metaData, values: [] }; + onSave(newMetaData); + } else { + onSave(metaData); + } + handleHideModal(); + }, [metaData, onSave, handleHideModal, isShowValueSwitch, type, valueError]); + + // Handle value changes, only update temporary state + 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; + }); + }, + [t], + ); + + // Handle blur event, synchronize to main state + const handleValueBlur = useCallback(() => { + // addUpdateValue(metaData.field, [...new Set([...tempValues])]); + tempValues.forEach((newValue, index) => { + if (index < data.values.length) { + const originalValue = data.values[index]; + if (originalValue !== newValue) { + addUpdateValue(metaData.field, originalValue, newValue); + } + } else { + if (newValue) { + addUpdateValue(metaData.field, '', newValue); + } + } + }); + handleChange('values', [...new Set([...tempValues])]); + }, [handleChange, tempValues, metaData, data, addUpdateValue]); + + // 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 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, + tempValues, + valueError, + deleteDialogContent, + handleChange, + handleValueChange, + handleValueBlur, + handleDelete, + handleAddValue, + showDeleteModal, + handleSave, + handleHideModal, + }; +}; diff --git a/web/src/pages/dataset/components/metedata/interface.ts b/web/src/pages/dataset/components/metedata/interface.ts index 2cd25b612..ef2990366 100644 --- a/web/src/pages/dataset/components/metedata/interface.ts +++ b/web/src/pages/dataset/components/metedata/interface.ts @@ -50,7 +50,11 @@ export interface IManageValuesProps { type: MetadataType; hideModal: () => void; onSave: (data: IMetaDataTableData) => void; - addUpdateValue: (key: string, value: string | string[]) => void; + addUpdateValue: ( + key: string, + originalValue: string, + newValue: string, + ) => void; addDeleteValue: (key: string, value: string) => void; } @@ -61,7 +65,8 @@ interface DeleteOperation { interface UpdateOperation { key: string; - value: string | string[]; + match: string; + value: string; } export interface MetadataOperations { diff --git a/web/src/pages/dataset/components/metedata/manage-modal.tsx b/web/src/pages/dataset/components/metedata/manage-modal.tsx index 0df879239..d91cdfb2d 100644 --- a/web/src/pages/dataset/components/metedata/manage-modal.tsx +++ b/web/src/pages/dataset/components/metedata/manage-modal.tsx @@ -25,11 +25,16 @@ import { useReactTable, } from '@tanstack/react-table'; import { Plus, Settings, Trash2 } from 'lucide-react'; -import { useCallback, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { MetadataType, useManageMetaDataModal } from './hook'; +import { + MetadataDeleteMap, + MetadataType, + useManageMetaDataModal, +} from './hooks/use-manage-modal'; import { IManageModalProps, IMetaDataTableData } from './interface'; import { ManageValuesModal } from './manage-values-modal'; + export const ManageMetadataModal = (props: IManageModalProps) => { const { title, @@ -134,7 +139,8 @@ export const ManageMetadataModal = (props: IManageModalProps) => { const values = row.getValue('values') as Array; return (

- {values.length > 0 && + {Array.isArray(values) && + values.length > 0 && values .filter((value: string, index: number) => index < 2) ?.map((value: string) => { @@ -159,17 +165,12 @@ export const ManageMetadataModal = (props: IManageModalProps) => { 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'), - }, - ), + t('knowledgeDetails.metadata.value'), + name: value, + warnText: + MetadataDeleteMap(t)[ + metadataType as MetadataType + ].warnValueText, onOk: () => { hideDeleteModal(); handleDeleteSingleValue( @@ -190,7 +191,7 @@ export const ManageMetadataModal = (props: IManageModalProps) => { ); })} - {values.length > 2 && ( + {Array.isArray(values) && values.length > 2 && (
...
)}
@@ -221,13 +222,14 @@ export const ManageMetadataModal = (props: IManageModalProps) => { setDeleteDialogContent({ visible: true, title: - t('common.delete') + - ' ' + - t('knowledgeDetails.metadata.metadata'), + // t('common.delete') + + // ' ' + + // t('knowledgeDetails.metadata.metadata') + MetadataDeleteMap(t)[metadataType as MetadataType].title, name: row.getValue('field'), - warnText: t('knowledgeDetails.metadata.deleteWarn', { - field: t('knowledgeDetails.metadata.field'), - }), + warnText: + MetadataDeleteMap(t)[metadataType as MetadataType] + .warnFieldText, onOk: () => { hideDeleteModal(); handleDeleteSingleRow(row.getValue('field')); @@ -266,7 +268,7 @@ export const ManageMetadataModal = (props: IManageModalProps) => { getFilteredRowModel: getFilteredRowModel(), manualPagination: true, }); - + const [shouldSave, setShouldSave] = useState(false); const handleSaveValues = (data: IMetaDataTableData) => { setTableData((prev) => { let newData; @@ -300,8 +302,20 @@ export const ManageMetadataModal = (props: IManageModalProps) => { return Array.from(fieldMap.values()); }); + setShouldSave(true); }; + useEffect(() => { + if (shouldSave) { + const timer = setTimeout(() => { + handleSave({ callback: () => {} }); + setShouldSave(false); + }, 0); + + return () => clearTimeout(timer); + } + }, [tableData, shouldSave, handleSave]); + const existsKeys = useMemo(() => { return tableData.map((item) => item.field); }, [tableData]); @@ -386,7 +400,8 @@ export const ManageMetadataModal = (props: IManageModalProps) => { - {metadataType === MetadataType.Setting + {metadataType === MetadataType.Setting || + metadataType === MetadataType.SingleFileSetting ? t('knowledgeDetails.metadata.fieldSetting') : t('knowledgeDetails.metadata.editMetadata')}
diff --git a/web/src/pages/dataset/components/metedata/manage-values-modal.tsx b/web/src/pages/dataset/components/metedata/manage-values-modal.tsx index 510ebbbc9..2bc2b8641 100644 --- a/web/src/pages/dataset/components/metedata/manage-values-modal.tsx +++ b/web/src/pages/dataset/components/metedata/manage-values-modal.tsx @@ -9,10 +9,10 @@ import { Modal } from '@/components/ui/modal/modal'; import { Switch } from '@/components/ui/switch'; import { Textarea } from '@/components/ui/textarea'; import { Plus, Trash2 } from 'lucide-react'; -import { memo, useCallback, useEffect, useState } from 'react'; +import { memo } from 'react'; import { useTranslation } from 'react-i18next'; -import { MetadataType } from './hook'; -import { IManageValuesProps, IMetaDataTableData } from './interface'; +import { useManageValues } from './hooks/use-manage-values-modal'; +import { IManageValuesProps } from './interface'; // Create a separate input component, wrapped with memo to avoid unnecessary re-renders const ValueInputItem = memo( @@ -57,188 +57,28 @@ const ValueInputItem = memo( export const ManageValuesModal = (props: IManageValuesProps) => { const { title, - data, isEditField, visible, isAddValue, isShowDescription, isShowValueSwitch, isVerticalShowValue, - hideModal, - onSave, - addUpdateValue, - addDeleteValue, - existsKeys, - type, } = props; - const [metaData, setMetaData] = useState(data); + const { + metaData, + tempValues, + valueError, + deleteDialogContent, + handleChange, + handleValueChange, + handleValueBlur, + handleDelete, + handleAddValue, + showDeleteModal, + handleSave, + handleHideModal, + } = useManageValues(props); const { t } = useTranslation(); - const [valueError, setValueError] = useState>({ - 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) => { - 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([...data.values]); - - useEffect(() => { - setTempValues([...data.values]); - setMetaData(data); - }, [data]); - - const handleHideModal = useCallback(() => { - hideModal(); - setMetaData({} as IMetaDataTableData); - }, [hideModal]); - - const handleSave = useCallback(() => { - if (type === MetadataType.Setting && valueError.field) { - return; - } - if (!metaData.restrictDefinedValues && isShowValueSwitch) { - const newMetaData = { ...metaData, values: [] }; - onSave(newMetaData); - } else { - onSave(metaData); - } - handleHideModal(); - }, [metaData, onSave, handleHideModal, isShowValueSwitch, type, valueError]); - - // Handle value changes, only update temporary state - 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; - }); - }, - [t], - ); - - // Handle blur event, synchronize to main state - const handleValueBlur = useCallback(() => { - addUpdateValue(metaData.field, [...new Set([...tempValues])]); - handleChange('values', [...new Set([...tempValues])]); - }, [handleChange, tempValues, metaData, addUpdateValue]); - - // 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 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, ''])]); - - // Synchronize to main state - setMetaData((prev) => ({ - ...prev, - values: [...new Set([...prev.values, ''])], - })); - }, []); return ( ; +}) { // get metadata field const form = useFormContext(); const { @@ -369,6 +376,7 @@ export function AutoMetadata() { tableData, config: metadataConfig, } = useManageMetadata(); + const autoMetadataField: FormFieldConfig = { name: 'parser_config.enable_metadata', label: t('knowledgeConfiguration.autoMetadata'), @@ -379,6 +387,7 @@ export function AutoMetadata() { render: (fieldProps: ControllerRenderProps) => (
), }; + + const handleSaveMetadata = (data?: IMetaDataReturnJSONSettings) => { + form.setValue('parser_config.metadata', data || []); + }; return ( <> @@ -431,8 +445,8 @@ export function AutoMetadata() { isShowDescription={true} isShowValueSwitch={true} isVerticalShowValue={false} - success={(data) => { - form.setValue('parser_config.metadata', data || []); + success={(data?: IMetaDataReturnJSONSettings) => { + handleSaveMetadata(data); }} /> )} diff --git a/web/src/pages/dataset/dataset-setting/form-schema.ts b/web/src/pages/dataset/dataset-setting/form-schema.ts index 196fefe76..8e7a16844 100644 --- a/web/src/pages/dataset/dataset-setting/form-schema.ts +++ b/web/src/pages/dataset/dataset-setting/form-schema.ts @@ -96,7 +96,7 @@ export const formSchema = z ) .optional(), enable_metadata: z.boolean().optional(), - llm_id: z.string().optional(), + llm_id: z.string().min(1, { message: 'Indexing model is required' }), }) .optional(), pagerank: z.number(), diff --git a/web/src/pages/dataset/dataset/index.tsx b/web/src/pages/dataset/dataset/index.tsx index fcbf8036b..1d2908d5d 100644 --- a/web/src/pages/dataset/dataset/index.tsx +++ b/web/src/pages/dataset/dataset/index.tsx @@ -16,7 +16,10 @@ import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-reques import { Pen, Upload } from 'lucide-react'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { MetadataType, useManageMetadata } from '../components/metedata/hook'; +import { + MetadataType, + useManageMetadata, +} from '../components/metedata/hooks/use-manage-modal'; import { ManageMetadataModal } from '../components/metedata/manage-modal'; import { DatasetTable } from './dataset-table'; import Generate from './generate-button/generate'; diff --git a/web/src/pages/dataset/dataset/use-dataset-table-columns.tsx b/web/src/pages/dataset/dataset/use-dataset-table-columns.tsx index d83fd0092..a7afc4a09 100644 --- a/web/src/pages/dataset/dataset/use-dataset-table-columns.tsx +++ b/web/src/pages/dataset/dataset/use-dataset-table-columns.tsx @@ -16,7 +16,10 @@ import { formatDate } from '@/utils/date'; import { ColumnDef } from '@tanstack/table-core'; import { ArrowUpDown, MonitorUp } from 'lucide-react'; import { useTranslation } from 'react-i18next'; -import { MetadataType, util } from '../components/metedata/hook'; +import { + MetadataType, + util, +} from '../components/metedata/hooks/use-manage-modal'; import { ShowManageMetadataModalProps } from '../components/metedata/interface'; import { DatasetActionCell } from './dataset-action-cell'; import { ParsingStatusCell } from './parsing-status-cell'; diff --git a/web/src/pages/dataset/process-log-modal.tsx b/web/src/pages/dataset/process-log-modal.tsx index 96b0c0e12..15e0d1f1f 100644 --- a/web/src/pages/dataset/process-log-modal.tsx +++ b/web/src/pages/dataset/process-log-modal.tsx @@ -1,6 +1,11 @@ import FileStatusBadge from '@/components/file-status-badge'; import { Button } from '@/components/ui/button'; import { Modal } from '@/components/ui/modal/modal'; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from '@/components/ui/tooltip'; import { RunningStatusMap } from '@/constants/knowledge'; import { useTranslate } from '@/hooks/common-hooks'; import React, { useMemo } from 'react'; @@ -40,7 +45,14 @@ const InfoItem: React.FC<{ return (
{label} - {value} + + + + {value} + + + {value} +
); }; @@ -70,9 +82,7 @@ const ProcessLogModal: React.FC = ({ }) => { const { t } = useTranslate('knowledgeDetails'); const blackKeyList = ['']; - console.log('logInfo', initData); const logInfo = useMemo(() => { - console.log('logInfo', initData); return initData; }, [initData]); diff --git a/web/src/services/knowledge-service.ts b/web/src/services/knowledge-service.ts index 169da2cd9..0cd916389 100644 --- a/web/src/services/knowledge-service.ts +++ b/web/src/services/knowledge-service.ts @@ -48,10 +48,10 @@ const { traceRaptor, check_embedding, kbUpdateMetaData, + documentUpdateMetaData, } = api; const methods = { - // 知识库管理 createKb: { url: create_kb, method: 'post', @@ -220,6 +220,10 @@ const methods = { url: kbUpdateMetaData, method: 'post', }, + documentUpdateMetaData: { + url: documentUpdateMetaData, + method: 'post', + }, // getMetaData: { // url: getMetaData, // method: 'get', diff --git a/web/src/utils/api.ts b/web/src/utils/api.ts index 29c10fa4b..251158000 100644 --- a/web/src/utils/api.ts +++ b/web/src/utils/api.ts @@ -80,6 +80,7 @@ export default { getMetaData: `${api_host}/document/metadata/summary`, updateMetaData: `${api_host}/document/metadata/update`, kbUpdateMetaData: `${api_host}/kb/update_metadata_setting`, + documentUpdateMetaData: `${api_host}/document/update_metadata_setting`, // tags listTag: (knowledgeId: string) => `${api_host}/kb/${knowledgeId}/tags`,