From b099c88c3f25ef8fcd7e104fe1e741c9b4dd37bc Mon Sep 17 00:00:00 2001 From: balibabu Date: Fri, 7 Aug 2026 11:29:05 +0800 Subject: [PATCH] Fix: Deduplication of wiki entity types (#17965) --- .../originui/select-with-search.tsx | 8 ++- web/src/locales/en.ts | 1 + web/src/locales/zh.ts | 1 + .../components/add-field-modal.tsx | 62 ++++++++++++++++++- .../components/template-configuration.tsx | 3 +- .../components/template-preview-header.tsx | 7 --- .../create-next/constant.ts | 5 ++ .../create-next/hooks/use-add-field-form.ts | 21 ++++++- .../hooks/use-template-section-data.ts | 8 ++- .../create-next/utils.ts | 17 +++++ .../edit-next/components/add-field-modal.tsx | 59 +++++++++++++++++- .../components/template-configuration.tsx | 3 +- .../components/template-preview-header.tsx | 7 --- .../edit-next/constant.ts | 5 ++ .../edit-next/hooks/use-add-field-form.ts | 26 ++++++-- .../hooks/use-template-section-data.ts | 8 ++- .../compilation-templates/edit-next/utils.ts | 17 +++++ 17 files changed, 223 insertions(+), 35 deletions(-) diff --git a/web/src/components/originui/select-with-search.tsx b/web/src/components/originui/select-with-search.tsx index dc71deeae1..7db60e536a 100644 --- a/web/src/components/originui/select-with-search.tsx +++ b/web/src/components/originui/select-with-search.tsx @@ -55,7 +55,8 @@ export type SelectWithSearchFlagProps = { placeholder?: string; emptyData?: string; allowCustomValue?: boolean; - onNoMatchEnter?(searchValue: string): void; + // Return false to veto selecting the custom value on Enter + onNoMatchEnter?(searchValue: string): boolean | void; disableAutoSelectOnEnter?: boolean; testId?: string; optionTestIdPrefix?: string; @@ -221,7 +222,10 @@ export const SelectWithSearch = forwardRef< setSearchValue(''); setOpen(false); } else if (!hasMatchingOptions(options, keywords)) { - onNoMatchEnter?.(keywords); + if (onNoMatchEnter?.(keywords) === false) { + // Vetoed: prevent cmdk from selecting the custom value item + e.preventDefault(); + } } } }, diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index dc02289284..c9e909f729 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -1945,6 +1945,7 @@ Example: Virtual Hosted Style`, addFieldModalTitle: 'Add field', editFieldModalTitle: 'Edit field', selectFieldType: 'Select field type', + fieldTypeExists: 'This field type already exists', blueprintsPlaceholder: 'Blueprints placeholder', blueprintsPlaceholderDescription: "Select or customize a specific structure from the Blueprint library on the left to define your Wiki's content framework and visual presentation.", diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index ae7a36cf5c..2a8ea1b3d9 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -1632,6 +1632,7 @@ NER:使用 spaCy NER 和基于规则的关键词提取来抽取实体和关系 addFieldModalTitle: '添加字段', editFieldModalTitle: '编辑字段', selectFieldType: '选择字段类型', + fieldTypeExists: '该字段类型已存在', blueprintsPlaceholder: '蓝图占位', blueprintsPlaceholderDescription: '从左侧的 Blueprint 库中选择或自定义特定结构,以定义您的 Wiki 内容框架和视觉呈现。', diff --git a/web/src/pages/user-setting/compilation-templates/create-next/components/add-field-modal.tsx b/web/src/pages/user-setting/compilation-templates/create-next/components/add-field-modal.tsx index 79b6158924..eebb679b32 100644 --- a/web/src/pages/user-setting/compilation-templates/create-next/components/add-field-modal.tsx +++ b/web/src/pages/user-setting/compilation-templates/create-next/components/add-field-modal.tsx @@ -2,6 +2,7 @@ import { SelectWithSearch } from '@/components/originui/select-with-search'; import { RAGFlowFormItem } from '@/components/ragflow-form'; import { Button } from '@/components/ui/button'; import { Form } from '@/components/ui/form'; +import message from '@/components/ui/message'; import { Modal } from '@/components/ui/modal/modal'; import { Textarea } from '@/components/ui/textarea'; import { ICompilationTemplateSection } from '@/interfaces/database/compilation-template'; @@ -9,7 +10,10 @@ import { startCase } from 'lodash'; import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import { FieldLabelKeyMap } from '@/pages/user-setting/compilation-templates/create-next/constant'; +import { + FieldLabelKeyMap, + FieldRequiredMessageKeyMap, +} from '@/pages/user-setting/compilation-templates/create-next/constant'; import { useAddFieldForm } from '../hooks/use-add-field-form'; @@ -18,6 +22,7 @@ type AddFieldModalProps = { onOpenChange: (open: boolean) => void; sectionName: string; builtinSection?: ICompilationTemplateSection; + existingFields?: Record[]; initialField?: Record; onAdd: (field: Record) => void; }; @@ -27,6 +32,7 @@ export function AddFieldModal({ onOpenChange, sectionName, builtinSection, + existingFields, initialField, onAdd, }: AddFieldModalProps) { @@ -35,12 +41,14 @@ export function AddFieldModal({ form, fieldKeys, hasTypeField, + requiredKeys, typeOptions, handleTypeChange, handleSubmit, } = useAddFieldForm({ open, builtinSection, + existingFields, initialField, }); @@ -65,6 +73,34 @@ export function AddFieldModal({ [t], ); + const getRequiredMessage = useCallback( + (key: string) => { + return FieldRequiredMessageKeyMap[key] + ? t(FieldRequiredMessageKeyMap[key]) + : t('common.pleaseInput'); + }, + [t], + ); + + const isDuplicateType = useCallback( + (typeValue: string) => { + if (!typeValue || typeValue === initialField?.type) return false; + return (existingFields ?? []).some((field) => field.type === typeValue); + }, + [existingFields, initialField], + ); + + const handleNoMatchEnter = useCallback( + (searchValue: string) => { + if (isDuplicateType(searchValue)) { + message.warning(t('setting.fieldTypeExists')); + return false; + } + return true; + }, + [isDuplicateType, t], + ); + return (
{hasTypeField && ( - + + !isDuplicateType(value) || t('setting.fieldTypeExists'), + }} + > {(field) => ( @@ -103,7 +149,17 @@ export function AddFieldModal({ )} {nonTypeKeys.map((key) => ( - +