mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-31 01:01:30 +08:00
Fix:Metadata saving, copywriting and other related issues (#12169)
### 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)
This commit is contained in:
@ -18,7 +18,9 @@ import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-reques
|
|||||||
import { IModalProps } from '@/interfaces/common';
|
import { IModalProps } from '@/interfaces/common';
|
||||||
import { IParserConfig } from '@/interfaces/database/document';
|
import { IParserConfig } from '@/interfaces/database/document';
|
||||||
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
||||||
|
import { MetadataType } from '@/pages/dataset/components/metedata/hooks/use-manage-modal';
|
||||||
import {
|
import {
|
||||||
|
AutoMetadata,
|
||||||
ChunkMethodItem,
|
ChunkMethodItem,
|
||||||
EnableTocToggle,
|
EnableTocToggle,
|
||||||
ImageContextWindow,
|
ImageContextWindow,
|
||||||
@ -86,6 +88,7 @@ export function ChunkMethodDialog({
|
|||||||
visible,
|
visible,
|
||||||
parserConfig,
|
parserConfig,
|
||||||
loading,
|
loading,
|
||||||
|
documentId,
|
||||||
}: IProps) {
|
}: IProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@ -142,6 +145,18 @@ export function ChunkMethodDialog({
|
|||||||
pages: z
|
pages: z
|
||||||
.array(z.object({ from: z.coerce.number(), to: z.coerce.number() }))
|
.array(z.object({ from: z.coerce.number(), to: z.coerce.number() }))
|
||||||
.optional(),
|
.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) => {
|
.superRefine((data, ctx) => {
|
||||||
@ -373,6 +388,10 @@ export function ChunkMethodDialog({
|
|||||||
)}
|
)}
|
||||||
{showAutoKeywords(selectedTag) && (
|
{showAutoKeywords(selectedTag) && (
|
||||||
<>
|
<>
|
||||||
|
<AutoMetadata
|
||||||
|
type={MetadataType.SingleFileSetting}
|
||||||
|
otherData={{ documentId }}
|
||||||
|
/>
|
||||||
<AutoKeywordsFormField></AutoKeywordsFormField>
|
<AutoKeywordsFormField></AutoKeywordsFormField>
|
||||||
<AutoQuestionsFormField></AutoQuestionsFormField>
|
<AutoQuestionsFormField></AutoQuestionsFormField>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -36,9 +36,11 @@ export function useDefaultParserValues() {
|
|||||||
// },
|
// },
|
||||||
entity_types: [],
|
entity_types: [],
|
||||||
pages: [],
|
pages: [],
|
||||||
|
metadata: [],
|
||||||
|
enable_metadata: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
return defaultParserValues;
|
return defaultParserValues as IParserConfig;
|
||||||
}, [t]);
|
}, [t]);
|
||||||
|
|
||||||
return defaultParserValues;
|
return defaultParserValues;
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import { Progress } from '@/components/ui/progress';
|
|||||||
import { useControllableState } from '@/hooks/use-controllable-state';
|
import { useControllableState } from '@/hooks/use-controllable-state';
|
||||||
import { cn, formatBytes } from '@/lib/utils';
|
import { cn, formatBytes } from '@/lib/utils';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip';
|
||||||
|
|
||||||
function isFileWithPreview(file: File): file is File & { preview: string } {
|
function isFileWithPreview(file: File): file is File & { preview: string } {
|
||||||
return 'preview' in file && typeof file.preview === 'string';
|
return 'preview' in file && typeof file.preview === 'string';
|
||||||
@ -58,10 +59,17 @@ function FileCard({ file, progress, onRemove }: FileCardProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col flex-1 gap-2 overflow-hidden">
|
<div className="flex flex-col flex-1 gap-2 overflow-hidden">
|
||||||
<div className="flex flex-col gap-px">
|
<div className="flex flex-col gap-px">
|
||||||
<p className="line-clamp-1 text-sm font-medium text-foreground/80 text-ellipsis">
|
<Tooltip>
|
||||||
{file.name}
|
<TooltipTrigger asChild>
|
||||||
</p>
|
<p className=" w-fit line-clamp-1 text-sm font-medium text-foreground/80 text-ellipsis truncate max-w-[370px]">
|
||||||
<p className="text-xs text-muted-foreground">
|
{file.name}
|
||||||
|
</p>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent className="border border-border-button">
|
||||||
|
{file.name}
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
<p className="text-xs text-text-secondary">
|
||||||
{formatBytes(file.size)}
|
{formatBytes(file.size)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -311,7 +319,7 @@ export function FileUploader(props: FileUploaderProps) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-px">
|
<div className="flex flex-col gap-px">
|
||||||
<p className="font-medium text-text-secondary">
|
<p className="font-medium text-text-secondary ">
|
||||||
{title || t('knowledgeDetails.uploadTitle')}
|
{title || t('knowledgeDetails.uploadTitle')}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-sm text-text-disabled">
|
<p className="text-sm text-text-disabled">
|
||||||
|
|||||||
@ -43,6 +43,18 @@ export interface IParserConfig {
|
|||||||
task_page_size?: number;
|
task_page_size?: number;
|
||||||
raptor?: Raptor;
|
raptor?: Raptor;
|
||||||
graphrag?: GraphRag;
|
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 {
|
interface Raptor {
|
||||||
|
|||||||
@ -190,12 +190,21 @@ Procedural Memory: Learned skills, habits, and automated procedures.`,
|
|||||||
manageMetadata: 'Manage metadata',
|
manageMetadata: 'Manage metadata',
|
||||||
metadata: 'Metadata',
|
metadata: 'Metadata',
|
||||||
values: 'Values',
|
values: 'Values',
|
||||||
|
value: 'Value',
|
||||||
action: 'Action',
|
action: 'Action',
|
||||||
field: 'Field',
|
field: 'Field',
|
||||||
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',
|
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',
|
metadataField: 'Metadata field',
|
||||||
systemAttribute: 'System attribute',
|
systemAttribute: 'System attribute',
|
||||||
|
|||||||
@ -177,6 +177,7 @@ export default {
|
|||||||
manageMetadata: '管理元数据',
|
manageMetadata: '管理元数据',
|
||||||
metadata: '元数据',
|
metadata: '元数据',
|
||||||
values: '值',
|
values: '值',
|
||||||
|
value: '值',
|
||||||
action: '操作',
|
action: '操作',
|
||||||
field: '字段',
|
field: '字段',
|
||||||
description: '描述',
|
description: '描述',
|
||||||
@ -186,6 +187,11 @@ export default {
|
|||||||
fieldNameExists: '字段名已存在。确认合并重复项并组合所有关联文件。',
|
fieldNameExists: '字段名已存在。确认合并重复项并组合所有关联文件。',
|
||||||
fieldExists: '字段名已存在。',
|
fieldExists: '字段名已存在。',
|
||||||
deleteWarn: '此 {{field}} 将从所有关联文件中移除',
|
deleteWarn: '此 {{field}} 将从所有关联文件中移除',
|
||||||
|
deleteManageFieldAllWarn:
|
||||||
|
'此字段及其所有对应值将从所有关联的文件中删除。',
|
||||||
|
deleteManageValueAllWarn: '此值将从所有关联的文件中删除。',
|
||||||
|
deleteManageFieldSingleWarn: '此字段及其所有对应值将从此文件中删除。',
|
||||||
|
deleteManageValueSingleWarn: '此值将从此文件中删除。',
|
||||||
},
|
},
|
||||||
localUpload: '本地上传',
|
localUpload: '本地上传',
|
||||||
fileSize: '文件大小',
|
fileSize: '文件大小',
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import kbService, {
|
|||||||
updateMetaData,
|
updateMetaData,
|
||||||
} from '@/services/knowledge-service';
|
} from '@/services/knowledge-service';
|
||||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { TFunction } from 'i18next';
|
||||||
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';
|
||||||
@ -19,12 +20,43 @@ import {
|
|||||||
IMetaDataTableData,
|
IMetaDataTableData,
|
||||||
MetadataOperations,
|
MetadataOperations,
|
||||||
ShowManageMetadataModalProps,
|
ShowManageMetadataModalProps,
|
||||||
} from './interface';
|
} from '../interface';
|
||||||
export enum MetadataType {
|
export enum MetadataType {
|
||||||
Manage = 1,
|
Manage = 1,
|
||||||
UpdateSingle = 2,
|
UpdateSingle = 2,
|
||||||
Setting = 3,
|
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 = {
|
export const util = {
|
||||||
changeToMetaDataTableData(data: IMetaDataReturnType): IMetaDataTableData[] {
|
changeToMetaDataTableData(data: IMetaDataReturnType): IMetaDataTableData[] {
|
||||||
return Object.entries(data).map(([key, value]) => {
|
return Object.entries(data).map(([key, value]) => {
|
||||||
@ -42,10 +74,21 @@ export const util = {
|
|||||||
data: Record<string, string | string[]>,
|
data: Record<string, string | string[]>,
|
||||||
): IMetaDataTableData[] {
|
): IMetaDataTableData[] {
|
||||||
return Object.entries(data).map(([key, value]) => {
|
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 {
|
return {
|
||||||
field: key,
|
field: key,
|
||||||
description: '',
|
description: '',
|
||||||
values: value,
|
values: thisValue,
|
||||||
} as IMetaDataTableData;
|
} 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(
|
const addUpdateValue = useCallback(
|
||||||
(key: string, value: string | string[]) => {
|
(key: string, originalValue: string, newValue: string) => {
|
||||||
setOperations((prev) => ({
|
setOperations((prev) => {
|
||||||
...prev,
|
const existsIndex = prev.updates.findIndex(
|
||||||
updates: [...prev.updates, { key, value }],
|
(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<IMetaDataTableData[]>(metaData);
|
const [tableData, setTableData] = useState<IMetaDataTableData[]>(metaData);
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { operations, addDeleteRow, addDeleteValue, addUpdateValue } =
|
const {
|
||||||
useMetadataOperations();
|
operations,
|
||||||
|
addDeleteRow,
|
||||||
|
addDeleteValue,
|
||||||
|
addUpdateValue,
|
||||||
|
resetOperations,
|
||||||
|
} = useMetadataOperations();
|
||||||
|
|
||||||
const { setDocumentMeta } = useSetDocumentMeta();
|
const { setDocumentMeta } = useSetDocumentMeta();
|
||||||
|
|
||||||
@ -265,11 +343,12 @@ export const useManageMetaDataModal = (
|
|||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: [DocumentApiAction.FetchDocumentList],
|
queryKey: [DocumentApiAction.FetchDocumentList],
|
||||||
});
|
});
|
||||||
|
resetOperations();
|
||||||
message.success(t('message.operated'));
|
message.success(t('message.operated'));
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[operations, id, t, queryClient],
|
[operations, id, t, queryClient, resetOperations],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSaveUpdateSingle = useCallback(
|
const handleSaveUpdateSingle = useCallback(
|
||||||
@ -303,7 +382,26 @@ export const useManageMetaDataModal = (
|
|||||||
|
|
||||||
return data;
|
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(
|
const handleSave = useCallback(
|
||||||
@ -317,12 +415,20 @@ export const useManageMetaDataModal = (
|
|||||||
break;
|
break;
|
||||||
case MetadataType.Setting:
|
case MetadataType.Setting:
|
||||||
return handleSaveSettings(callback);
|
return handleSaveSettings(callback);
|
||||||
|
case MetadataType.SingleFileSetting:
|
||||||
|
return handleSaveSingleFileSettings(callback);
|
||||||
default:
|
default:
|
||||||
handleSaveManage(callback);
|
handleSaveManage(callback);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[handleSaveManage, type, handleSaveUpdateSingle, handleSaveSettings],
|
[
|
||||||
|
handleSaveManage,
|
||||||
|
type,
|
||||||
|
handleSaveUpdateSingle,
|
||||||
|
handleSaveSettings,
|
||||||
|
handleSaveSingleFileSettings,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -377,11 +483,3 @@ export const useManageMetadata = () => {
|
|||||||
config,
|
config,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useManageValues = () => {
|
|
||||||
const [updateValues, setUpdateValues] = useState<{
|
|
||||||
field: string;
|
|
||||||
values: string[];
|
|
||||||
} | null>(null);
|
|
||||||
return { updateValues, setUpdateValues };
|
|
||||||
};
|
|
||||||
@ -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<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) => {
|
||||||
|
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]);
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -50,7 +50,11 @@ export interface IManageValuesProps {
|
|||||||
type: MetadataType;
|
type: MetadataType;
|
||||||
hideModal: () => void;
|
hideModal: () => void;
|
||||||
onSave: (data: IMetaDataTableData) => 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;
|
addDeleteValue: (key: string, value: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +65,8 @@ interface DeleteOperation {
|
|||||||
|
|
||||||
interface UpdateOperation {
|
interface UpdateOperation {
|
||||||
key: string;
|
key: string;
|
||||||
value: string | string[];
|
match: string;
|
||||||
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetadataOperations {
|
export interface MetadataOperations {
|
||||||
|
|||||||
@ -25,11 +25,16 @@ import {
|
|||||||
useReactTable,
|
useReactTable,
|
||||||
} from '@tanstack/react-table';
|
} from '@tanstack/react-table';
|
||||||
import { Plus, Settings, Trash2 } from 'lucide-react';
|
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 { useTranslation } from 'react-i18next';
|
||||||
import { MetadataType, useManageMetaDataModal } from './hook';
|
import {
|
||||||
|
MetadataDeleteMap,
|
||||||
|
MetadataType,
|
||||||
|
useManageMetaDataModal,
|
||||||
|
} from './hooks/use-manage-modal';
|
||||||
import { IManageModalProps, IMetaDataTableData } from './interface';
|
import { IManageModalProps, IMetaDataTableData } from './interface';
|
||||||
import { ManageValuesModal } from './manage-values-modal';
|
import { ManageValuesModal } from './manage-values-modal';
|
||||||
|
|
||||||
export const ManageMetadataModal = (props: IManageModalProps) => {
|
export const ManageMetadataModal = (props: IManageModalProps) => {
|
||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
@ -134,7 +139,8 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
|
|||||||
const values = row.getValue('values') as Array<string>;
|
const values = row.getValue('values') as Array<string>;
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
{values.length > 0 &&
|
{Array.isArray(values) &&
|
||||||
|
values.length > 0 &&
|
||||||
values
|
values
|
||||||
.filter((value: string, index: number) => index < 2)
|
.filter((value: string, index: number) => index < 2)
|
||||||
?.map((value: string) => {
|
?.map((value: string) => {
|
||||||
@ -159,17 +165,12 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
|
|||||||
title:
|
title:
|
||||||
t('common.delete') +
|
t('common.delete') +
|
||||||
' ' +
|
' ' +
|
||||||
t('knowledgeDetails.metadata.metadata'),
|
t('knowledgeDetails.metadata.value'),
|
||||||
name: row.getValue('field') + '/' + value,
|
name: value,
|
||||||
warnText: t(
|
warnText:
|
||||||
'knowledgeDetails.metadata.deleteWarn',
|
MetadataDeleteMap(t)[
|
||||||
{
|
metadataType as MetadataType
|
||||||
field:
|
].warnValueText,
|
||||||
t('knowledgeDetails.metadata.field') +
|
|
||||||
'/' +
|
|
||||||
t('knowledgeDetails.metadata.values'),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
hideDeleteModal();
|
hideDeleteModal();
|
||||||
handleDeleteSingleValue(
|
handleDeleteSingleValue(
|
||||||
@ -190,7 +191,7 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
|
|||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{values.length > 2 && (
|
{Array.isArray(values) && values.length > 2 && (
|
||||||
<div className="text-text-secondary self-end">...</div>
|
<div className="text-text-secondary self-end">...</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -221,13 +222,14 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
|
|||||||
setDeleteDialogContent({
|
setDeleteDialogContent({
|
||||||
visible: true,
|
visible: true,
|
||||||
title:
|
title:
|
||||||
t('common.delete') +
|
// t('common.delete') +
|
||||||
' ' +
|
// ' ' +
|
||||||
t('knowledgeDetails.metadata.metadata'),
|
// t('knowledgeDetails.metadata.metadata')
|
||||||
|
MetadataDeleteMap(t)[metadataType as MetadataType].title,
|
||||||
name: row.getValue('field'),
|
name: row.getValue('field'),
|
||||||
warnText: t('knowledgeDetails.metadata.deleteWarn', {
|
warnText:
|
||||||
field: t('knowledgeDetails.metadata.field'),
|
MetadataDeleteMap(t)[metadataType as MetadataType]
|
||||||
}),
|
.warnFieldText,
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
hideDeleteModal();
|
hideDeleteModal();
|
||||||
handleDeleteSingleRow(row.getValue('field'));
|
handleDeleteSingleRow(row.getValue('field'));
|
||||||
@ -266,7 +268,7 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
|
|||||||
getFilteredRowModel: getFilteredRowModel(),
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
manualPagination: true,
|
manualPagination: true,
|
||||||
});
|
});
|
||||||
|
const [shouldSave, setShouldSave] = useState(false);
|
||||||
const handleSaveValues = (data: IMetaDataTableData) => {
|
const handleSaveValues = (data: IMetaDataTableData) => {
|
||||||
setTableData((prev) => {
|
setTableData((prev) => {
|
||||||
let newData;
|
let newData;
|
||||||
@ -300,8 +302,20 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
|
|||||||
|
|
||||||
return Array.from(fieldMap.values());
|
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(() => {
|
const existsKeys = useMemo(() => {
|
||||||
return tableData.map((item) => item.field);
|
return tableData.map((item) => item.field);
|
||||||
}, [tableData]);
|
}, [tableData]);
|
||||||
@ -386,7 +400,8 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
|
|||||||
<ManageValuesModal
|
<ManageValuesModal
|
||||||
title={
|
title={
|
||||||
<div>
|
<div>
|
||||||
{metadataType === MetadataType.Setting
|
{metadataType === MetadataType.Setting ||
|
||||||
|
metadataType === MetadataType.SingleFileSetting
|
||||||
? t('knowledgeDetails.metadata.fieldSetting')
|
? t('knowledgeDetails.metadata.fieldSetting')
|
||||||
: t('knowledgeDetails.metadata.editMetadata')}
|
: t('knowledgeDetails.metadata.editMetadata')}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -9,10 +9,10 @@ import { Modal } from '@/components/ui/modal/modal';
|
|||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
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 } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { MetadataType } from './hook';
|
import { useManageValues } from './hooks/use-manage-values-modal';
|
||||||
import { IManageValuesProps, IMetaDataTableData } from './interface';
|
import { IManageValuesProps } 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
|
||||||
const ValueInputItem = memo(
|
const ValueInputItem = memo(
|
||||||
@ -57,188 +57,28 @@ const ValueInputItem = memo(
|
|||||||
export const ManageValuesModal = (props: IManageValuesProps) => {
|
export const ManageValuesModal = (props: IManageValuesProps) => {
|
||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
data,
|
|
||||||
isEditField,
|
isEditField,
|
||||||
visible,
|
visible,
|
||||||
isAddValue,
|
isAddValue,
|
||||||
isShowDescription,
|
isShowDescription,
|
||||||
isShowValueSwitch,
|
isShowValueSwitch,
|
||||||
isVerticalShowValue,
|
isVerticalShowValue,
|
||||||
hideModal,
|
|
||||||
onSave,
|
|
||||||
addUpdateValue,
|
|
||||||
addDeleteValue,
|
|
||||||
existsKeys,
|
|
||||||
type,
|
|
||||||
} = props;
|
} = 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 { 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) => {
|
|
||||||
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]);
|
|
||||||
|
|
||||||
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 (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@ -35,7 +35,8 @@ import {
|
|||||||
MetadataType,
|
MetadataType,
|
||||||
useManageMetadata,
|
useManageMetadata,
|
||||||
util,
|
util,
|
||||||
} from '../../components/metedata/hook';
|
} from '../../components/metedata/hooks/use-manage-modal';
|
||||||
|
import { IMetaDataReturnJSONSettings } from '../../components/metedata/interface';
|
||||||
import { ManageMetadataModal } from '../../components/metedata/manage-modal';
|
import { ManageMetadataModal } from '../../components/metedata/manage-modal';
|
||||||
import {
|
import {
|
||||||
useHandleKbEmbedding,
|
useHandleKbEmbedding,
|
||||||
@ -359,7 +360,13 @@ export function OverlappedPercent() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AutoMetadata() {
|
export function AutoMetadata({
|
||||||
|
type = MetadataType.Setting,
|
||||||
|
otherData,
|
||||||
|
}: {
|
||||||
|
type?: MetadataType;
|
||||||
|
otherData?: Record<string, any>;
|
||||||
|
}) {
|
||||||
// get metadata field
|
// get metadata field
|
||||||
const form = useFormContext();
|
const form = useFormContext();
|
||||||
const {
|
const {
|
||||||
@ -369,6 +376,7 @@ export function AutoMetadata() {
|
|||||||
tableData,
|
tableData,
|
||||||
config: metadataConfig,
|
config: metadataConfig,
|
||||||
} = useManageMetadata();
|
} = useManageMetadata();
|
||||||
|
|
||||||
const autoMetadataField: FormFieldConfig = {
|
const autoMetadataField: FormFieldConfig = {
|
||||||
name: 'parser_config.enable_metadata',
|
name: 'parser_config.enable_metadata',
|
||||||
label: t('knowledgeConfiguration.autoMetadata'),
|
label: t('knowledgeConfiguration.autoMetadata'),
|
||||||
@ -379,6 +387,7 @@ export function AutoMetadata() {
|
|||||||
render: (fieldProps: ControllerRenderProps) => (
|
render: (fieldProps: ControllerRenderProps) => (
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<Button
|
<Button
|
||||||
|
type="button"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const metadata = form.getValues('parser_config.metadata');
|
const metadata = form.getValues('parser_config.metadata');
|
||||||
@ -387,7 +396,8 @@ export function AutoMetadata() {
|
|||||||
showManageMetadataModal({
|
showManageMetadataModal({
|
||||||
metadata: tableMetaData,
|
metadata: tableMetaData,
|
||||||
isCanAdd: true,
|
isCanAdd: true,
|
||||||
type: MetadataType.Setting,
|
type: type,
|
||||||
|
record: otherData,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -403,6 +413,10 @@ export function AutoMetadata() {
|
|||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSaveMetadata = (data?: IMetaDataReturnJSONSettings) => {
|
||||||
|
form.setValue('parser_config.metadata', data || []);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RenderField field={autoMetadataField} />
|
<RenderField field={autoMetadataField} />
|
||||||
@ -431,8 +445,8 @@ export function AutoMetadata() {
|
|||||||
isShowDescription={true}
|
isShowDescription={true}
|
||||||
isShowValueSwitch={true}
|
isShowValueSwitch={true}
|
||||||
isVerticalShowValue={false}
|
isVerticalShowValue={false}
|
||||||
success={(data) => {
|
success={(data?: IMetaDataReturnJSONSettings) => {
|
||||||
form.setValue('parser_config.metadata', data || []);
|
handleSaveMetadata(data);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -96,7 +96,7 @@ export const formSchema = z
|
|||||||
)
|
)
|
||||||
.optional(),
|
.optional(),
|
||||||
enable_metadata: z.boolean().optional(),
|
enable_metadata: z.boolean().optional(),
|
||||||
llm_id: z.string().optional(),
|
llm_id: z.string().min(1, { message: 'Indexing model is required' }),
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
pagerank: z.number(),
|
pagerank: z.number(),
|
||||||
|
|||||||
@ -16,7 +16,10 @@ import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-reques
|
|||||||
import { Pen, Upload } from 'lucide-react';
|
import { Pen, Upload } from 'lucide-react';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
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 { ManageMetadataModal } from '../components/metedata/manage-modal';
|
||||||
import { DatasetTable } from './dataset-table';
|
import { DatasetTable } from './dataset-table';
|
||||||
import Generate from './generate-button/generate';
|
import Generate from './generate-button/generate';
|
||||||
|
|||||||
@ -16,7 +16,10 @@ import { formatDate } from '@/utils/date';
|
|||||||
import { ColumnDef } from '@tanstack/table-core';
|
import { ColumnDef } from '@tanstack/table-core';
|
||||||
import { ArrowUpDown, MonitorUp } from 'lucide-react';
|
import { ArrowUpDown, MonitorUp } from 'lucide-react';
|
||||||
import { useTranslation } from 'react-i18next';
|
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 { ShowManageMetadataModalProps } from '../components/metedata/interface';
|
||||||
import { DatasetActionCell } from './dataset-action-cell';
|
import { DatasetActionCell } from './dataset-action-cell';
|
||||||
import { ParsingStatusCell } from './parsing-status-cell';
|
import { ParsingStatusCell } from './parsing-status-cell';
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
import FileStatusBadge from '@/components/file-status-badge';
|
import FileStatusBadge from '@/components/file-status-badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Modal } from '@/components/ui/modal/modal';
|
import { Modal } from '@/components/ui/modal/modal';
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from '@/components/ui/tooltip';
|
||||||
import { RunningStatusMap } from '@/constants/knowledge';
|
import { RunningStatusMap } from '@/constants/knowledge';
|
||||||
import { useTranslate } from '@/hooks/common-hooks';
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
@ -40,7 +45,14 @@ const InfoItem: React.FC<{
|
|||||||
return (
|
return (
|
||||||
<div className={`flex flex-col mb-4 ${className}`}>
|
<div className={`flex flex-col mb-4 ${className}`}>
|
||||||
<span className="text-text-secondary text-sm">{label}</span>
|
<span className="text-text-secondary text-sm">{label}</span>
|
||||||
<span className="text-text-primary mt-1">{value}</span>
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<span className="text-text-primary mt-1 truncate max-w-[200px]">
|
||||||
|
{value}
|
||||||
|
</span>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>{value}</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -70,9 +82,7 @@ const ProcessLogModal: React.FC<ProcessLogModalProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslate('knowledgeDetails');
|
const { t } = useTranslate('knowledgeDetails');
|
||||||
const blackKeyList = [''];
|
const blackKeyList = [''];
|
||||||
console.log('logInfo', initData);
|
|
||||||
const logInfo = useMemo(() => {
|
const logInfo = useMemo(() => {
|
||||||
console.log('logInfo', initData);
|
|
||||||
return initData;
|
return initData;
|
||||||
}, [initData]);
|
}, [initData]);
|
||||||
|
|
||||||
|
|||||||
@ -48,10 +48,10 @@ const {
|
|||||||
traceRaptor,
|
traceRaptor,
|
||||||
check_embedding,
|
check_embedding,
|
||||||
kbUpdateMetaData,
|
kbUpdateMetaData,
|
||||||
|
documentUpdateMetaData,
|
||||||
} = api;
|
} = api;
|
||||||
|
|
||||||
const methods = {
|
const methods = {
|
||||||
// 知识库管理
|
|
||||||
createKb: {
|
createKb: {
|
||||||
url: create_kb,
|
url: create_kb,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
@ -220,6 +220,10 @@ const methods = {
|
|||||||
url: kbUpdateMetaData,
|
url: kbUpdateMetaData,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
},
|
},
|
||||||
|
documentUpdateMetaData: {
|
||||||
|
url: documentUpdateMetaData,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
// getMetaData: {
|
// getMetaData: {
|
||||||
// url: getMetaData,
|
// url: getMetaData,
|
||||||
// method: 'get',
|
// method: 'get',
|
||||||
|
|||||||
@ -80,6 +80,7 @@ export default {
|
|||||||
getMetaData: `${api_host}/document/metadata/summary`,
|
getMetaData: `${api_host}/document/metadata/summary`,
|
||||||
updateMetaData: `${api_host}/document/metadata/update`,
|
updateMetaData: `${api_host}/document/metadata/update`,
|
||||||
kbUpdateMetaData: `${api_host}/kb/update_metadata_setting`,
|
kbUpdateMetaData: `${api_host}/kb/update_metadata_setting`,
|
||||||
|
documentUpdateMetaData: `${api_host}/document/update_metadata_setting`,
|
||||||
|
|
||||||
// tags
|
// tags
|
||||||
listTag: (knowledgeId: string) => `${api_host}/kb/${knowledgeId}/tags`,
|
listTag: (knowledgeId: string) => `${api_host}/kb/${knowledgeId}/tags`,
|
||||||
|
|||||||
Reference in New Issue
Block a user