From 924a1692248973498581e6207462e8b5b5e6bcd1 Mon Sep 17 00:00:00 2001 From: Ivan <8611739+IRBorisov@users.noreply.github.com> Date: Tue, 4 Nov 2025 01:48:14 +0300 Subject: [PATCH] F: Improve dialogs validation info --- .../src/components/modal/modal-form.tsx | 29 +++++++++++-------- .../ai/dialogs/dlg-create-prompt-template.tsx | 2 +- .../library/dialogs/dlg-change-location.tsx | 6 +++- .../library/dialogs/dlg-create-version.tsx | 14 +++++++-- .../dlg-edit-versions/dlg-edit-versions.tsx | 4 +-- .../dlg-create-block/dlg-create-block.tsx | 14 ++++++++- .../dlg-create-block/tab-block-card.tsx | 1 + .../oss/dialogs/dlg-create-schema.tsx | 16 +++++++++- .../dlg-create-synthesis.tsx | 15 ++++++++-- .../dlg-create-synthesis/tab-arguments.tsx | 2 ++ .../tab-substitutions.tsx | 7 ++++- .../features/oss/dialogs/dlg-edit-block.tsx | 1 + .../dlg-edit-operation/dlg-edit-operation.tsx | 2 ++ .../dlg-edit-operation/tab-operation.tsx | 2 ++ .../dlg-edit-operation/tab-substitutions.tsx | 7 ++++- .../oss/dialogs/dlg-import-schema.tsx | 14 ++++++++- .../oss/dialogs/dlg-relocate-constituents.tsx | 3 +- .../dialogs/dlg-create-cst/dlg-create-cst.tsx | 14 +++++++-- .../dlg-cst-template/dlg-cst-template.tsx | 14 ++++++++- .../dialogs/dlg-edit-cst/dlg-edit-cst.tsx | 4 +-- .../dlg-edit-reference/dlg-edit-reference.tsx | 2 ++ .../dlg-inline-synthesis.tsx | 2 ++ .../rsform/dialogs/dlg-rename-cst.tsx | 3 +- .../rsform/dialogs/dlg-substitute-cst.tsx | 5 ++-- .../rsform/dialogs/dlg-upload-rsform.tsx | 2 ++ rsconcept/frontend/src/utils/labels.ts | 22 ++++++++++++-- 26 files changed, 169 insertions(+), 38 deletions(-) diff --git a/rsconcept/frontend/src/components/modal/modal-form.tsx b/rsconcept/frontend/src/components/modal/modal-form.tsx index eced50e2..8a8a15d0 100644 --- a/rsconcept/frontend/src/components/modal/modal-form.tsx +++ b/rsconcept/frontend/src/components/modal/modal-form.tsx @@ -5,10 +5,11 @@ import { BadgeHelp } from '@/features/help/components/badge-help'; import { useEscapeKey } from '@/hooks/use-escape-key'; import { useDialogsStore } from '@/stores/dialogs'; +import { globalIDs } from '@/utils/constants'; import { prepareTooltip } from '@/utils/utils'; import { Button, MiniButton, SubmitButton } from '../control'; -import { IconClose } from '../icons'; +import { IconAlert, IconClose } from '../icons'; import { type Styling } from '../props'; import { cn } from '../utils'; @@ -33,7 +34,7 @@ interface ModalFormProps extends ModalProps { submitText?: string; /** Tooltip for the submit button when the form is invalid. */ - submitInvalidTooltip?: string; + validationHint?: string; /** Indicates that submit button is enabled. */ canSubmit?: boolean; @@ -60,7 +61,7 @@ export function ModalForm({ canSubmit = true, submitText = 'Продолжить', - submitInvalidTooltip, + validationHint, beforeSubmit, onSubmit, onCancel, @@ -121,7 +122,7 @@ export function ModalForm({
-
- +
+ {validationHint ? ( +
+ +
+ ) : null} +
diff --git a/rsconcept/frontend/src/features/ai/dialogs/dlg-create-prompt-template.tsx b/rsconcept/frontend/src/features/ai/dialogs/dlg-create-prompt-template.tsx index 99ddf642..fc178634 100644 --- a/rsconcept/frontend/src/features/ai/dialogs/dlg-create-prompt-template.tsx +++ b/rsconcept/frontend/src/features/ai/dialogs/dlg-create-prompt-template.tsx @@ -53,7 +53,7 @@ export function DlgCreatePromptTemplate() { submitText='Создать' canSubmit={canSubmit} onSubmit={event => void handleSubmit(onSubmit)(event)} - submitInvalidTooltip='Введите уникальное название шаблона' + validationHint={canSubmit ? '' : 'Введите уникальное название шаблона'} className='cc-column w-140 max-h-120 py-2 px-6' helpTopic={HelpTopic.ASSISTANT} > diff --git a/rsconcept/frontend/src/features/library/dialogs/dlg-change-location.tsx b/rsconcept/frontend/src/features/library/dialogs/dlg-change-location.tsx index 0518ac3d..c3b2667c 100644 --- a/rsconcept/frontend/src/features/library/dialogs/dlg-change-location.tsx +++ b/rsconcept/frontend/src/features/library/dialogs/dlg-change-location.tsx @@ -47,7 +47,11 @@ export function DlgChangeLocation() { overflowVisible header='Изменение расположения' submitText='Переместить' - submitInvalidTooltip={`Допустимы буквы, цифры, подчерк, пробел и "!". Сегмент пути не может начинаться и заканчиваться пробелом. Общая длина (с корнем) не должна превышать ${limits.len_location}`} + validationHint={ + isValid + ? '' + : `Допустимы буквы, цифры, подчерк, пробел и "!". Сегмент пути не может начинаться и заканчиваться пробелом. Общая длина (с корнем) не должна превышать ${limits.len_location}` + } canSubmit={isValid && isDirty} onSubmit={event => void handleSubmit(onSubmit)(event)} className='w-130 pb-3 px-6 h-36' diff --git a/rsconcept/frontend/src/features/library/dialogs/dlg-create-version.tsx b/rsconcept/frontend/src/features/library/dialogs/dlg-create-version.tsx index 840e1741..5ddb2a57 100644 --- a/rsconcept/frontend/src/features/library/dialogs/dlg-create-version.tsx +++ b/rsconcept/frontend/src/features/library/dialogs/dlg-create-version.tsx @@ -6,7 +6,7 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { Checkbox, TextArea, TextInput } from '@/components/input'; import { ModalForm } from '@/components/modal'; import { useDialogsStore } from '@/stores/dialogs'; -import { errorMsg } from '@/utils/labels'; +import { hintMsg } from '@/utils/labels'; import { type ICreateVersionDTO, type IVersionInfo, schemaCreateVersion } from '../backend/types'; import { useCreateVersion } from '../backend/use-create-version'; @@ -41,7 +41,15 @@ export function DlgCreateVersion() { mode: 'onChange' }); const version = useWatch({ control, name: 'version' }); - const canSubmit = !!version && !versions.find(ver => ver.version === version); + const { canSubmit, hint } = (() => { + if (!version) { + return { canSubmit: false, hint: hintMsg.versionEmpty }; + } else if (versions.find(ver => ver.version === version)) { + return { canSubmit: false, hint: hintMsg.versionTaken }; + } else { + return { canSubmit: true, hint: '' }; + } + })(); function onSubmit(data: ICreateVersionDTO) { return versionCreate({ itemID, data }).then(onCreate); @@ -52,7 +60,7 @@ export function DlgCreateVersion() { header='Создание версии' className='cc-column w-120 py-2 px-6' canSubmit={canSubmit} - submitInvalidTooltip={errorMsg.versionTaken} + validationHint={hint} submitText='Создать' onSubmit={event => void handleSubmit(onSubmit)(event)} > diff --git a/rsconcept/frontend/src/features/library/dialogs/dlg-edit-versions/dlg-edit-versions.tsx b/rsconcept/frontend/src/features/library/dialogs/dlg-edit-versions/dlg-edit-versions.tsx index ca3222f2..d0a39406 100644 --- a/rsconcept/frontend/src/features/library/dialogs/dlg-edit-versions/dlg-edit-versions.tsx +++ b/rsconcept/frontend/src/features/library/dialogs/dlg-edit-versions/dlg-edit-versions.tsx @@ -12,7 +12,7 @@ import { IconReset, IconSave } from '@/components/icons'; import { TextArea, TextInput } from '@/components/input'; import { ModalView } from '@/components/modal'; import { useDialogsStore } from '@/stores/dialogs'; -import { errorMsg } from '@/utils/labels'; +import { hintMsg } from '@/utils/labels'; import { type IUpdateVersionDTO, schemaUpdateVersion } from '../../backend/types'; import { useDeleteVersion } from '../../backend/use-delete-version'; @@ -106,7 +106,7 @@ export function DlgEditVersions() {
} disabled={!isDirty || !isValid || isProcessing} diff --git a/rsconcept/frontend/src/features/oss/dialogs/dlg-create-block/dlg-create-block.tsx b/rsconcept/frontend/src/features/oss/dialogs/dlg-create-block/dlg-create-block.tsx index 4ba581ed..f9f21f12 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/dlg-create-block/dlg-create-block.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/dlg-create-block/dlg-create-block.tsx @@ -9,6 +9,7 @@ import { HelpTopic } from '@/features/help'; import { ModalForm } from '@/components/modal'; import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs'; import { useDialogsStore } from '@/stores/dialogs'; +import { hintMsg } from '@/utils/labels'; import { type ICreateBlockDTO, type IOssLayout, schemaCreateBlock } from '../../backend/types'; import { useCreateBlock } from '../../backend/use-create-block'; @@ -77,7 +78,17 @@ export function DlgCreateBlock() { const children_blocks = useWatch({ control: methods.control, name: 'children_blocks' }); const children_operations = useWatch({ control: methods.control, name: 'children_operations' }); const [activeTab, setActiveTab] = useState(TabID.CARD); - const canSubmit = methods.formState.isValid && !!title && !manager.oss.blocks.some(block => block.title === title); + const { canSubmit, hint } = (() => { + if (!methods.formState.isValid) { + return { canSubmit: false, hint: hintMsg.formInvalid }; + } else if (!title) { + return { canSubmit: false, hint: hintMsg.titleEmpty }; + } else if (manager.oss.blocks.some(block => block.title === title)) { + return { canSubmit: false, hint: hintMsg.blockTitleTaken }; + } else { + return { canSubmit: true, hint: '' }; + } + })(); function onSubmit(data: ICreateBlockDTO) { data.position = manager.newBlockPosition(data); @@ -90,6 +101,7 @@ export function DlgCreateBlock() { header='Создание блока' submitText='Создать' canSubmit={canSubmit} + validationHint={hint} onSubmit={event => void methods.handleSubmit(onSubmit)(event)} className='w-160 px-6 h-110' helpTopic={HelpTopic.CC_STRUCTURING} diff --git a/rsconcept/frontend/src/features/oss/dialogs/dlg-create-block/tab-block-card.tsx b/rsconcept/frontend/src/features/oss/dialogs/dlg-create-block/tab-block-card.tsx index e7e86490..c90b6a39 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/dlg-create-block/tab-block-card.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/dlg-create-block/tab-block-card.tsx @@ -28,6 +28,7 @@ export function TabBlockCard({ oss }: TabBlockCardProps) { diff --git a/rsconcept/frontend/src/features/oss/dialogs/dlg-create-schema.tsx b/rsconcept/frontend/src/features/oss/dialogs/dlg-create-schema.tsx index 582ec16c..628d9269 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/dlg-create-schema.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/dlg-create-schema.tsx @@ -8,6 +8,7 @@ import { HelpTopic } from '@/features/help'; import { TextArea, TextInput } from '@/components/input'; import { ModalForm } from '@/components/modal'; import { useDialogsStore } from '@/stores/dialogs'; +import { hintMsg } from '@/utils/labels'; import { type ICreateSchemaDTO, type IOssLayout, schemaCreateSchema } from '../backend/types'; import { useCreateSchema } from '../backend/use-create-schema'; @@ -64,7 +65,17 @@ export function DlgCreateSchema() { mode: 'onChange' }); const alias = useWatch({ control: control, name: 'item_data.alias' }); - const canSubmit = isValid && !!alias && !manager.oss.operations.some(operation => operation.alias === alias); + const { canSubmit, hint } = (() => { + if (!isValid) { + return { canSubmit: false, hint: hintMsg.formInvalid }; + } else if (!alias) { + return { canSubmit: false, hint: hintMsg.aliasEmpty }; + } else if (manager.oss.operations.some(operation => operation.alias === alias)) { + return { canSubmit: false, hint: hintMsg.schemaAliasTaken }; + } else { + return { canSubmit: true, hint: '' }; + } + })(); function onSubmit(data: ICreateSchemaDTO) { data.position = manager.newOperationPosition(data); @@ -77,6 +88,7 @@ export function DlgCreateSchema() { header='Создание операции: Новая схема' submitText='Создать' canSubmit={canSubmit} + validationHint={hint} onSubmit={event => void handleSubmit(onSubmit)(event)} className='w-180 px-6 pb-3 cc-column' helpTopic={HelpTopic.CC_OSS} @@ -84,6 +96,7 @@ export function DlgCreateSchema() { @@ -93,6 +106,7 @@ export function DlgCreateSchema() { id='operation_alias' // label='Сокращение' className='w-80' + placeholder='Введите сокращение' {...register('item_data.alias')} error={errors.item_data?.alias} /> diff --git a/rsconcept/frontend/src/features/oss/dialogs/dlg-create-synthesis/dlg-create-synthesis.tsx b/rsconcept/frontend/src/features/oss/dialogs/dlg-create-synthesis/dlg-create-synthesis.tsx index 34f0664f..00fcdc4b 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/dlg-create-synthesis/dlg-create-synthesis.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/dlg-create-synthesis/dlg-create-synthesis.tsx @@ -10,6 +10,7 @@ import { Loader } from '@/components/loader'; import { ModalForm } from '@/components/modal'; import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs'; import { useDialogsStore } from '@/stores/dialogs'; +import { hintMsg } from '@/utils/labels'; import { type ICreateSynthesisDTO, type IOssLayout, schemaCreateSynthesis } from '../../backend/types'; import { useCreateSynthesis } from '../../backend/use-create-synthesis'; @@ -73,8 +74,17 @@ export function DlgCreateSynthesis() { }); const alias = useWatch({ control: methods.control, name: 'item_data.alias' }); const [activeTab, setActiveTab] = useState(TabID.ARGUMENTS); - const canSubmit = - methods.formState.isValid && !!alias && !manager.oss.operations.some(operation => operation.alias === alias); + const { canSubmit, hint } = (() => { + if (!methods.formState.isValid) { + return { canSubmit: false, hint: hintMsg.formInvalid }; + } else if (!alias) { + return { canSubmit: false, hint: hintMsg.aliasEmpty }; + } else if (manager.oss.operations.some(operation => operation.alias === alias)) { + return { canSubmit: false, hint: hintMsg.schemaAliasTaken }; + } else { + return { canSubmit: true, hint: '' }; + } + })(); function onSubmit(data: ICreateSynthesisDTO) { data.position = manager.newOperationPosition(data); @@ -87,6 +97,7 @@ export function DlgCreateSynthesis() { header='Создание операции синтеза' submitText='Создать' canSubmit={canSubmit} + validationHint={hint} onSubmit={event => void methods.handleSubmit(onSubmit)(event)} className='w-180 px-6 h-128' helpTopic={HelpTopic.CC_OSS} diff --git a/rsconcept/frontend/src/features/oss/dialogs/dlg-create-synthesis/tab-arguments.tsx b/rsconcept/frontend/src/features/oss/dialogs/dlg-create-synthesis/tab-arguments.tsx index 0db304d4..7991df1b 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/dlg-create-synthesis/tab-arguments.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/dlg-create-synthesis/tab-arguments.tsx @@ -32,6 +32,7 @@ export function TabArguments({ oss }: TabArgumentsProps) { @@ -40,6 +41,7 @@ export function TabArguments({ oss }: TabArgumentsProps) { -