diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddGlossaryTerm/AddGlossaryTerm.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddGlossaryTerm/AddGlossaryTerm.component.tsx index c7bd06cf8e6..b79d2fdb795 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/AddGlossaryTerm/AddGlossaryTerm.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/AddGlossaryTerm/AddGlossaryTerm.component.tsx @@ -19,11 +19,15 @@ import { FormatedUsersData, } from 'Models'; import React, { useEffect, useRef, useState } from 'react'; -import { UrlEntityCharRegEx } from '../../constants/regex.constants'; import { PageLayoutType } from '../../enums/layout.enum'; import { CreateGlossaryTerm } from '../../generated/api/data/createGlossaryTerm'; import { TermReference } from '../../generated/entity/data/glossaryTerm'; -import { errorMsg, requiredField } from '../../utils/CommonUtils'; +import { + errorMsg, + isUrlFriendlyName, + isValidUrl, + requiredField, +} from '../../utils/CommonUtils'; import SVGIcons from '../../utils/SvgUtils'; import { Button } from '../buttons/Button/Button'; import MarkdownWithPreview from '../common/editor/MarkdownWithPreview'; @@ -57,6 +61,7 @@ const AddGlossaryTerm = ({ const [showErrorMsg, setShowErrorMsg] = useState<{ [key: string]: boolean }>({ name: false, invalidName: false, + invalidReferences: false, }); const [name, setName] = useState(''); @@ -158,12 +163,29 @@ const AddGlossaryTerm = ({ const newFormValues = [...references]; newFormValues[i][field] = value; setReferences(newFormValues); + setShowErrorMsg((prev) => { + return { ...prev, invalidReferences: false }; + }); }; - const validateForm = () => { + const isValidReferences = (refs: TermReference[]): boolean => { + let retVal = true; + for (const ref of refs) { + if (!isValidUrl(ref.endpoint || '')) { + retVal = false; + + break; + } + } + + return retVal; + }; + + const validateForm = (refs: TermReference[]) => { const errMsg = { name: !name.trim(), - invalidName: UrlEntityCharRegEx.test(name.trim()), + invalidName: !isUrlFriendlyName(name.trim()), + invalidReferences: !isValidReferences(refs), }; setShowErrorMsg(errMsg); @@ -171,16 +193,19 @@ const AddGlossaryTerm = ({ }; const handleSave = () => { - const updatedReference = references.filter( - (ref) => !isEmpty(ref.endpoint) && !isEmpty(ref.name) - ); + const updatedReference = references + .map((ref) => ({ + name: ref.name?.trim(), + endpoint: ref.endpoint?.trim(), + })) + .filter((ref) => !isEmpty(ref.endpoint) && !isEmpty(ref.name)); const updatedTerms = relatedTerms.map((term) => ({ id: term.id, type: term.type, })); - if (validateForm()) { + if (validateForm(updatedReference)) { const data: CreateGlossaryTerm = { name, displayName: name, @@ -382,6 +407,9 @@ const AddGlossaryTerm = ({ ))} + {showErrorMsg.invalidReferences + ? errorMsg('Endpoints should be valid URL.') + : null} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/GlossaryReferences/GlossaryReferences.tsx b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryReferences/GlossaryReferences.tsx index 0b0913cb8cc..6d878e1b424 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/GlossaryReferences/GlossaryReferences.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryReferences/GlossaryReferences.tsx @@ -75,7 +75,7 @@ const GlossaryReferences: FunctionComponent = ({ = ({ className="tw-form-inputs tw-px-3 tw-py-1" id={`url-${i}`} name="endpoint" - placeholder="url" + placeholder="Endpoint" type="text" value={value.endpoint} onChange={(e) => diff --git a/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/GlossaryTermsV1.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/GlossaryTermsV1.component.tsx index 0f48eed069f..2ce2e53527d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/GlossaryTermsV1.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/GlossaryTermsV1.component.tsx @@ -14,7 +14,7 @@ import classNames from 'classnames'; import { cloneDeep, includes, isEqual } from 'lodash'; import { EntityTags, FormatedUsersData, GlossaryTermAssets } from 'Models'; -import React, { useEffect, useState } from 'react'; +import React, { Fragment, useEffect, useState } from 'react'; import { LIST_SIZE, TITLE_FOR_NON_ADMIN_ACTION, @@ -102,7 +102,12 @@ const GlossaryTermsV1 = ({ const oldReviewer = data.filter((d) => includes(reviewer, d)); const newReviewer = data .filter((d) => !includes(reviewer, d)) - .map((d) => ({ id: d.id, type: d.type })); + .map((d) => ({ + id: d.id, + type: d.type, + displayName: d.displayName, + name: d.name, + })); updatedGlossaryTerm = { ...updatedGlossaryTerm, reviewers: [...oldReviewer, ...newReviewer], @@ -384,36 +389,32 @@ const GlossaryTermsV1 = ({ {references && references.length ? (
{references.map((d, i) => ( - <> + {i > 0 && ,} - <> - 32, - } - )} - title={d?.name as string}> - {d?.name} - - - - + 32, + } + )} + title={d?.name as string}> + {d?.name} + + - + ))}
) : ( diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Modals/GlossaryReferenceModal/GlossaryReferenceModal.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Modals/GlossaryReferenceModal/GlossaryReferenceModal.tsx index 7865b992f72..645974d1451 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Modals/GlossaryReferenceModal/GlossaryReferenceModal.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Modals/GlossaryReferenceModal/GlossaryReferenceModal.tsx @@ -11,8 +11,10 @@ * limitations under the License. */ +import { cloneDeep } from 'lodash'; import React, { useState } from 'react'; import { TermReference } from '../../../generated/entity/data/glossaryTerm'; +import { errorMsg, isValidUrl } from '../../../utils/CommonUtils'; import { Button } from '../../buttons/Button/Button'; import GlossaryReferences from '../../GlossaryReferences/GlossaryReferences'; @@ -30,11 +32,40 @@ const GlossaryReferenceModal = ({ header, }: RelatedTermsModalProp) => { const [references, setReferences] = useState( - referenceList || [] + cloneDeep(referenceList) || [] ); + const [errMsg, setErrMsg] = useState(); const handleReferenceFieldChange = (refs: TermReference[]) => { setReferences(refs); + setErrMsg(''); + }; + + const isValid = (refs: TermReference[]): boolean => { + let retVal = true; + for (const ref of refs) { + if (!isValidUrl(ref.endpoint || '')) { + retVal = false; + + break; + } + } + + return retVal; + }; + + const handleSave = () => { + const refList = references + .map((item) => ({ + name: item.name?.trim(), + endpoint: item.endpoint?.trim(), + })) + .filter((item) => item.name && item.endpoint); + if (isValid(refList)) { + onSave(references); + } else { + setErrMsg('Endpoints should be valid URL.'); + } }; return ( @@ -51,6 +82,7 @@ const GlossaryReferenceModal = ({ referenceList={references} onReferenceFieldChange={handleReferenceFieldChange} /> + {errMsg && errorMsg(errMsg)}
diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts index b058e8058bd..7ba7e1f2bcf 100644 --- a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts +++ b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts @@ -341,14 +341,14 @@ export const navLinkDevelop = [ ]; export const navLinkSettings = [ - { name: 'Teams', to: '/teams', disabled: false }, - { name: 'Roles', to: '/roles', disabled: false, isAdminOnly: true }, - { name: 'Users', to: '/user-list', disabled: false, isAdminOnly: true }, - { name: 'Tags', to: '/tags', disabled: false }, - // { name: 'Store', to: '/store', disabled: false }, - { name: 'Services', to: '/services', disabled: false }, - { name: 'Webhooks', to: '/webhooks', disabled: false }, { name: 'Glossaries', to: '/glossary', disabled: false }, + { name: 'Roles', to: '/roles', disabled: false, isAdminOnly: true }, + { name: 'Services', to: '/services', disabled: false }, + { name: 'Tags', to: '/tags', disabled: false }, + { name: 'Teams', to: '/teams', disabled: false }, + { name: 'Users', to: '/user-list', disabled: false, isAdminOnly: true }, + // { name: 'Store', to: '/store', disabled: false }, + { name: 'Webhooks', to: '/webhooks', disabled: false }, // { name: 'Ingestions', to: '/ingestion', disabled: false }, // { name: 'Marketplace', to: '/marketplace', disabled: true }, // { name: 'Preferences', to: '/preference', disabled: true }, diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/GlossaryPage/GlossaryPageV1.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/GlossaryPage/GlossaryPageV1.component.tsx index b22cfa54c20..5c9e6bf40af 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/GlossaryPage/GlossaryPageV1.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/GlossaryPage/GlossaryPageV1.component.tsx @@ -322,7 +322,32 @@ const GlossaryPageV1 = () => { const updateGlossary = (updatedData: Glossary) => { saveUpdatedGlossaryData(updatedData) .then((res: AxiosResponse) => { - setSelectedData(res.data); + if (res?.data) { + const { data } = res; + setSelectedData(data); + setGlossaries((pre) => { + return pre.map((item) => { + if (item.name === data.name) { + const { children } = item; + + return extend(cloneDeep(item), { ...data, children }); + } else { + return item; + } + }); + }); + setGlossariesList((pre) => { + return pre.map((item) => { + if (item.name === data.name) { + const { children } = item; + + return extend(cloneDeep(item), { ...data, children }); + } else { + return item; + } + }); + }); + } }) .catch((err: AxiosError) => { showToast({