mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-19 06:28:03 +00:00
parent
171477cbb9
commit
d18198bb20
@ -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 = ({
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
{showErrorMsg.invalidReferences
|
||||
? errorMsg('Endpoints should be valid URL.')
|
||||
: null}
|
||||
</div>
|
||||
|
||||
<Field>
|
||||
|
@ -75,7 +75,7 @@ const GlossaryReferences: FunctionComponent<Props> = ({
|
||||
<input
|
||||
className="tw-form-inputs tw-px-3 tw-py-1"
|
||||
id={`name-${i}`}
|
||||
name="key"
|
||||
name="name"
|
||||
placeholder="Name"
|
||||
type="text"
|
||||
value={value.name}
|
||||
@ -89,7 +89,7 @@ const GlossaryReferences: FunctionComponent<Props> = ({
|
||||
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) =>
|
||||
|
@ -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 ? (
|
||||
<div className="tw-flex">
|
||||
{references.map((d, i) => (
|
||||
<>
|
||||
<Fragment key={i}>
|
||||
{i > 0 && <span className="tw-mr-2">,</span>}
|
||||
<a
|
||||
className="link-text tw-flex"
|
||||
data-testid="owner-link"
|
||||
href={d?.endpoint}
|
||||
key={i}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank">
|
||||
<>
|
||||
<span
|
||||
className={classNames(
|
||||
'tw-mr-1 tw-inline-block tw-truncate',
|
||||
{
|
||||
'tw-w-52': (d?.name as string).length > 32,
|
||||
}
|
||||
)}
|
||||
title={d?.name as string}>
|
||||
{d?.name}
|
||||
</span>
|
||||
|
||||
<SVGIcons
|
||||
alt="external-link"
|
||||
className="tw-align-middle"
|
||||
icon="external-link"
|
||||
width="12px"
|
||||
/>
|
||||
</>
|
||||
<span
|
||||
className={classNames(
|
||||
'tw-mr-1 tw-inline-block tw-truncate',
|
||||
{
|
||||
'tw-w-52': (d?.name as string).length > 32,
|
||||
}
|
||||
)}
|
||||
title={d?.name as string}>
|
||||
{d?.name}
|
||||
</span>
|
||||
<SVGIcons
|
||||
alt="external-link"
|
||||
className="tw-align-middle"
|
||||
icon="external-link"
|
||||
width="12px"
|
||||
/>
|
||||
</a>
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
|
@ -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<TermReference[]>(
|
||||
referenceList || []
|
||||
cloneDeep(referenceList) || []
|
||||
);
|
||||
const [errMsg, setErrMsg] = useState<string>();
|
||||
|
||||
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)}
|
||||
</div>
|
||||
<div className="tw-modal-footer" data-testid="cta-container">
|
||||
<Button
|
||||
@ -66,7 +98,7 @@ const GlossaryReferenceModal = ({
|
||||
theme="primary"
|
||||
type="submit"
|
||||
variant="contained"
|
||||
onClick={() => onSave(references)}>
|
||||
onClick={handleSave}>
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -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 },
|
||||
|
@ -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({
|
||||
|
Loading…
x
Reference in New Issue
Block a user