From 7a68ee30e0010de28a175d7344f62e805b43a709 Mon Sep 17 00:00:00 2001 From: Aniket Katkar Date: Thu, 27 Jun 2024 15:47:51 +0530 Subject: [PATCH] Fix #16471: Form validation message and alert bug fixes and improvements (#16761) * Fix the styling issue for the teams and user selection component in the alert form * Fix the incorrect field names in form error messages * Fix and modify cypress tests * Fix the incorrect util function import * update the field name in form validation message * Update proper assertions --- .../ui/cypress/common/DomainUtils.ts | 9 +- .../ui/cypress/common/GlossaryUtils.ts | 9 +- .../resources/ui/cypress/common/Utils/Form.ts | 50 ++++++++ .../ui/cypress/common/Utils/Teams.ts | 8 +- .../ui/cypress/constants/constants.ts | 7 +- .../cypress/e2e/Features/CustomMetric.spec.ts | 7 +- .../e2e/Flow/AddRoleAndAssignToUser.spec.ts | 7 +- .../e2e/Flow/NotificationAlerts.spec.ts | 7 +- .../e2e/Flow/ObservabilityAlerts.spec.ts | 7 +- .../ui/cypress/e2e/Flow/PersonaFlow.spec.ts | 14 ++- .../ui/cypress/e2e/Pages/Policies.spec.ts | 14 ++- .../Extensions/image/ImageComponent.tsx | 12 +- .../CustomMetricForm.component.tsx | 29 +---- .../TestCaseStatusModal.component.tsx | 14 +-- .../AddTestSuiteForm/AddTestSuiteForm.tsx | 19 +-- .../AddDomainForm/AddDomainForm.component.tsx | 21 +--- .../AddGlossary/AddGlossary.component.tsx | 17 +-- .../AddGlossaryTermForm.component.tsx | 21 +--- .../ChangeParentHierarchy.component.tsx | 9 +- .../AddEditPersona.component.tsx | 9 +- .../Bot/BotDetails/AuthMechanismForm.tsx | 112 +++++++++--------- .../common/CronEditor/CronEditor.tsx | 3 + .../ui/src/constants/Form.constants.ts | 38 ++++++ .../AddNotificationPage.tsx | 13 +- .../AddObservabilityPage.tsx | 13 +- .../team-and-user-select-item.less | 4 +- .../AddPolicyPage/AddPolicyPage.tsx | 19 +-- .../pages/PoliciesPage/RuleForm/RuleForm.tsx | 19 +-- .../RolesPage/AddRolePage/AddRolePage.tsx | 19 +-- .../UpdateDescriptionPage.tsx | 24 +--- .../ui/src/pages/TeamsPage/AddTeamForm.tsx | 14 +-- .../main/resources/ui/src/utils/formUtils.tsx | 8 +- 32 files changed, 279 insertions(+), 297 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Form.ts create mode 100644 openmetadata-ui/src/main/resources/ui/src/constants/Form.constants.ts diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/DomainUtils.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/DomainUtils.ts index 7c060206055..d1f2026698d 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/DomainUtils.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/DomainUtils.ts @@ -13,7 +13,7 @@ import { DELETE_TERM, INVALID_NAMES, - NAME_MAX_LENGTH_VALIDATION_ERROR, + NAME_MIN_MAX_LENGTH_VALIDATION_ERROR_1_128, NAME_VALIDATION_ERROR, SEARCH_ENTITY_TABLE, } from '../constants/constants'; @@ -47,9 +47,10 @@ export const validateDomainForm = () => { .scrollIntoView() .should('be.visible') .type(INVALID_NAMES.MAX_LENGTH); - cy.get('#name_help') - .should('be.visible') - .contains(NAME_MAX_LENGTH_VALIDATION_ERROR); + cy.get('#name_help').should( + 'contain', + NAME_MIN_MAX_LENGTH_VALIDATION_ERROR_1_128 + ); // with special char validation cy.get('[data-testid="name"]') diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/GlossaryUtils.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/GlossaryUtils.ts index c64e077f181..725221426fd 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/GlossaryUtils.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/GlossaryUtils.ts @@ -14,7 +14,7 @@ import { DELETE_TERM, INVALID_NAMES, - NAME_MAX_LENGTH_VALIDATION_ERROR, + NAME_MIN_MAX_LENGTH_VALIDATION_ERROR_1_128, NAME_VALIDATION_ERROR, } from '../constants/constants'; import { SidebarItem } from '../constants/Entity.interface'; @@ -40,9 +40,10 @@ export const validateForm = () => { .scrollIntoView() .should('be.visible') .type(INVALID_NAMES.MAX_LENGTH); - cy.get('#name_help') - .should('be.visible') - .contains(NAME_MAX_LENGTH_VALIDATION_ERROR); + cy.get('#name_help').should( + 'contain', + NAME_MIN_MAX_LENGTH_VALIDATION_ERROR_1_128 + ); // with special char validation cy.get('[data-testid="name"]') diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Form.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Form.ts new file mode 100644 index 00000000000..992370c75b6 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Form.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2024 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EXAMPLE_LONG_STRING } from '../../constants/constants'; + +export const validateFormNameFieldInput = ({ + fieldSelector = '#name', + checkEmpty = true, + checkLong = true, + fieldName, + errorDivSelector, + value, +}: { + value: string; + fieldName: string; + errorDivSelector: string; + fieldSelector?: string; + checkEmpty?: boolean; + checkLong?: boolean; +}) => { + if (checkEmpty) { + // Check empty name field message + cy.get(fieldSelector).type('test'); + cy.get(fieldSelector).clear(); + cy.get(`${errorDivSelector} .ant-form-item-explain-error`).contains( + `${fieldName} is required` + ); + } + + if (checkLong) { + // Check long name field message + cy.get(fieldSelector).type(EXAMPLE_LONG_STRING); + cy.get(`${errorDivSelector} .ant-form-item-explain-error`).contains( + `${fieldName} size must be between 1 and 128` + ); + cy.get(fieldSelector).clear(); + } + + cy.get(fieldSelector).type(value); +}; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Teams.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Teams.ts index 302a94ca978..20dd951f9a3 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Teams.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Teams.ts @@ -17,6 +17,7 @@ import { toastNotification, verifyResponseStatusCode, } from '../common'; +import { validateFormNameFieldInput } from './Form'; const TEAM_TYPES = ['Department', 'Division', 'Group']; @@ -179,7 +180,12 @@ export const addTeam = ( verifyResponseStatusCode('@addTeam', 200); // Entering team details - cy.get('[data-testid="name"]').type(teamDetails.name); + validateFormNameFieldInput({ + value: teamDetails.name, + fieldName: 'Name', + fieldSelector: '[data-testid="name"]', + errorDivSelector: '#add-team-nest-messages_name_help', + }); cy.get('[data-testid="display-name"]').type(teamDetails.name); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.ts b/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.ts index 5232c79f3a9..f2e4a42be64 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.ts @@ -621,9 +621,8 @@ export const NAME_VALIDATION_ERROR = export const NAME_MIN_MAX_LENGTH_VALIDATION_ERROR = 'Name size must be between 2 and 64'; - -export const NAME_MAX_LENGTH_VALIDATION_ERROR = - 'Name can be a maximum of 128 characters'; +export const NAME_MIN_MAX_LENGTH_VALIDATION_ERROR_1_128 = + 'Name size must be between 1 and 128'; export const DOMAIN_1 = { name: 'Cypress%Domain', @@ -836,3 +835,5 @@ export const JWT_EXPIRY_TIME_MAP = { '1 hour': 3600, '2 hours': 7200, }; + +export const EXAMPLE_LONG_STRING = 'name'.repeat(33); // 132 characters diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/CustomMetric.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/CustomMetric.spec.ts index f32b2138066..4d03ca276ab 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/CustomMetric.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/CustomMetric.spec.ts @@ -20,7 +20,7 @@ import { visitEntityDetailsPage } from '../../common/Utils/Entity'; import { getToken } from '../../common/Utils/LocalStorage'; import { INVALID_NAMES, - NAME_MAX_LENGTH_VALIDATION_ERROR, + NAME_MIN_MAX_LENGTH_VALIDATION_ERROR_1_128, NAME_VALIDATION_ERROR, uuid, } from '../../constants/constants'; @@ -53,7 +53,10 @@ const validateForm = (isColumnMetric = false) => { // max length validation cy.get('#name').scrollIntoView().type(INVALID_NAMES.MAX_LENGTH); - cy.get('#name_help').should('contain', NAME_MAX_LENGTH_VALIDATION_ERROR); + cy.get('#name_help').should( + 'contain', + NAME_MIN_MAX_LENGTH_VALIDATION_ERROR_1_128 + ); // with special char validation cy.get('#name') diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/AddRoleAndAssignToUser.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/AddRoleAndAssignToUser.spec.ts index ca15d9760c7..871dbc88f81 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/AddRoleAndAssignToUser.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/AddRoleAndAssignToUser.spec.ts @@ -17,6 +17,7 @@ import { uuid, verifyResponseStatusCode, } from '../../common/common'; +import { validateFormNameFieldInput } from '../../common/Utils/Form'; import { BASE_URL } from '../../constants/constants'; import { GlobalSettingOptions } from '../../constants/settings.constant'; @@ -44,7 +45,11 @@ describe( cy.get('[data-testid="inactive-link"]').should('contain', 'Add New Role'); // Entering name - cy.get('#name').type(roleName); + validateFormNameFieldInput({ + value: roleName, + fieldName: 'Name', + errorDivSelector: '#name_help', + }); // Entering descrription cy.get(descriptionBox).type('description'); // Select the policies diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/NotificationAlerts.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/NotificationAlerts.spec.ts index 8480e41911b..637849f3bd8 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/NotificationAlerts.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/NotificationAlerts.spec.ts @@ -33,6 +33,7 @@ import { createSingleLevelEntity, hardDeleteService, } from '../../common/EntityUtils'; +import { validateFormNameFieldInput } from '../../common/Utils/Form'; import { getToken } from '../../common/Utils/LocalStorage'; import { ALERT_DESCRIPTION, @@ -155,7 +156,11 @@ describe( cy.get('[data-testid="create-notification"]').click(); // Enter alert name - cy.get('#name').type(ALERT_NAME); + validateFormNameFieldInput({ + value: ALERT_NAME, + fieldName: 'Name', + errorDivSelector: '#name_help', + }); // Enter description cy.get(descriptionBox).clear().type(ALERT_DESCRIPTION); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/ObservabilityAlerts.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/ObservabilityAlerts.spec.ts index ea44849a518..9475df36a4f 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/ObservabilityAlerts.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/ObservabilityAlerts.spec.ts @@ -29,6 +29,7 @@ import { verifyResponseStatusCode, } from '../../common/common'; import { createEntityTable, hardDeleteService } from '../../common/EntityUtils'; +import { validateFormNameFieldInput } from '../../common/Utils/Form'; import { getToken } from '../../common/Utils/LocalStorage'; import { ALERT_DESCRIPTION, @@ -371,7 +372,11 @@ describe( cy.get('[data-testid="create-observability"]').click(); // Enter alert name - cy.get('#name').type(ALERT_NAME); + validateFormNameFieldInput({ + value: ALERT_NAME, + fieldName: 'Name', + errorDivSelector: '#name_help', + }); // Enter description cy.get(descriptionBox).clear().type(ALERT_DESCRIPTION); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/PersonaFlow.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/PersonaFlow.spec.ts index 23b21de5ff4..2a4c894cb61 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/PersonaFlow.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/PersonaFlow.spec.ts @@ -17,6 +17,7 @@ import { toastNotification, verifyResponseStatusCode, } from '../../common/common'; +import { validateFormNameFieldInput } from '../../common/Utils/Form'; import { getToken } from '../../common/Utils/LocalStorage'; import { DELETE_TERM } from '../../constants/constants'; import { PERSONA_DETAILS, USER_DETAILS } from '../../constants/EntityConstant'; @@ -41,7 +42,12 @@ const updatePersonaDisplayName = (displayName) => { }; describe('Persona operations', { tags: 'Settings' }, () => { - const user = {}; + const user = { + details: { + id: '', + name: '', + }, + }; const userSearchText = `${USER_DETAILS.firstName}${USER_DETAILS.lastName}`; before(() => { cy.login(); @@ -87,6 +93,12 @@ describe('Persona operations', { tags: 'Settings' }, () => { it('Persona creation should work properly', () => { cy.get('[data-testid="add-persona-button"]').scrollIntoView().click(); cy.get('[data-testid="name"]').clear().type(PERSONA_DETAILS.name); + validateFormNameFieldInput({ + value: PERSONA_DETAILS.name, + fieldName: 'Name', + fieldSelector: '[data-testid="name"]', + errorDivSelector: '#name_help', + }); cy.get('[data-testid="displayName"]') .clear() .type(PERSONA_DETAILS.displayName); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Policies.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Policies.spec.ts index 31ef739df75..360bb912905 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Policies.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Policies.spec.ts @@ -17,6 +17,7 @@ import { uuid, verifyResponseStatusCode, } from '../../common/common'; +import { validateFormNameFieldInput } from '../../common/Utils/Form'; import { BASE_URL } from '../../constants/constants'; import { GlobalSettingOptions } from '../../constants/settings.constant'; @@ -58,7 +59,12 @@ const newRuledescription = `This is ${newRuleName} description`; const updatedRuleName = `New-Rule-test-${uuid()}-updated`; const addRule = (rulename, ruleDescription, descriptionIndex) => { - cy.get('[data-testid="rule-name"]').should('be.visible').type(rulename); + validateFormNameFieldInput({ + value: rulename, + fieldName: 'Name', + fieldSelector: '[data-testid="rule-name"]', + errorDivSelector: '#ruleName_help', + }); // Enter rule description cy.get('.toastui-editor-md-container > .toastui-editor > .ProseMirror') .eq(descriptionIndex) @@ -127,6 +133,12 @@ describe('Policy page should work properly', { tags: 'Settings' }, () => { // Enter policy name cy.get('[data-testid="policy-name"]').should('be.visible').type(policyName); + validateFormNameFieldInput({ + value: policyName, + fieldName: 'Name', + fieldSelector: '[data-testid="policy-name"]', + errorDivSelector: '#name_help', + }); // Enter description cy.get(descriptionBox).eq(0).type(description); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/BlockEditor/Extensions/image/ImageComponent.tsx b/openmetadata-ui/src/main/resources/ui/src/components/BlockEditor/Extensions/image/ImageComponent.tsx index 49b1d178bd4..85ae0eb816d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/BlockEditor/Extensions/image/ImageComponent.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/BlockEditor/Extensions/image/ImageComponent.tsx @@ -123,7 +123,17 @@ const PopoverContent: FC = ({ onFinish={handleEmbedImage}> - + { if (metricNames.includes(value) && !isEditMode) { @@ -126,9 +111,6 @@ const CustomMetricForm = ({ rules={[ { required: true, - message: t('label.field-required', { - field: t('label.column'), - }), }, ]}> = ({ }, [isBot, authenticationMechanism]); return ( - <> -
- - - + + + + - - - + + + - - {!isEmpty(authenticationMechanism) && ( - - )} - - -
- + )} + + + ); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/CronEditor/CronEditor.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/CronEditor/CronEditor.tsx index a00bc07c6c5..eb04b2d6920 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/CronEditor/CronEditor.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/CronEditor/CronEditor.tsx @@ -549,6 +549,9 @@ const CronEditor: FC = (props) => { rules={[ { required: true, + message: t('label.field-required', { + field: t('label.cron'), + }), }, { validator: async (_, value) => { diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/Form.constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/Form.constants.ts new file mode 100644 index 00000000000..555d77df330 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/constants/Form.constants.ts @@ -0,0 +1,38 @@ +/* + * Copyright 2024 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Rule } from 'antd/lib/form'; +import { t } from 'i18next'; +import { ENTITY_NAME_REGEX } from './regex.constants'; + +export const NAME_FIELD_RULES: Rule[] = [ + { + required: true, + message: t('label.field-required', { + field: t('label.name'), + }), + }, + { + min: 1, + max: 128, + message: t('message.entity-size-in-between', { + entity: t('label.name'), + min: 1, + max: 128, + }), + }, + { + pattern: ENTITY_NAME_REGEX, + message: t('message.entity-name-validation'), + }, +]; diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/AddNotificationPage/AddNotificationPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/AddNotificationPage/AddNotificationPage.tsx index fa6beb7b57c..c860795532c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/AddNotificationPage/AddNotificationPage.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/AddNotificationPage/AddNotificationPage.tsx @@ -21,9 +21,9 @@ import Loader from '../../components/common/Loader/Loader'; import ResizablePanels from '../../components/common/ResizablePanels/ResizablePanels'; import RichTextEditor from '../../components/common/RichTextEditor/RichTextEditor'; import TitleBreadcrumb from '../../components/common/TitleBreadcrumb/TitleBreadcrumb.component'; -import { ROUTES } from '../../constants/constants'; +import { ROUTES, VALIDATION_MESSAGES } from '../../constants/constants'; +import { NAME_FIELD_RULES } from '../../constants/Form.constants'; import { GlobalSettingsMenuCategory } from '../../constants/GlobalSettings.constants'; -import { ENTITY_NAME_REGEX } from '../../constants/regex.constants'; import { CreateEventSubscription } from '../../generated/events/api/createEventSubscription'; import { AlertType, @@ -212,6 +212,7 @@ const AddNotificationPage = () => { ...alert, resources: alert?.filteringRules?.resources, }} + validateMessages={VALIDATION_MESSAGES} onFinish={handleSave}> {loadingCount > 0 ? ( @@ -222,13 +223,7 @@ const AddNotificationPage = () => { label={t('label.name')} labelCol={{ span: 24 }} name="name" - rules={[ - { required: true }, - { - pattern: ENTITY_NAME_REGEX, - message: t('message.entity-name-validation'), - }, - ]}> + rules={NAME_FIELD_RULES}> @@ -224,13 +225,7 @@ function AddObservabilityPage() { label={t('label.name')} labelCol={{ span: 24 }} name="name" - rules={[ - { required: true }, - { - pattern: ENTITY_NAME_REGEX, - message: t('message.entity-name-validation'), - }, - ]}> + rules={NAME_FIELD_RULES}> { + rules={NAME_FIELD_RULES}> = ({ ruleData, setRuleData }) => { + rules={NAME_FIELD_RULES}> { + rules={NAME_FIELD_RULES}> { const getDescription = () => { if (!isEmpty(columnObject) && !isUndefined(columnObject)) { - return columnObject.description || ''; + return columnObject.description ?? ''; } else { - return entityData.description || ''; + return entityData.description ?? ''; } }; @@ -225,6 +226,7 @@ const UpdateDescription = () => { data-testid="form-container" form={form} layout="vertical" + validateMessages={VALIDATION_MESSAGES} onFinish={onCreateTask}> { data-testid="assignees" label={`${t('label.assignee-plural')}:`} name="assignees" - rules={[ - { - required: true, - message: t('message.field-text-is-required', { - fieldText: t('label.assignee-plural'), - }), - }, - ]}> + rules={[{ required: true }]}> { data-testid="description-tabs" label={`${t('label.description')}:`} name="description" - rules={[ - { - required: true, - message: t('message.field-text-is-required', { - fieldText: t('label.description'), - }), - }, - ]}> + rules={[{ required: true }]}> = ({ label={t('label.name')} name="name" rules={[ - { - required: true, - type: 'string', - min: 1, - max: 128, - whitespace: true, - }, - { - pattern: ENTITY_NAME_REGEX, - message: t('message.entity-name-validation'), - }, + ...NAME_FIELD_RULES, { validator: (_, value) => { if ( diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx index 50f64a14796..cc47389a999 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx @@ -21,6 +21,7 @@ import { Switch, TooltipProps, } from 'antd'; +import { RuleObject } from 'antd/lib/form'; import { TooltipPlacement } from 'antd/lib/tooltip'; import classNames from 'classnames'; import { compact, startCase } from 'lodash'; @@ -64,7 +65,12 @@ export const getField = (field: FieldProp) => { let internalFormItemProps: FormItemProps = {}; let fieldElement: ReactNode = null; let fieldRules = [...rules]; - if (required) { + // Check if required rule is already present to avoid rule duplication + const isRequiredRulePresent = rules.some( + (rule) => (rule as RuleObject).required ?? false + ); + + if (required && !isRequiredRulePresent) { fieldRules = [ ...fieldRules, {