mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-01-30 07:06:39 +08:00
Fix: Issues with metadata parameter addition failures and single-file chunk saving failures. (#12818)
### What problem does this PR solve? Fix: Issues with metadata parameter addition failures and single-file chunk saving failures. ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@ -144,15 +144,13 @@ export function ChunkMethodDialog({
|
||||
pages: z
|
||||
.array(z.object({ from: z.coerce.number(), to: z.coerce.number() }))
|
||||
.optional(),
|
||||
metadata: z
|
||||
metadata: z.any().optional(),
|
||||
built_in_metadata: z
|
||||
.array(
|
||||
z
|
||||
.object({
|
||||
key: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
enum: z.array(z.string().optional()).optional(),
|
||||
})
|
||||
.optional(),
|
||||
z.object({
|
||||
key: z.string().optional(),
|
||||
type: z.string().optional(),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
enable_metadata: z.boolean().optional(),
|
||||
|
||||
@ -184,6 +184,7 @@ Example: A 1 KB message with 1024-dim embedding uses ~9 KB. The 5 MB default lim
|
||||
},
|
||||
knowledgeDetails: {
|
||||
metadata: {
|
||||
selectFiles: 'Selected {{count}} files',
|
||||
type: 'Type',
|
||||
fieldNameInvalid: 'Field name can only contain letters or underscores.',
|
||||
builtIn: 'Built-in',
|
||||
@ -205,10 +206,10 @@ Example: A 1 KB message with 1024-dim embedding uses ~9 KB. The 5 MB default lim
|
||||
fieldExists: 'Field already exists.',
|
||||
fieldSetting: 'Field settings',
|
||||
changesAffectNewParses: 'Changes affect new parses only.',
|
||||
editMetadataForDataset: 'View and edit metadata for ',
|
||||
// editMetadataForDataset: 'View and edit metadata for ',
|
||||
restrictDefinedValues: 'Restrict to defined values',
|
||||
metadataGenerationSettings: 'Metadata generation settings',
|
||||
manageMetadataForDataset: 'Manage metadata for this dataset',
|
||||
// manageMetadataForDataset: 'Manage metadata for this dataset',
|
||||
manageMetadata: 'Manage metadata',
|
||||
metadata: 'Metadata',
|
||||
values: 'Values',
|
||||
|
||||
@ -175,6 +175,7 @@ export default {
|
||||
},
|
||||
knowledgeDetails: {
|
||||
metadata: {
|
||||
selectFiles: '已选择 {{count}} 个文件',
|
||||
type: '类型',
|
||||
fieldNameInvalid: '字段名称只能包含字母或下划线。',
|
||||
builtIn: '内置',
|
||||
@ -192,10 +193,10 @@ export default {
|
||||
fieldExists: '字段名已存在。',
|
||||
fieldSetting: '字段设置',
|
||||
changesAffectNewParses: '更改仅影响新的解析。',
|
||||
editMetadataForDataset: '查看和编辑元数据 ',
|
||||
// editMetadataForDataset: '查看和编辑元数据 ',
|
||||
restrictDefinedValues: '限制为已定义的值',
|
||||
metadataGenerationSettings: '元数据生成设置',
|
||||
manageMetadataForDataset: '管理此数据集的元数据',
|
||||
// manageMetadataForDataset: '管理此数据集的元数据',
|
||||
manageMetadata: '管理元数据',
|
||||
metadata: '元数据',
|
||||
values: '值',
|
||||
|
||||
@ -11,11 +11,7 @@ import { RowSelectionState } from '@tanstack/react-table';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useParams } from 'react-router';
|
||||
import {
|
||||
DEFAULT_VALUE_TYPE,
|
||||
MetadataType,
|
||||
metadataValueTypeEnum,
|
||||
} from '../constant';
|
||||
import { DEFAULT_VALUE_TYPE, MetadataType } from '../constant';
|
||||
import {
|
||||
IBuiltInMetadataItem,
|
||||
IMetaDataReturnJSONSettings,
|
||||
@ -25,6 +21,7 @@ import {
|
||||
MetadataOperations,
|
||||
MetadataValueType,
|
||||
ShowManageMetadataModalProps,
|
||||
UpdateOperation,
|
||||
} from '../interface';
|
||||
|
||||
export const util = {
|
||||
@ -136,6 +133,7 @@ export const useMetadataOperations = () => {
|
||||
deletes: [],
|
||||
updates: [],
|
||||
});
|
||||
// const operationsRef = useRef(operations);
|
||||
|
||||
const addDeleteRow = useCallback((key: string) => {
|
||||
setOperations((prev) => ({
|
||||
@ -165,41 +163,60 @@ export const useMetadataOperations = () => {
|
||||
newValue: string | string[],
|
||||
type?: MetadataValueType,
|
||||
) => {
|
||||
let newValuesRes: string | string[];
|
||||
if (type !== metadataValueTypeEnum['list']) {
|
||||
if (Array.isArray(newValue) && newValue.length > 0) {
|
||||
newValuesRes = newValue[0];
|
||||
} else {
|
||||
newValuesRes = newValue;
|
||||
}
|
||||
} else {
|
||||
newValuesRes = newValue;
|
||||
}
|
||||
// let newValuesRes: string | string[];
|
||||
// if (type !== metadataValueTypeEnum['list']) {
|
||||
// if (Array.isArray(newValue) && newValue.length > 0) {
|
||||
// newValuesRes = newValue[0];
|
||||
// } else {
|
||||
// newValuesRes = newValue;
|
||||
// }
|
||||
// } else {
|
||||
// newValuesRes = newValue;
|
||||
// }
|
||||
setOperations((prev) => {
|
||||
let updatedUpdates = [...prev.updates];
|
||||
const existsIndex = prev.updates.findIndex(
|
||||
(update) => update.key === key && update.match === originalValue,
|
||||
(update) =>
|
||||
update.key === key &&
|
||||
update.match === originalValue &&
|
||||
update.match !== '',
|
||||
);
|
||||
|
||||
if (existsIndex > -1) {
|
||||
const updatedUpdates = [...prev.updates];
|
||||
updatedUpdates[existsIndex] = {
|
||||
key,
|
||||
match: originalValue,
|
||||
value: newValuesRes,
|
||||
value: newValue,
|
||||
valueType: type || DEFAULT_VALUE_TYPE,
|
||||
};
|
||||
return {
|
||||
...prev,
|
||||
updates: updatedUpdates,
|
||||
};
|
||||
|
||||
// operationsRef.current = updatedOperations;
|
||||
} else {
|
||||
updatedUpdates.push({
|
||||
key,
|
||||
match: originalValue,
|
||||
value: newValue,
|
||||
valueType: type,
|
||||
});
|
||||
}
|
||||
return {
|
||||
updatedUpdates = updatedUpdates.reduce((pre, cur) => {
|
||||
if (
|
||||
!pre.some(
|
||||
(item) =>
|
||||
item.key === cur.key &&
|
||||
item.match === cur.match &&
|
||||
item.value === cur.value,
|
||||
)
|
||||
) {
|
||||
pre.push(cur);
|
||||
}
|
||||
return pre;
|
||||
}, [] as UpdateOperation[]);
|
||||
|
||||
const updatedOperations = {
|
||||
...prev,
|
||||
updates: [
|
||||
...prev.updates,
|
||||
{ key, match: originalValue, value: newValuesRes, valueType: type },
|
||||
],
|
||||
updates: updatedUpdates,
|
||||
};
|
||||
return updatedOperations;
|
||||
});
|
||||
},
|
||||
[],
|
||||
@ -213,6 +230,7 @@ export const useMetadataOperations = () => {
|
||||
}, []);
|
||||
|
||||
return {
|
||||
// operationsRef,
|
||||
operations,
|
||||
addDeleteBatch,
|
||||
addDeleteRow,
|
||||
@ -272,6 +290,7 @@ export const useManageMetaDataModal = (
|
||||
const [tableData, setTableData] = useState<IMetaDataTableData[]>(metaData);
|
||||
const queryClient = useQueryClient();
|
||||
const {
|
||||
// operationsRef,
|
||||
operations,
|
||||
addDeleteRow,
|
||||
addDeleteBatch,
|
||||
|
||||
@ -72,6 +72,7 @@ export type IManageModalProps = {
|
||||
isVerticalShowValue?: boolean;
|
||||
builtInMetadata?: IBuiltInMetadataItem[];
|
||||
success?: (data: any) => void;
|
||||
secondTitle?: ReactNode;
|
||||
};
|
||||
|
||||
export interface IManageValuesProps {
|
||||
@ -98,12 +99,12 @@ export interface IManageValuesProps {
|
||||
addDeleteValue: (key: string, value: string) => void;
|
||||
}
|
||||
|
||||
interface DeleteOperation {
|
||||
export interface DeleteOperation {
|
||||
key: string;
|
||||
value?: string;
|
||||
}
|
||||
|
||||
interface UpdateOperation {
|
||||
export interface UpdateOperation {
|
||||
key: string;
|
||||
match: string;
|
||||
value: string | string[];
|
||||
|
||||
@ -4,12 +4,7 @@ import { Input } from '@/components/ui/input';
|
||||
import { DateInput } from '@/components/ui/input-date';
|
||||
import { formatDate } from '@/utils/date';
|
||||
import { ColumnDef, Row, Table } from '@tanstack/react-table';
|
||||
import {
|
||||
ListChevronsDownUp,
|
||||
ListChevronsUpDown,
|
||||
Settings,
|
||||
Trash2,
|
||||
} from 'lucide-react';
|
||||
import { ListChevronsDownUp, Settings, Trash2 } from 'lucide-react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
@ -51,12 +46,16 @@ export const useMetadataColumns = ({
|
||||
onOk: () => {},
|
||||
onCancel: () => {},
|
||||
});
|
||||
const [expanded, setExpanded] = useState(true);
|
||||
// const [expanded, setExpanded] = useState(true);
|
||||
const [editingValue, setEditingValue] = useState<{
|
||||
field: string;
|
||||
value: string;
|
||||
newValue: string;
|
||||
} | null>(null);
|
||||
const [rowExpandedStates, setRowExpandedStates] = useState<
|
||||
Record<string, boolean>
|
||||
>({});
|
||||
|
||||
const isSettingsMode =
|
||||
metadataType === MetadataType.Setting ||
|
||||
metadataType === MetadataType.SingleFileSetting ||
|
||||
@ -142,21 +141,7 @@ export const useMetadataColumns = ({
|
||||
</div>
|
||||
),
|
||||
},
|
||||
// ...(showTypeColumn
|
||||
// ? ([
|
||||
// {
|
||||
// accessorKey: 'valueType',
|
||||
// header: () => <span>Type</span>,
|
||||
// cell: ({ row }) => (
|
||||
// <div className="text-sm">
|
||||
// {getMetadataValueTypeLabel(
|
||||
// row.original.valueType as IMetaDataTableData['valueType'],
|
||||
// )}
|
||||
// </div>
|
||||
// ),
|
||||
// },
|
||||
// ] as ColumnDef<IMetaDataTableData>[])
|
||||
// : []),
|
||||
|
||||
{
|
||||
accessorKey: 'description',
|
||||
header: () => <span>{t('knowledgeDetails.metadata.description')}</span>,
|
||||
@ -182,7 +167,7 @@ export const useMetadataColumns = ({
|
||||
header: () => (
|
||||
<div className="flex items-center">
|
||||
<span>{t('knowledgeDetails.metadata.values')}</span>
|
||||
<div
|
||||
{/* <div
|
||||
className="ml-2 p-1 cursor-pointer"
|
||||
onClick={() => {
|
||||
setExpanded(!expanded);
|
||||
@ -194,16 +179,25 @@ export const useMetadataColumns = ({
|
||||
<ListChevronsUpDown size={14} />
|
||||
)}
|
||||
{expanded}
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const values = row.getValue('values') as Array<string>;
|
||||
const displayedValues = expanded ? values : values.slice(0, 2);
|
||||
const isRowExpanded = rowExpandedStates[row.original.field] ?? false;
|
||||
|
||||
const toggleRowExpanded = () => {
|
||||
setRowExpandedStates((prev) => ({
|
||||
...prev,
|
||||
[row.original.field]: !isRowExpanded,
|
||||
}));
|
||||
};
|
||||
|
||||
const displayedValues = isRowExpanded ? values : values.slice(0, 2);
|
||||
const hasMore = Array.isArray(values) && values.length > 2;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex gap-1">
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{displayedValues?.map((value: string) => {
|
||||
const isEditing =
|
||||
@ -218,7 +212,6 @@ export const useMetadataColumns = ({
|
||||
<DateInput
|
||||
value={new Date(editingValue.newValue)}
|
||||
onChange={(value) => {
|
||||
console.log('value', value);
|
||||
const newValue = {
|
||||
...editingValue,
|
||||
newValue: formatDate(
|
||||
@ -228,13 +221,7 @@ export const useMetadataColumns = ({
|
||||
};
|
||||
setEditingValue(newValue);
|
||||
saveEditedValue(newValue);
|
||||
// onValueChange(index, formatDate(value), true);
|
||||
}}
|
||||
// openChange={(open) => {
|
||||
// console.log('open', open);
|
||||
// if (!open) {
|
||||
// }
|
||||
// }}
|
||||
showTimeSelect={true}
|
||||
/>
|
||||
)}
|
||||
@ -249,7 +236,7 @@ export const useMetadataColumns = ({
|
||||
newValue: e.target.value,
|
||||
})
|
||||
}
|
||||
onBlur={saveEditedValue}
|
||||
onBlur={() => saveEditedValue()}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
saveEditedValue();
|
||||
@ -316,10 +303,37 @@ export const useMetadataColumns = ({
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
{hasMore && !expanded && (
|
||||
<div className="text-text-secondary self-end">...</div>
|
||||
)}
|
||||
</div>
|
||||
{hasMore && !isRowExpanded && (
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
className="border border-border-button h-auto px-2 py-1"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
toggleRowExpanded();
|
||||
}}
|
||||
>
|
||||
<div className="text-text-secondary">
|
||||
+{values.length - 2}
|
||||
</div>
|
||||
</Button>
|
||||
)}
|
||||
{hasMore && isRowExpanded && (
|
||||
// <div className="self-end mt-1">
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
className="bg-transparent px-2 py-1"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
toggleRowExpanded();
|
||||
}}
|
||||
>
|
||||
<div className="text-text-secondary">
|
||||
<ListChevronsDownUp size={14} />
|
||||
</div>
|
||||
</Button>
|
||||
// </div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@ -390,10 +404,10 @@ export const useMetadataColumns = ({
|
||||
isDeleteSingleValue,
|
||||
handleEditValueRow,
|
||||
metadataType,
|
||||
expanded,
|
||||
// expanded,
|
||||
editingValue,
|
||||
saveEditedValue,
|
||||
showTypeColumn,
|
||||
rowExpandedStates,
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
@ -69,6 +69,7 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
|
||||
builtInMetadata,
|
||||
success,
|
||||
documentIds,
|
||||
secondTitle,
|
||||
} = props;
|
||||
const { t } = useTranslation();
|
||||
const [valueData, setValueData] = useState<IMetaDataTableData>({
|
||||
@ -316,7 +317,9 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
|
||||
<>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>{t('knowledgeDetails.metadata.metadata')}</div>
|
||||
<div className="w-1/2">
|
||||
{secondTitle || t('knowledgeDetails.metadata.metadata')}
|
||||
</div>
|
||||
<div>
|
||||
{metadataType === MetadataType.Manage && (
|
||||
<Button
|
||||
@ -564,7 +567,7 @@ export const ManageMetadataModal = (props: IManageModalProps) => {
|
||||
isAddValue={isAddValue || isAddValueMode}
|
||||
isShowDescription={isShowDescription}
|
||||
isShowValueSwitch={isShowValueSwitch}
|
||||
isShowType={isSettingsMode}
|
||||
isShowType={true}
|
||||
isVerticalShowValue={isVerticalShowValue}
|
||||
isAddValueMode={isAddValueMode}
|
||||
// handleDeleteSingleValue={handleDeleteSingleValue}
|
||||
|
||||
@ -40,11 +40,13 @@ import {
|
||||
util,
|
||||
} from '../../components/metedata/hooks/use-manage-modal';
|
||||
|
||||
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
|
||||
import {
|
||||
IBuiltInMetadataItem,
|
||||
IMetaDataReturnJSONSettings,
|
||||
} from '../../components/metedata/interface';
|
||||
import { ManageMetadataModal } from '../../components/metedata/manage-modal';
|
||||
import { useKnowledgeBaseContext } from '../../contexts/knowledge-base-context';
|
||||
import {
|
||||
useHandleKbEmbedding,
|
||||
useHasParsedDocument,
|
||||
@ -378,6 +380,7 @@ export function AutoMetadata({
|
||||
const location = useLocation();
|
||||
const form = useFormContext();
|
||||
const datasetContext = useContext(DataSetContext);
|
||||
const { knowledgeBase } = useKnowledgeBaseContext();
|
||||
const {
|
||||
manageMetadataVisible,
|
||||
showManageMetadataModal,
|
||||
@ -396,16 +399,31 @@ export function AutoMetadata({
|
||||
type: type,
|
||||
record: otherData,
|
||||
builtInMetadata,
|
||||
secondTitle: knowledgeBase ? (
|
||||
<div className="w-full flex items-center gap-1 text-sm text-text-secondary">
|
||||
<RAGFlowAvatar
|
||||
avatar={knowledgeBase.avatar}
|
||||
name={knowledgeBase.name}
|
||||
className="size-8"
|
||||
></RAGFlowAvatar>
|
||||
<div className=" text-text-primary text-base space-y-1 overflow-hidden">
|
||||
{knowledgeBase.name}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
),
|
||||
});
|
||||
}, [form, otherData, showManageMetadataModal, type]);
|
||||
}, [form, otherData, showManageMetadataModal, knowledgeBase, type]);
|
||||
|
||||
useEffect(() => {
|
||||
const locationState = location.state as
|
||||
| { openMetadata?: boolean }
|
||||
| undefined;
|
||||
if (locationState?.openMetadata && !datasetContext?.loading) {
|
||||
setTimeout(() => {
|
||||
const timer = setTimeout(() => {
|
||||
handleClickOpenMetadata();
|
||||
clearTimeout(timer);
|
||||
}, 0);
|
||||
locationState.openMetadata = false;
|
||||
history.replace({ ...location }, locationState);
|
||||
@ -475,6 +493,7 @@ export function AutoMetadata({
|
||||
isShowValueSwitch={true}
|
||||
isVerticalShowValue={false}
|
||||
builtInMetadata={metadataConfig.builtInMetadata}
|
||||
secondTitle={metadataConfig.secondTitle}
|
||||
success={(data?: {
|
||||
metadata?: IMetaDataReturnJSONSettings;
|
||||
builtInMetadata?: IBuiltInMetadataItem[];
|
||||
|
||||
@ -104,14 +104,21 @@ export default function Dataset() {
|
||||
isEditField: false,
|
||||
isDeleteSingleValue: true,
|
||||
isAddValue: true,
|
||||
secondTitle: (
|
||||
<>
|
||||
{t('knowledgeDetails.metadata.selectFiles', {
|
||||
count: documents.length,
|
||||
})}
|
||||
</>
|
||||
),
|
||||
title: (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="text-base font-normal">
|
||||
{t('knowledgeDetails.metadata.manageMetadata')}
|
||||
</div>
|
||||
<div className="text-sm text-text-secondary">
|
||||
{/* <div className="text-sm text-text-secondary">
|
||||
{t('knowledgeDetails.metadata.manageMetadataForDataset')}
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
),
|
||||
documentIds: documents.map((doc) => doc.id),
|
||||
@ -240,9 +247,9 @@ export default function Dataset() {
|
||||
<div className="text-base font-normal">
|
||||
{t('knowledgeDetails.metadata.manageMetadata')}
|
||||
</div>
|
||||
<div className="text-sm text-text-secondary">
|
||||
{/* <div className="text-sm text-text-secondary">
|
||||
{t('knowledgeDetails.metadata.manageMetadataForDataset')}
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -255,6 +262,7 @@ export default function Dataset() {
|
||||
isVerticalShowValue={metadataConfig.isVerticalShowValue}
|
||||
isEditField={metadataConfig.isEditField}
|
||||
isDeleteSingleValue={metadataConfig.isDeleteSingleValue}
|
||||
secondTitle={metadataConfig.secondTitle}
|
||||
type={metadataConfig.type}
|
||||
documentIds={metadataConfig.documentIds}
|
||||
otherData={metadataConfig.record}
|
||||
|
||||
@ -9,7 +9,14 @@ import {
|
||||
useSetDocumentStatus,
|
||||
} from '@/hooks/use-document-request';
|
||||
import { IDocumentInfo } from '@/interfaces/database/document';
|
||||
import { Ban, CircleCheck, CircleX, PenIcon, Play, Trash2 } from 'lucide-react';
|
||||
import {
|
||||
Ban,
|
||||
CircleCheck,
|
||||
CircleX,
|
||||
Cylinder,
|
||||
Play,
|
||||
Trash2,
|
||||
} from 'lucide-react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { toast } from 'sonner';
|
||||
@ -143,7 +150,7 @@ export function useBulkOperateDataset({
|
||||
{
|
||||
id: 'batch-metadata',
|
||||
label: t('knowledgeDetails.metadata.metadata'),
|
||||
icon: <PenIcon />,
|
||||
icon: <Cylinder />,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@ -191,10 +191,16 @@ export function useDatasetTableColumns({
|
||||
<div className="text-base font-normal">
|
||||
{t('metadata.editMetadata')}
|
||||
</div>
|
||||
<div className="text-sm text-text-secondary w-full truncate">
|
||||
{/* <div className="text-sm text-text-secondary w-full truncate">
|
||||
{t('metadata.editMetadataForDataset')}
|
||||
{row.original.name}
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
),
|
||||
secondTitle: (
|
||||
<div className="w-full flex gap-1 text-sm text-text-secondary">
|
||||
<FileIcon name={row.original.name}></FileIcon>
|
||||
<div className="truncate">{row.original.name}</div>
|
||||
</div>
|
||||
),
|
||||
isDeleteSingleValue: true,
|
||||
|
||||
Reference in New Issue
Block a user