mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-19 22:49:00 +00:00
Fixed No data placeholders for reviewers and related terms (#3359)
* Fixed No data placeholders for reviewers and related terms
This commit is contained in:
parent
f03fb1cafa
commit
4d1d25a58b
@ -29,7 +29,6 @@ import { getTagCategories, getTaglist } from '../../utils/TagsUtils';
|
||||
import { Button } from '../buttons/Button/Button';
|
||||
import Avatar from '../common/avatar/Avatar';
|
||||
import Description from '../common/description/Description';
|
||||
import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder';
|
||||
import NonAdminAction from '../common/non-admin-action/NonAdminAction';
|
||||
import PopOver from '../common/popover/PopOver';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
@ -181,7 +180,7 @@ const GlossaryDetails = ({ isHasAccess, glossary, updateGlossary }: props) => {
|
||||
}
|
||||
}, [glossary.reviewers]);
|
||||
|
||||
const rightPosButton = () => {
|
||||
const AddReviewerButton = () => {
|
||||
return (
|
||||
<NonAdminAction position="bottom" title={TITLE_FOR_NON_ADMIN_ACTION}>
|
||||
<Button
|
||||
@ -217,10 +216,10 @@ const GlossaryDetails = ({ isHasAccess, glossary, updateGlossary }: props) => {
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<ErrorPlaceHolder>
|
||||
<p className="tw-text-base tw-text-center">No Reviewers.</p>
|
||||
<p className="tw-text-lg tw-text-center tw-mt-2">{rightPosButton()}</p>
|
||||
</ErrorPlaceHolder>
|
||||
<div className="tw-py-3 tw-text-center tw-bg-white tw-border tw-border-main">
|
||||
<p className="tw-mb-3">No reviewers assigned</p>
|
||||
<p>{AddReviewerButton()}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -353,7 +352,7 @@ const GlossaryDetails = ({ isHasAccess, glossary, updateGlossary }: props) => {
|
||||
glossary.reviewers &&
|
||||
glossary.reviewers.length > 0 &&
|
||||
activeTab === 1
|
||||
? rightPosButton()
|
||||
? AddReviewerButton()
|
||||
: undefined
|
||||
}
|
||||
setActiveTab={setActiveTabHandler}
|
||||
|
@ -13,7 +13,12 @@
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { cloneDeep, includes, isEqual } from 'lodash';
|
||||
import { EntityTags, FormatedUsersData, GlossaryTermAssets } from 'Models';
|
||||
import {
|
||||
EntityTags,
|
||||
FormatedGlossaryTermData,
|
||||
FormatedUsersData,
|
||||
GlossaryTermAssets,
|
||||
} from 'Models';
|
||||
import React, { Fragment, useEffect, useState } from 'react';
|
||||
import {
|
||||
LIST_SIZE,
|
||||
@ -29,11 +34,11 @@ import SVGIcons from '../../utils/SvgUtils';
|
||||
import { getTagCategories, getTaglist } from '../../utils/TagsUtils';
|
||||
import { Button } from '../buttons/Button/Button';
|
||||
import Description from '../common/description/Description';
|
||||
import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder';
|
||||
import NonAdminAction from '../common/non-admin-action/NonAdminAction';
|
||||
import PopOver from '../common/popover/PopOver';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
import GlossaryReferenceModal from '../Modals/GlossaryReferenceModal/GlossaryReferenceModal';
|
||||
import RelatedTermsModal from '../Modals/RelatedTermsModal/RelatedTermsModal';
|
||||
import ReviewerModal from '../Modals/ReviewerModal/ReviewerModal.component';
|
||||
import TagsContainer from '../tags-container/tags-container';
|
||||
import Tags from '../tags/tags';
|
||||
@ -60,6 +65,7 @@ const GlossaryTermsV1 = ({
|
||||
const [isDescriptionEditable, setIsDescriptionEditable] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState(1);
|
||||
const [showRevieweModal, setShowRevieweModal] = useState(false);
|
||||
const [showRelatedTermsModal, setShowRelatedTermsModal] = useState(false);
|
||||
const [isSynonymsEditing, setIsSynonymsEditing] = useState(false);
|
||||
const [isReferencesEditing, setIsReferencesEditing] = useState(false);
|
||||
const [synonyms, setSynonyms] = useState(
|
||||
@ -67,12 +73,9 @@ const GlossaryTermsV1 = ({
|
||||
);
|
||||
const [references, setReferences] = useState(glossaryTerm.references || []);
|
||||
const [reviewer, setReviewer] = useState<Array<FormatedUsersData>>([]);
|
||||
const [relatedTerms, setRelatedTerms] = useState<
|
||||
{
|
||||
relatedTerms: string;
|
||||
description: string;
|
||||
}[]
|
||||
>([]);
|
||||
const [relatedTerms, setRelatedTerms] = useState<FormatedGlossaryTermData[]>(
|
||||
[]
|
||||
);
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
@ -92,6 +95,32 @@ const GlossaryTermsV1 = ({
|
||||
},
|
||||
];
|
||||
|
||||
const onRelatedTermsModalCancel = () => {
|
||||
setShowRelatedTermsModal(false);
|
||||
};
|
||||
|
||||
const handleRelatedTermsSave = (terms: Array<FormatedGlossaryTermData>) => {
|
||||
if (!isEqual(terms, relatedTerms)) {
|
||||
let updatedGlossaryTerm = cloneDeep(glossaryTerm);
|
||||
const oldTerms = terms.filter((d) => includes(relatedTerms, d));
|
||||
const newTerms = terms
|
||||
.filter((d) => !includes(relatedTerms, d))
|
||||
.map((d) => ({
|
||||
id: d.id,
|
||||
type: d.type,
|
||||
displayName: d.displayName,
|
||||
name: d.name,
|
||||
}));
|
||||
updatedGlossaryTerm = {
|
||||
...updatedGlossaryTerm,
|
||||
relatedTerms: [...oldTerms, ...newTerms],
|
||||
};
|
||||
setRelatedTerms(terms);
|
||||
handleGlossaryTermUpdate(updatedGlossaryTerm);
|
||||
}
|
||||
onRelatedTermsModalCancel();
|
||||
};
|
||||
|
||||
const onReviewerModalCancel = () => {
|
||||
setShowRevieweModal(false);
|
||||
};
|
||||
@ -258,19 +287,12 @@ const GlossaryTermsV1 = ({
|
||||
}, [glossaryTerm.reviewers]);
|
||||
|
||||
useEffect(() => {
|
||||
if (glossaryTerm.relatedTerms && glossaryTerm.relatedTerms.length) {
|
||||
setRelatedTerms(
|
||||
glossaryTerm.relatedTerms.map((term) => {
|
||||
return {
|
||||
relatedTerms: (term.displayName || term.name) as string,
|
||||
description: term.description ?? '',
|
||||
};
|
||||
})
|
||||
);
|
||||
if (glossaryTerm.relatedTerms?.length) {
|
||||
setRelatedTerms(glossaryTerm.relatedTerms as FormatedGlossaryTermData[]);
|
||||
}
|
||||
}, [glossaryTerm]);
|
||||
}, [glossaryTerm.relatedTerms]);
|
||||
|
||||
const rightPosButton = () => {
|
||||
const AddReviewerButton = () => {
|
||||
return (
|
||||
<NonAdminAction position="bottom" title={TITLE_FOR_NON_ADMIN_ACTION}>
|
||||
<Button
|
||||
@ -288,6 +310,24 @@ const GlossaryTermsV1 = ({
|
||||
);
|
||||
};
|
||||
|
||||
const AddRelatedTermButton = () => {
|
||||
return (
|
||||
<NonAdminAction position="bottom" title={TITLE_FOR_NON_ADMIN_ACTION}>
|
||||
<Button
|
||||
className={classNames('tw-h-8 tw-rounded', {
|
||||
'tw-opacity-40': isHasAccess,
|
||||
})}
|
||||
data-testid="add-new-tag-button"
|
||||
size="small"
|
||||
theme="primary"
|
||||
variant="contained"
|
||||
onClick={() => setShowRelatedTermsModal(true)}>
|
||||
Add Related Term
|
||||
</Button>
|
||||
</NonAdminAction>
|
||||
);
|
||||
};
|
||||
|
||||
const getReviewerTabData = () => {
|
||||
return glossaryTerm.reviewers && glossaryTerm.reviewers.length > 0 ? (
|
||||
<div className="tw-grid xxl:tw-grid-cols-4 lg:tw-grid-cols-3 md:tw-grid-cols-2 tw-gap-4">
|
||||
@ -306,13 +346,26 @@ const GlossaryTermsV1 = ({
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<ErrorPlaceHolder>
|
||||
<p className="tw-text-base tw-text-center">No Reviewers.</p>
|
||||
<p className="tw-text-lg tw-text-center tw-mt-2">{rightPosButton()}</p>
|
||||
</ErrorPlaceHolder>
|
||||
<div className="tw-py-3 tw-text-center tw-bg-white tw-border tw-border-main">
|
||||
<p className="tw-mb-3">No reviewers assigned</p>
|
||||
<p>{AddReviewerButton()}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const getTabPaneButton = () => {
|
||||
switch (activeTab) {
|
||||
case 1: {
|
||||
return relatedTerms.length ? AddRelatedTermButton() : undefined;
|
||||
}
|
||||
case 3: {
|
||||
return glossaryTerm.reviewers?.length ? AddReviewerButton() : undefined;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="tw-w-full tw-h-full tw-flex tw-flex-col">
|
||||
<div className="tw-flex tw-gap-5 tw-mb-2">
|
||||
@ -551,19 +604,18 @@ const GlossaryTermsV1 = ({
|
||||
<TabsPane
|
||||
activeTab={activeTab}
|
||||
className="tw-flex-initial"
|
||||
rightPosButton={
|
||||
glossaryTerm.reviewers &&
|
||||
glossaryTerm.reviewers.length > 0 &&
|
||||
activeTab === 3
|
||||
? rightPosButton()
|
||||
: undefined
|
||||
}
|
||||
rightPosButton={getTabPaneButton()}
|
||||
setActiveTab={activeTabHandler}
|
||||
tabs={tabs}
|
||||
/>
|
||||
|
||||
<div className="tw-flex-grow tw-py-4">
|
||||
{activeTab === 1 && <RelationshipTab data={relatedTerms} />}
|
||||
{activeTab === 1 && (
|
||||
<RelationshipTab
|
||||
addButton={<>{AddRelatedTermButton()}</>}
|
||||
data={relatedTerms}
|
||||
/>
|
||||
)}
|
||||
{activeTab === 2 && (
|
||||
<AssetsTabs
|
||||
assetData={assetData}
|
||||
@ -573,6 +625,14 @@ const GlossaryTermsV1 = ({
|
||||
{activeTab === 3 && getReviewerTabData()}
|
||||
</div>
|
||||
|
||||
{showRelatedTermsModal && (
|
||||
<RelatedTermsModal
|
||||
header="Add Related Terms"
|
||||
relatedTerms={relatedTerms}
|
||||
onCancel={onRelatedTermsModalCancel}
|
||||
onSave={handleRelatedTermsSave}
|
||||
/>
|
||||
)}
|
||||
{showRevieweModal && (
|
||||
<ReviewerModal
|
||||
header="Add Reviewer"
|
||||
|
@ -12,68 +12,69 @@
|
||||
*/
|
||||
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
import ErrorPlaceHolder from '../../common/error-with-placeholder/ErrorPlaceHolder';
|
||||
import { FormatedGlossaryTermData } from 'Models';
|
||||
import React, { ReactNode } from 'react';
|
||||
import RichTextEditorPreviewer from '../../common/rich-text-editor/RichTextEditorPreviewer';
|
||||
/* eslint-disable max-len */
|
||||
// need to remove eslint disable once API data comes
|
||||
|
||||
type RelationshipTableType = {
|
||||
relatedTerms: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
data?: RelationshipTableType[];
|
||||
data?: FormatedGlossaryTermData[];
|
||||
addButton?: ReactNode;
|
||||
};
|
||||
|
||||
const RelationshipTab = ({ data }: Props) => {
|
||||
return data?.length ? (
|
||||
const RelationshipTab = ({ data, addButton }: Props) => {
|
||||
return (
|
||||
<div className="tw-table-responsive" id="relationship">
|
||||
<table className="tw-w-full tw-bg-white">
|
||||
<thead>
|
||||
<tr className="tableHead-row">
|
||||
<th className="tableHead-cell">Terms</th>
|
||||
<th className="tableHead-cell tw-w-2/12">Terms</th>
|
||||
<th className="tableHead-cell">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.map((row, index) => {
|
||||
return (
|
||||
<tr className={classNames('tableBody-row')} key={index}>
|
||||
<td
|
||||
className={classNames(
|
||||
'tableBody-cell tw-group tw-relative tw-align-baseline tw-w-2/12'
|
||||
)}>
|
||||
{row.relatedTerms}
|
||||
</td>
|
||||
<td
|
||||
className={classNames(
|
||||
'tableBody-cell tw-group tw-relative tw-align-baseline'
|
||||
)}>
|
||||
<div
|
||||
className="description-text"
|
||||
data-testid="description-text">
|
||||
{row.description.trim() ? (
|
||||
<RichTextEditorPreviewer
|
||||
enableSeeMoreVariant={false}
|
||||
markdown={row.description}
|
||||
/>
|
||||
) : (
|
||||
<span className="tw-no-description">No description</span>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
{data?.length ? (
|
||||
data.map((row, index) => {
|
||||
return (
|
||||
<tr className={classNames('tableBody-row')} key={index}>
|
||||
<td
|
||||
className={classNames(
|
||||
'tableBody-cell tw-group tw-relative tw-align-baseline'
|
||||
)}>
|
||||
{row.displayName || row.name}
|
||||
</td>
|
||||
<td
|
||||
className={classNames(
|
||||
'tableBody-cell tw-group tw-relative tw-align-baseline'
|
||||
)}>
|
||||
<div
|
||||
className="description-text"
|
||||
data-testid="description-text">
|
||||
{row.description?.trim() ? (
|
||||
<RichTextEditorPreviewer
|
||||
enableSeeMoreVariant={false}
|
||||
markdown={row.description}
|
||||
/>
|
||||
) : (
|
||||
<span className="tw-no-description">
|
||||
No description
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<tr className="tableBody-row">
|
||||
<td className="tableBody-cell tw-text-center" colSpan={4}>
|
||||
<p className="tw-mb-3">No related terms available.</p>
|
||||
{addButton}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
) : (
|
||||
<ErrorPlaceHolder>
|
||||
<p className="tw-text-base tw-text-center">No related terms.</p>
|
||||
</ErrorPlaceHolder>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -44,7 +44,7 @@ const RelatedTermsModal = ({
|
||||
>(relatedTerms ?? []);
|
||||
|
||||
const getSearchedTerms = (searchedData: FormatedGlossaryTermData[]) => {
|
||||
const currOptions = selectedOption.map((item) => item.fqdn);
|
||||
const currOptions = selectedOption.map((item) => item.fqdn || item.name);
|
||||
const data = searchedData.filter((item: FormatedGlossaryTermData) => {
|
||||
return !currOptions.includes(item.fqdn);
|
||||
});
|
||||
|
@ -223,6 +223,7 @@ declare module 'Models' {
|
||||
fqdn: string;
|
||||
type: string;
|
||||
id: string;
|
||||
description?: string;
|
||||
};
|
||||
|
||||
export interface FormatedGlossarySuggestion {
|
||||
|
Loading…
x
Reference in New Issue
Block a user