Fixes: #3263, #3256 and Settings menu sorting (#3331)

This commit is contained in:
darth-coder00 2022-03-09 21:41:51 +05:30 committed by GitHub
parent 171477cbb9
commit d18198bb20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 130 additions and 44 deletions

View File

@ -19,11 +19,15 @@ import {
FormatedUsersData, FormatedUsersData,
} from 'Models'; } from 'Models';
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { UrlEntityCharRegEx } from '../../constants/regex.constants';
import { PageLayoutType } from '../../enums/layout.enum'; import { PageLayoutType } from '../../enums/layout.enum';
import { CreateGlossaryTerm } from '../../generated/api/data/createGlossaryTerm'; import { CreateGlossaryTerm } from '../../generated/api/data/createGlossaryTerm';
import { TermReference } from '../../generated/entity/data/glossaryTerm'; 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 SVGIcons from '../../utils/SvgUtils';
import { Button } from '../buttons/Button/Button'; import { Button } from '../buttons/Button/Button';
import MarkdownWithPreview from '../common/editor/MarkdownWithPreview'; import MarkdownWithPreview from '../common/editor/MarkdownWithPreview';
@ -57,6 +61,7 @@ const AddGlossaryTerm = ({
const [showErrorMsg, setShowErrorMsg] = useState<{ [key: string]: boolean }>({ const [showErrorMsg, setShowErrorMsg] = useState<{ [key: string]: boolean }>({
name: false, name: false,
invalidName: false, invalidName: false,
invalidReferences: false,
}); });
const [name, setName] = useState(''); const [name, setName] = useState('');
@ -158,12 +163,29 @@ const AddGlossaryTerm = ({
const newFormValues = [...references]; const newFormValues = [...references];
newFormValues[i][field] = value; newFormValues[i][field] = value;
setReferences(newFormValues); 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 = { const errMsg = {
name: !name.trim(), name: !name.trim(),
invalidName: UrlEntityCharRegEx.test(name.trim()), invalidName: !isUrlFriendlyName(name.trim()),
invalidReferences: !isValidReferences(refs),
}; };
setShowErrorMsg(errMsg); setShowErrorMsg(errMsg);
@ -171,16 +193,19 @@ const AddGlossaryTerm = ({
}; };
const handleSave = () => { const handleSave = () => {
const updatedReference = references.filter( const updatedReference = references
(ref) => !isEmpty(ref.endpoint) && !isEmpty(ref.name) .map((ref) => ({
); name: ref.name?.trim(),
endpoint: ref.endpoint?.trim(),
}))
.filter((ref) => !isEmpty(ref.endpoint) && !isEmpty(ref.name));
const updatedTerms = relatedTerms.map((term) => ({ const updatedTerms = relatedTerms.map((term) => ({
id: term.id, id: term.id,
type: term.type, type: term.type,
})); }));
if (validateForm()) { if (validateForm(updatedReference)) {
const data: CreateGlossaryTerm = { const data: CreateGlossaryTerm = {
name, name,
displayName: name, displayName: name,
@ -382,6 +407,9 @@ const AddGlossaryTerm = ({
</button> </button>
</div> </div>
))} ))}
{showErrorMsg.invalidReferences
? errorMsg('Endpoints should be valid URL.')
: null}
</div> </div>
<Field> <Field>

View File

@ -75,7 +75,7 @@ const GlossaryReferences: FunctionComponent<Props> = ({
<input <input
className="tw-form-inputs tw-px-3 tw-py-1" className="tw-form-inputs tw-px-3 tw-py-1"
id={`name-${i}`} id={`name-${i}`}
name="key" name="name"
placeholder="Name" placeholder="Name"
type="text" type="text"
value={value.name} value={value.name}
@ -89,7 +89,7 @@ const GlossaryReferences: FunctionComponent<Props> = ({
className="tw-form-inputs tw-px-3 tw-py-1" className="tw-form-inputs tw-px-3 tw-py-1"
id={`url-${i}`} id={`url-${i}`}
name="endpoint" name="endpoint"
placeholder="url" placeholder="Endpoint"
type="text" type="text"
value={value.endpoint} value={value.endpoint}
onChange={(e) => onChange={(e) =>

View File

@ -14,7 +14,7 @@
import classNames from 'classnames'; import classNames from 'classnames';
import { cloneDeep, includes, isEqual } from 'lodash'; import { cloneDeep, includes, isEqual } from 'lodash';
import { EntityTags, FormatedUsersData, GlossaryTermAssets } from 'Models'; import { EntityTags, FormatedUsersData, GlossaryTermAssets } from 'Models';
import React, { useEffect, useState } from 'react'; import React, { Fragment, useEffect, useState } from 'react';
import { import {
LIST_SIZE, LIST_SIZE,
TITLE_FOR_NON_ADMIN_ACTION, TITLE_FOR_NON_ADMIN_ACTION,
@ -102,7 +102,12 @@ const GlossaryTermsV1 = ({
const oldReviewer = data.filter((d) => includes(reviewer, d)); const oldReviewer = data.filter((d) => includes(reviewer, d));
const newReviewer = data const newReviewer = data
.filter((d) => !includes(reviewer, d)) .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 = {
...updatedGlossaryTerm, ...updatedGlossaryTerm,
reviewers: [...oldReviewer, ...newReviewer], reviewers: [...oldReviewer, ...newReviewer],
@ -384,36 +389,32 @@ const GlossaryTermsV1 = ({
{references && references.length ? ( {references && references.length ? (
<div className="tw-flex"> <div className="tw-flex">
{references.map((d, i) => ( {references.map((d, i) => (
<> <Fragment key={i}>
{i > 0 && <span className="tw-mr-2">,</span>} {i > 0 && <span className="tw-mr-2">,</span>}
<a <a
className="link-text tw-flex" className="link-text tw-flex"
data-testid="owner-link" data-testid="owner-link"
href={d?.endpoint} href={d?.endpoint}
key={i}
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank"> target="_blank">
<> <span
<span className={classNames(
className={classNames( 'tw-mr-1 tw-inline-block tw-truncate',
'tw-mr-1 tw-inline-block tw-truncate', {
{ 'tw-w-52': (d?.name as string).length > 32,
'tw-w-52': (d?.name as string).length > 32, }
} )}
)} title={d?.name as string}>
title={d?.name as string}> {d?.name}
{d?.name} </span>
</span> <SVGIcons
alt="external-link"
<SVGIcons className="tw-align-middle"
alt="external-link" icon="external-link"
className="tw-align-middle" width="12px"
icon="external-link" />
width="12px"
/>
</>
</a> </a>
</> </Fragment>
))} ))}
</div> </div>
) : ( ) : (

View File

@ -11,8 +11,10 @@
* limitations under the License. * limitations under the License.
*/ */
import { cloneDeep } from 'lodash';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { TermReference } from '../../../generated/entity/data/glossaryTerm'; import { TermReference } from '../../../generated/entity/data/glossaryTerm';
import { errorMsg, isValidUrl } from '../../../utils/CommonUtils';
import { Button } from '../../buttons/Button/Button'; import { Button } from '../../buttons/Button/Button';
import GlossaryReferences from '../../GlossaryReferences/GlossaryReferences'; import GlossaryReferences from '../../GlossaryReferences/GlossaryReferences';
@ -30,11 +32,40 @@ const GlossaryReferenceModal = ({
header, header,
}: RelatedTermsModalProp) => { }: RelatedTermsModalProp) => {
const [references, setReferences] = useState<TermReference[]>( const [references, setReferences] = useState<TermReference[]>(
referenceList || [] cloneDeep(referenceList) || []
); );
const [errMsg, setErrMsg] = useState<string>();
const handleReferenceFieldChange = (refs: TermReference[]) => { const handleReferenceFieldChange = (refs: TermReference[]) => {
setReferences(refs); 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 ( return (
@ -51,6 +82,7 @@ const GlossaryReferenceModal = ({
referenceList={references} referenceList={references}
onReferenceFieldChange={handleReferenceFieldChange} onReferenceFieldChange={handleReferenceFieldChange}
/> />
{errMsg && errorMsg(errMsg)}
</div> </div>
<div className="tw-modal-footer" data-testid="cta-container"> <div className="tw-modal-footer" data-testid="cta-container">
<Button <Button
@ -66,7 +98,7 @@ const GlossaryReferenceModal = ({
theme="primary" theme="primary"
type="submit" type="submit"
variant="contained" variant="contained"
onClick={() => onSave(references)}> onClick={handleSave}>
Save Save
</Button> </Button>
</div> </div>

View File

@ -341,14 +341,14 @@ export const navLinkDevelop = [
]; ];
export const navLinkSettings = [ 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: '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: 'Ingestions', to: '/ingestion', disabled: false },
// { name: 'Marketplace', to: '/marketplace', disabled: true }, // { name: 'Marketplace', to: '/marketplace', disabled: true },
// { name: 'Preferences', to: '/preference', disabled: true }, // { name: 'Preferences', to: '/preference', disabled: true },

View File

@ -322,7 +322,32 @@ const GlossaryPageV1 = () => {
const updateGlossary = (updatedData: Glossary) => { const updateGlossary = (updatedData: Glossary) => {
saveUpdatedGlossaryData(updatedData) saveUpdatedGlossaryData(updatedData)
.then((res: AxiosResponse) => { .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) => { .catch((err: AxiosError) => {
showToast({ showToast({