Fix: When creating a dataset, if no chunk_method is selected, there is no indication that this is a required field. (#14039)

### What problem does this PR solve?
Fix: When creating a dataset, if no `chunk_method` is selected, there is
no indication that this is a required field.

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
balibabu
2026-04-10 19:05:14 +08:00
committed by GitHub
parent 82d74fd276
commit 462be53b76
14 changed files with 93 additions and 205 deletions

View File

@@ -13,7 +13,7 @@ import {
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { DocumentParserType } from '@/constants/knowledge';
import { DocumentParserType, ParseType } from '@/constants/knowledge';
import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request';
import { IModalProps } from '@/interfaces/common';
import { IParserConfig } from '@/interfaces/database/document';
@@ -102,7 +102,7 @@ export function ChunkMethodDialog({
const FormSchema = z
.object({
parseType: z.number(),
parseType: z.nativeEnum(ParseType),
parser_id: z
.string()
.min(1, {
@@ -156,7 +156,7 @@ export function ChunkMethodDialog({
}),
})
.superRefine((data, ctx) => {
if (data.parseType === 2 && !data.pipeline_id) {
if (data.parseType === ParseType.Pipeline && !data.pipeline_id) {
ctx.addIssue({
path: ['pipeline_id'],
message: t('common.pleaseSelect'),
@@ -170,7 +170,7 @@ export function ChunkMethodDialog({
defaultValues: {
parser_id: parserId || '',
pipeline_id: pipelineId || '',
parseType: pipelineId ? 2 : 1,
parseType: pipelineId ? ParseType.Pipeline : ParseType.BuiltIn,
parser_config: defaultParserValues,
},
});
@@ -248,7 +248,7 @@ export function ChunkMethodDialog({
form.reset({
parser_id: parserId || '',
pipeline_id: pipelineId || '',
parseType: pipelineId ? 2 : 1,
parseType: pipelineId ? ParseType.Pipeline : ParseType.BuiltIn,
parser_config: fillDefaultParserValue({
pages: pages.length > 0 ? pages : [{ from: 1, to: 1024 }],
...omit(parserConfig, 'pages'),
@@ -279,10 +279,10 @@ export function ChunkMethodDialog({
const parseType = useWatch({
control: form.control,
name: 'parseType',
defaultValue: pipelineId ? 2 : 1,
defaultValue: pipelineId ? ParseType.Pipeline : ParseType.BuiltIn,
});
useEffect(() => {
if (parseType === 1) {
if (parseType === ParseType.BuiltIn) {
form.setValue('pipeline_id', '');
}
}, [parseType, form]);
@@ -301,49 +301,36 @@ export function ChunkMethodDialog({
>
<div className="space-y-6">
<ParseTypeItem />
{parseType === 1 && <ChunkMethodItem />}
{parseType === ParseType.BuiltIn && <ChunkMethodItem />}
{/* <FormField
control={form.control}
name="parser_id"
render={({ field }) => (
<FormItem>
<FormLabel>{t('knowledgeDetails.chunkMethod')}</FormLabel>
<FormControl>
<RAGFlowSelect
{...field}
options={parserList}
></RAGFlowSelect>
</FormControl>
<FormMessage />
</FormItem>
)}
/> */}
{showPages && parseType === 1 && <DynamicPageRange />}
{showPages && parseType === 1 && layoutRecognize && (
<FormField
control={form.control}
name="parser_config.task_page_size"
render={({ field }) => (
<FormItem>
<FormLabel
tooltip={t('knowledgeDetails.taskPageSizeTip')}
>
{t('knowledgeDetails.taskPageSize')}
</FormLabel>
<FormControl>
<Input {...field} type={'number'} min={1} max={128} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{showPages && parseType === ParseType.BuiltIn && (
<DynamicPageRange />
)}
{showPages &&
parseType === ParseType.BuiltIn &&
layoutRecognize && (
<FormField
control={form.control}
name="parser_config.task_page_size"
render={({ field }) => (
<FormItem>
<FormLabel
tooltip={t('knowledgeDetails.taskPageSizeTip')}
>
{t('knowledgeDetails.taskPageSize')}
</FormLabel>
<FormControl>
<Input {...field} type={'number'} min={1} max={128} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
)}
</div>
{parseType === 1 && (
{parseType === ParseType.BuiltIn && (
<>
<div className="space-y-6 border-t-0.5 border-border-button pt-6 empty:hidden">
{showOne && (
@@ -411,7 +398,7 @@ export function ChunkMethodDialog({
)}
<div className="space-y-6 empty:hidden">
{parseType === 2 && (
{parseType === ParseType.Pipeline && (
<DataFlowSelect
isMult={false}
// toDataPipeline={navigateToAgents}

View File

@@ -86,6 +86,7 @@ export function DataFlowSelect(props: IProps) {
<FormLabel
// tooltip={t('dataFlowTip')}
className="text-sm text-text-primary whitespace-wrap "
required
>
{t('manualSetup')}
</FormLabel>

View File

@@ -95,3 +95,8 @@ export enum DocumentParserType {
}
export const TagRenameId = 'tagRename';
export enum ParseType {
BuiltIn = 1,
Pipeline = 2,
}

View File

@@ -1,5 +1,6 @@
import { useHandleFilterSubmit } from '@/components/list-filter-bar/use-handle-filter-submit';
import message from '@/components/ui/message';
import { ParseType } from '@/constants/knowledge';
import { ResponsePostType } from '@/interfaces/database/base';
import {
IKnowledge,
@@ -208,7 +209,7 @@ export const useCreateKnowledge = () => {
name: string;
embedding_model?: string;
chunk_method?: string;
parseType?: number;
parseType?: ParseType;
pipeline_id?: string | null;
ext?: {
language?: string;

View File

@@ -211,6 +211,7 @@ Example: A 1 KB message with 1024-dim embedding uses ~9 KB. The 5 MB default lim
searchKnowledgePlaceholder: 'Search',
noMoreData: `That's all. Nothing more.`,
parserRequired: 'Chunk method is required',
dataFlowRequired: 'Data flow is required',
},
knowledgeDetails: {
metadata: {

View File

@@ -180,6 +180,7 @@ export default {
searchKnowledgePlaceholder: '搜索',
noMoreData: '没有更多数据了',
parserRequired: '分块方法必填',
dataFlowRequired: '数据流必填',
},
knowledgeDetails: {
metadata: {

View File

@@ -19,7 +19,7 @@ import {
import { Radio } from '@/components/ui/radio';
import { Spin } from '@/components/ui/spin';
import { Switch } from '@/components/ui/switch';
import { LlmModelType } from '@/constants/knowledge';
import { LlmModelType, ParseType } from '@/constants/knowledge';
import { useTranslate } from '@/hooks/common-hooks';
import { useComposeLlmOptionsByModelTypes } from '@/hooks/use-llm-request';
import { cn } from '@/lib/utils';
@@ -248,8 +248,8 @@ export function ParseTypeItem({
line === 1 ? 'w-1/2' : 'w-3/4',
)}
>
<Radio value={1}>{t('builtIn')}</Radio>
<Radio value={2}>{t('manualSetup')}</Radio>
<Radio value={ParseType.BuiltIn}>{t('builtIn')}</Radio>
<Radio value={ParseType.Pipeline}>{t('manualSetup')}</Radio>
</div>
</Radio.Group>
</FormControl>

View File

@@ -1,9 +1,10 @@
import { ParseType } from '@/constants/knowledge';
import { t } from 'i18next';
import { z } from 'zod';
export const formSchema = z
.object({
parse_type: z.number(),
parse_type: z.nativeEnum(ParseType),
name: z.string().min(1, {
message: 'Username must be at least 2 characters.',
}),
@@ -110,7 +111,7 @@ export const formSchema = z
// icon: z.array(z.instanceof(File)),
})
.superRefine((data, ctx) => {
if (data.parseType === 2 && !data.pipeline_id) {
if (data.parse_type === ParseType.Pipeline && !data.pipeline_id) {
ctx.addIssue({
path: ['pipeline_id'],
message: t('common.pleaseSelect'),

View File

@@ -35,7 +35,7 @@ export function useHasParsedDocument(isEdit?: boolean) {
}
export const useFetchKnowledgeConfigurationOnMount = (
form: UseFormReturn<z.infer<typeof formSchema>, any, undefined>,
form: UseFormReturn<z.infer<typeof formSchema>>,
) => {
const { data: knowledgeDetails, loading } =
useFetchKnowledgeBaseConfiguration();

View File

@@ -12,7 +12,7 @@ import {
import Divider from '@/components/ui/divider';
import { Form } from '@/components/ui/form';
import { FormLayout } from '@/constants/form';
import { DocumentParserType } from '@/constants/knowledge';
import { DocumentParserType, ParseType } from '@/constants/knowledge';
import { PermissionRole } from '@/constants/permission';
import { IConnector, IKnowledge } from '@/interfaces/database/knowledge';
import { useDataSourceInfo } from '@/pages/user-setting/data-source/constant';
@@ -111,7 +111,7 @@ export default function DatasetSettings() {
llm_id: '',
},
pipeline_id: '',
parse_type: 1,
parse_type: ParseType.BuiltIn,
pagerank: 0,
connectors: [],
},
@@ -157,7 +157,10 @@ export default function DatasetSettings() {
finish_at: knowledgeDetails.raptor_task_finish_at,
task_id: knowledgeDetails.raptor_task_id,
} as IGenerateLogButtonProps);
form.setValue('parse_type', knowledgeDetails.pipeline_id ? 2 : 1);
form.setValue(
'parse_type',
knowledgeDetails.pipeline_id ? ParseType.Pipeline : ParseType.BuiltIn,
);
form.setValue('pipeline_id', knowledgeDetails.pipeline_id || '');
}
}, [knowledgeDetails, form]);
@@ -216,7 +219,9 @@ export default function DatasetSettings() {
const parseType = useWatch({
control: form.control,
name: 'parse_type',
defaultValue: knowledgeDetails.pipeline_id ? 2 : 1,
defaultValue: knowledgeDetails.pipeline_id
? ParseType.Pipeline
: ParseType.BuiltIn,
});
const selectedTag = useWatch({
name: 'chunk_method',
@@ -224,7 +229,7 @@ export default function DatasetSettings() {
});
useEffect(() => {
if (parseType === 1) {
if (parseType === ParseType.BuiltIn) {
form.setValue('pipeline_id', '');
} else {
form.setValue('chunk_method', DocumentParserType.Naive);
@@ -236,7 +241,6 @@ export default function DatasetSettings() {
const connectors = sourceData?.filter((connector) => {
return connector.id !== data.id;
});
console.log('🚀 ~ DatasetSettings ~ connectors:', connectors);
setSourceData(connectors as IDataSourceNodeProps[]);
form.setValue('connectors', connectors || []);
// form.setValue('pipeline_name', data.name || '');
@@ -304,13 +308,13 @@ export default function DatasetSettings() {
{t('knowledgeConfiguration.dataPipeline')}
</div>
<ParseTypeItem line={1} name="parse_type" />
{parseType === 1 && (
{parseType === ParseType.BuiltIn && (
<ChunkMethodItem
line={1}
name="chunk_method"
></ChunkMethodItem>
)}
{parseType === 2 && (
{parseType === ParseType.Pipeline && (
<DataFlowSelect
isMult={false}
showToDataPipeline={true}
@@ -320,7 +324,7 @@ export default function DatasetSettings() {
)}
{/* <Divider /> */}
{parseType === 1 && <ChunkMethodForm />}
{parseType === ParseType.BuiltIn && <ChunkMethodForm />}
{/* <LinkDataPipeline
data={pipelineData}
@@ -372,7 +376,9 @@ export default function DatasetSettings() {
</DataSetContext.Provider>
<div className="flex-1 p-5 overflow-auto">
{parseType === 1 && <ChunkMethodLearnMore parserId={selectedTag} />}
{parseType === ParseType.BuiltIn && (
<ChunkMethodLearnMore parserId={selectedTag} />
)}
</div>
</CardContent>
</Card>

View File

@@ -1,4 +1,5 @@
import { ButtonLoading } from '@/components/ui/button';
import { ParseType } from '@/constants/knowledge';
import { useUpdateKnowledge } from '@/hooks/use-knowledge-request';
import { useMemo } from 'react';
import { useFormContext } from 'react-hook-form';
@@ -68,7 +69,7 @@ export function SavingButton() {
if (beValid) {
form.handleSubmit(async (originalValues) => {
const values = originalValues;
if (originalValues.parse_type === 1) {
if (originalValues.parse_type === ParseType.BuiltIn) {
values.pipeline_id = null;
} else {
values.chunk_method = null;

View File

@@ -18,6 +18,7 @@ import {
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { FormLayout } from '@/constants/form';
import { ParseType } from '@/constants/knowledge';
import { useFetchTenantInfo } from '@/hooks/use-user-setting-request';
import { IModalProps } from '@/interfaces/common';
import { zodResolver } from '@hookform/resolvers/zod';
@@ -34,6 +35,8 @@ import {
const FormId = 'dataset-creating-form';
const ChunkMethodName = 'chunk_method';
export function InputForm({ onOk }: IModalProps<any>) {
const { t } = useTranslation();
const { data: tenantInfo } = useFetchTenantInfo();
@@ -46,30 +49,30 @@ export function InputForm({ onOk }: IModalProps<any>) {
message: t('knowledgeList.namePlaceholder'),
})
.trim(),
parseType: z.number().optional(),
parseType: z.nativeEnum(ParseType).optional(),
embedding_model: z
.string()
.min(1, {
message: t('knowledgeConfiguration.embeddingModelPlaceholder'),
})
.trim(),
chunk_method: z.string().optional(),
[ChunkMethodName]: z.string().optional(),
pipeline_id: z.string().optional(),
})
.superRefine((data, ctx) => {
// When parseType === 1, chunk_method is required
// When parseType === BuiltIn, chunk_method is required
if (
data.parseType === 1 &&
(!data.chunk_method || data.chunk_method.trim() === '')
data.parseType === ParseType.BuiltIn &&
(!data[ChunkMethodName] || data[ChunkMethodName].trim() === '')
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: t('knowledgeList.parserRequired'),
path: ['parser_id'],
path: [ChunkMethodName],
});
}
// When parseType === 1, pipline_id required
if (data.parseType === 2 && !data.pipeline_id) {
// When parseType === Pipeline, pipeline_id required
if (data.parseType === ParseType.Pipeline && !data.pipeline_id) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: t('knowledgeList.dataFlowRequired'),
@@ -82,8 +85,8 @@ export function InputForm({ onOk }: IModalProps<any>) {
resolver: zodResolver(FormSchema),
defaultValues: {
name: '',
parseType: 1,
chunk_method: '',
parseType: ParseType.BuiltIn,
[ChunkMethodName]: '',
embedding_model: tenantInfo?.embd_id,
},
});
@@ -94,12 +97,13 @@ export function InputForm({ onOk }: IModalProps<any>) {
});
function onSubmit(data: z.infer<typeof FormSchema>) {
const nextData = parseType === 1 ? data : omit(data, 'chunk_method');
const nextData =
parseType === ParseType.BuiltIn ? data : omit(data, ChunkMethodName);
onOk?.(nextData);
}
useEffect(() => {
if (parseType === 1) {
if (parseType === ParseType.BuiltIn) {
form.setValue('pipeline_id', '');
}
}, [parseType, form]);
@@ -107,7 +111,9 @@ export function InputForm({ onOk }: IModalProps<any>) {
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
onSubmit={form.handleSubmit(onSubmit, (errors) => {
console.warn(errors);
})}
className="space-y-6"
id={FormId}
>
@@ -133,10 +139,10 @@ export function InputForm({ onOk }: IModalProps<any>) {
<EmbeddingModelItem line={2} isEdit={false} />
<ParseTypeItem />
{parseType === 1 && (
<ChunkMethodItem name="chunk_method"></ChunkMethodItem>
{parseType === ParseType.BuiltIn && (
<ChunkMethodItem name={ChunkMethodName}></ChunkMethodItem>
)}
{parseType === 2 && (
{parseType === ParseType.Pipeline && (
<DataFlowSelect
isMult={false}
showToDataPipeline={true}

View File

@@ -1,123 +0,0 @@
import { ButtonLoading } from '@/components/ui/button';
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { IModalProps } from '@/interfaces/common';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm, useWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';
import {
DataExtractKnowledgeItem,
DataFlowItem,
EmbeddingModelItem,
ParseTypeItem,
TeamItem,
} from '../dataset/dataset-setting/configuration/common-item';
const FormId = 'dataset-creating-form';
export function InputForm({ onOk }: IModalProps<any>) {
const { t } = useTranslation();
const FormSchema = z.object({
name: z
.string()
.min(1, {
message: t('knowledgeList.namePlaceholder'),
})
.trim(),
parseType: z.number().optional(),
});
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
defaultValues: {
name: '',
parseType: 1,
},
});
function onSubmit(data: z.infer<typeof FormSchema>) {
onOk?.(data.name);
}
const parseType = useWatch({
control: form.control,
name: 'parseType',
});
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-6"
id={FormId}
>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>
<span className="text-destructive mr-1"> *</span>
{t('knowledgeList.name')}
</FormLabel>
<FormControl>
<Input
placeholder={t('knowledgeList.namePlaceholder')}
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<EmbeddingModelItem line={2} />
<ParseTypeItem />
{parseType === 2 && (
<>
<DataFlowItem />
<DataExtractKnowledgeItem />
<TeamItem />
</>
)}
</form>
</Form>
);
}
export function DatasetCreatingDialog({
hideModal,
onOk,
loading,
}: IModalProps<any>) {
const { t } = useTranslation();
return (
<Dialog open onOpenChange={hideModal}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>{t('knowledgeList.createKnowledgeBase')}</DialogTitle>
</DialogHeader>
<InputForm onOk={onOk}></InputForm>
<DialogFooter>
<ButtonLoading type="submit" form={FormId} loading={loading}>
{t('common.save')}
</ButtonLoading>
</DialogFooter>
</DialogContent>
</Dialog>
);
}

View File

@@ -1,3 +1,4 @@
import { ParseType } from '@/constants/knowledge';
import { useSetModalState } from '@/hooks/common-hooks';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { useCreateKnowledge } from '@/hooks/use-knowledge-request';
@@ -18,7 +19,7 @@ export interface Iknowledge {
name: string;
embedding_model?: string;
chunk_method?: string;
parseType?: number;
parseType?: ParseType;
pipeline_id?: string | null;
ext?: {
language?: string;