-
+
+ {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) {
-
+
);
}
diff --git a/rsconcept/frontend/src/features/oss/dialogs/dlg-edit-block.tsx b/rsconcept/frontend/src/features/oss/dialogs/dlg-edit-block.tsx
index d57d13d2..97c28ba2 100644
--- a/rsconcept/frontend/src/features/oss/dialogs/dlg-edit-block.tsx
+++ b/rsconcept/frontend/src/features/oss/dialogs/dlg-edit-block.tsx
@@ -67,6 +67,7 @@ export function DlgEditBlock() {
diff --git a/rsconcept/frontend/src/features/oss/dialogs/dlg-edit-operation/dlg-edit-operation.tsx b/rsconcept/frontend/src/features/oss/dialogs/dlg-edit-operation/dlg-edit-operation.tsx
index 5bf84777..5d606210 100644
--- a/rsconcept/frontend/src/features/oss/dialogs/dlg-edit-operation/dlg-edit-operation.tsx
+++ b/rsconcept/frontend/src/features/oss/dialogs/dlg-edit-operation/dlg-edit-operation.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 IOssLayout, type IUpdateOperationDTO, OperationType, schemaUpdateOperation } from '../../backend/types';
import { useOssSuspense } from '../../backend/use-oss';
@@ -79,6 +80,7 @@ export function DlgEditOperation() {
header='Редактирование операции'
submitText='Сохранить'
canSubmit={canSubmit}
+ validationHint={hintMsg.formInvalid}
onSubmit={event => void methods.handleSubmit(onSubmit)(event)}
className='w-160 px-6 h-128'
helpTopic={HelpTopic.UI_SUBSTITUTIONS}
diff --git a/rsconcept/frontend/src/features/oss/dialogs/dlg-edit-operation/tab-operation.tsx b/rsconcept/frontend/src/features/oss/dialogs/dlg-edit-operation/tab-operation.tsx
index 5c5d5657..194de6a7 100644
--- a/rsconcept/frontend/src/features/oss/dialogs/dlg-edit-operation/tab-operation.tsx
+++ b/rsconcept/frontend/src/features/oss/dialogs/dlg-edit-operation/tab-operation.tsx
@@ -22,6 +22,7 @@ export function TabOperation({ oss }: TabOperationProps) {
@@ -29,6 +30,7 @@ export function TabOperation({ oss }: TabOperationProps) {
-
+
);
}
diff --git a/rsconcept/frontend/src/features/oss/dialogs/dlg-import-schema.tsx b/rsconcept/frontend/src/features/oss/dialogs/dlg-import-schema.tsx
index 984c1afb..096c9272 100644
--- a/rsconcept/frontend/src/features/oss/dialogs/dlg-import-schema.tsx
+++ b/rsconcept/frontend/src/features/oss/dialogs/dlg-import-schema.tsx
@@ -11,6 +11,7 @@ import { PickSchema } from '@/features/library/components/pick-schema';
import { Checkbox, TextArea, TextInput } from '@/components/input';
import { ModalForm } from '@/components/modal';
import { useDialogsStore } from '@/stores/dialogs';
+import { hintMsg } from '@/utils/labels';
import { type IImportSchemaDTO, type IOssLayout, schemaImportSchema } from '../backend/types';
import { useImportSchema } from '../backend/use-import-schema';
@@ -73,7 +74,17 @@ export function DlgImportSchema() {
});
const alias = useWatch({ control: control, name: 'item_data.alias' });
const clone_source = useWatch({ control: control, name: 'clone_source' });
- 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: IImportSchemaDTO) {
data.position = manager.newOperationPosition(data);
@@ -101,6 +112,7 @@ export function DlgImportSchema() {
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}
diff --git a/rsconcept/frontend/src/features/oss/dialogs/dlg-relocate-constituents.tsx b/rsconcept/frontend/src/features/oss/dialogs/dlg-relocate-constituents.tsx
index b61645c7..7a736dd0 100644
--- a/rsconcept/frontend/src/features/oss/dialogs/dlg-relocate-constituents.tsx
+++ b/rsconcept/frontend/src/features/oss/dialogs/dlg-relocate-constituents.tsx
@@ -15,6 +15,7 @@ import { MiniButton } from '@/components/control';
import { Loader } from '@/components/loader';
import { ModalForm } from '@/components/modal';
import { useDialogsStore } from '@/stores/dialogs';
+import { hintMsg } from '@/utils/labels';
import { type IOssLayout, type IRelocateConstituentsDTO, schemaRelocateConstituents } from '../backend/types';
import { useOssSuspense } from '../backend/use-oss';
@@ -120,7 +121,7 @@ export function DlgRelocateConstituents() {
header='Перенос конституент'
submitText='Переместить'
canSubmit={canSubmit}
- submitInvalidTooltip='Необходимо выбрать хотя бы одну собственную конституенту'
+ validationHint={canSubmit ? '' : hintMsg.relocateEmpty}
onSubmit={event => void handleSubmit(onSubmit)(event)}
className='w-160 h-132 py-3 px-6'
helpTopic={HelpTopic.UI_RELOCATE_CST}
diff --git a/rsconcept/frontend/src/features/rsform/dialogs/dlg-create-cst/dlg-create-cst.tsx b/rsconcept/frontend/src/features/rsform/dialogs/dlg-create-cst/dlg-create-cst.tsx
index c79bea81..9aaf48ee 100644
--- a/rsconcept/frontend/src/features/rsform/dialogs/dlg-create-cst/dlg-create-cst.tsx
+++ b/rsconcept/frontend/src/features/rsform/dialogs/dlg-create-cst/dlg-create-cst.tsx
@@ -5,7 +5,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
import { ModalForm } from '@/components/modal';
import { useDialogsStore } from '@/stores/dialogs';
-import { errorMsg } from '@/utils/labels';
+import { hintMsg } from '@/utils/labels';
import { type RO } from '@/utils/meta';
import {
@@ -37,7 +37,15 @@ export function DlgCreateCst() {
});
const alias = useWatch({ control: methods.control, name: 'alias' });
const cst_type = useWatch({ control: methods.control, name: 'cst_type' });
- const canSubmit = methods.formState.isValid && validateNewAlias(alias, cst_type, schema);
+ const { canSubmit, hint } = (() => {
+ if (!methods.formState.isValid) {
+ return { canSubmit: false, hint: hintMsg.formInvalid };
+ } else if (!validateNewAlias(alias, cst_type, schema)) {
+ return { canSubmit: false, hint: hintMsg.aliasInvalid };
+ } else {
+ return { canSubmit: true, hint: '' };
+ }
+ })();
function onSubmit(data: ICreateConstituentaDTO) {
return cstCreate({ itemID: schema.id, data }).then(onCreate);
@@ -48,7 +56,7 @@ export function DlgCreateCst() {
header='Создание конституенты'
canSubmit={canSubmit}
onSubmit={event => void methods.handleSubmit(onSubmit)(event)}
- submitInvalidTooltip={errorMsg.aliasInvalid}
+ validationHint={hint}
submitText='Создать'
className='cc-column w-140 max-h-120 py-2 px-6'
>
diff --git a/rsconcept/frontend/src/features/rsform/dialogs/dlg-cst-template/dlg-cst-template.tsx b/rsconcept/frontend/src/features/rsform/dialogs/dlg-cst-template/dlg-cst-template.tsx
index b14d4186..de04076c 100644
--- a/rsconcept/frontend/src/features/rsform/dialogs/dlg-cst-template/dlg-cst-template.tsx
+++ b/rsconcept/frontend/src/features/rsform/dialogs/dlg-cst-template/dlg-cst-template.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 RO } from '@/utils/meta';
import {
@@ -61,7 +62,17 @@ export function DlgCstTemplate() {
});
const alias = useWatch({ control: methods.control, name: 'alias' });
const cst_type = useWatch({ control: methods.control, name: 'cst_type' });
- const canSubmit = methods.formState.isValid && validateNewAlias(alias, cst_type, schema);
+ const { canSubmit, hint } = (() => {
+ if (!cst_type) {
+ return { canSubmit: false, hint: hintMsg.templateInvalid };
+ } else if (!methods.formState.isValid) {
+ return { canSubmit: false, hint: hintMsg.formInvalid };
+ } else if (!validateNewAlias(alias, cst_type, schema)) {
+ return { canSubmit: false, hint: hintMsg.aliasInvalid };
+ } else {
+ return { canSubmit: true, hint: '' };
+ }
+ })();
const [activeTab, setActiveTab] = useState