diff --git a/dashboard/src/components/ShowMore/DrawerBodyChipView.tsx b/dashboard/src/components/ShowMore/DrawerBodyChipView.tsx index 8d6c06c6f14..c655d46e23c 100644 --- a/dashboard/src/components/ShowMore/DrawerBodyChipView.tsx +++ b/dashboard/src/components/ShowMore/DrawerBodyChipView.tsx @@ -37,6 +37,7 @@ import SearchIcon from "@mui/icons-material/Search"; import ErrorRoundedIcon from "@mui/icons-material/ErrorRounded"; import { Link as MuiLink } from "@mui/material"; import { cloneDeep } from "@utils/Helper"; +import { EntityStatus } from "@utils/EntityStatus"; const CHIP_MAX_WIDTH = "200px"; @@ -328,11 +329,11 @@ const DrawerBodyChipView = ({ } onDelete={ - !isEmpty(removeApiMethod) && !isDeleteIcon + currentEntity?.status !== EntityStatus.DELETED && !isEmpty(removeApiMethod) && !isDeleteIcon ? () => { handleDelete(obj[displayKey] || obj); } - : isDeleteIcon && obj.count > 1 + : currentEntity?.status !== EntityStatus.DELETED && isDeleteIcon && obj.count > 1 ? () => { const searchParams = new URLSearchParams(); searchParams.set("tabActive", "classification"); diff --git a/dashboard/src/components/ShowMore/ShowMoreView.tsx b/dashboard/src/components/ShowMore/ShowMoreView.tsx index d6543410ead..ca40eb250c2 100644 --- a/dashboard/src/components/ShowMore/ShowMoreView.tsx +++ b/dashboard/src/components/ShowMore/ShowMoreView.tsx @@ -19,7 +19,7 @@ import Typography from "@mui/material/Typography"; import Chip from "@mui/material/Chip"; import MuiLink from "@mui/material/Link"; import { LightTooltip } from "../muiComponents"; -import { useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { EllipsisText } from "../commonComponents"; import { extractKeyValueFromEntity, isEmpty, serverError } from "@utils/Utils"; import { useAppDispatch, useAppSelector } from "@hooks/reducerHook"; @@ -31,8 +31,9 @@ import ErrorRoundedIcon from "@mui/icons-material/ErrorRounded"; import { fetchGlossaryData } from "@redux/slice/glossarySlice"; import { fetchGlossaryDetails } from "@redux/slice/glossaryDetailsSlice"; import ShowMoreDrawer from "./ShowMoreDrawer"; -import { openDrawer } from "@redux/slice/drawerSlice"; +import { openDrawer, closeDrawer } from "@redux/slice/drawerSlice"; import { cloneDeep } from "@utils/Helper"; +import { EntityStatus } from "@utils/EntityStatus"; const CHIP_MAX_WIDTH = "200px"; @@ -73,6 +74,12 @@ const ShowMoreView = ({ const gType = searchParams.get("gtype"); const dispatchApi = useAppDispatch(); + useEffect(() => { + return () => { + dispatchApi(closeDrawer()); + }; + }, [dispatchApi]); + const { classificationData = {} }: any = useAppSelector( (state: any) => state.classification ); @@ -310,13 +317,13 @@ const ShowMoreView = ({ } component="a" onDelete={ - !isEmpty(removeApiMethod) && !isDeleteIcon + !isEmpty(removeApiMethod) && !isDeleteIcon && currentEntity?.status !== EntityStatus.DELETED ? () => { // Handle undefined displayKey by extracting a string value const deleteValue = obj[displayKey] || obj.displayText || obj.text || obj.name || ''; handleDelete(deleteValue); } - : isDeleteIcon && obj.count > 1 + : isDeleteIcon && obj.count > 1 && currentEntity?.status !== EntityStatus.DELETED ? () => { const searchParams = new URLSearchParams(); searchParams.set("tabActive", "classification"); diff --git a/dashboard/src/components/ShowMore/__tests__/ShowMoreView.test.tsx b/dashboard/src/components/ShowMore/__tests__/ShowMoreView.test.tsx index 5e618258048..1ee9ca290da 100644 --- a/dashboard/src/components/ShowMore/__tests__/ShowMoreView.test.tsx +++ b/dashboard/src/components/ShowMore/__tests__/ShowMoreView.test.tsx @@ -151,6 +151,9 @@ jest.mock('@redux/slice/drawerSlice', () => ({ openDrawer: jest.fn((id: string) => ({ type: 'drawer/openDrawer', payload: id + })), + closeDrawer: jest.fn(() => ({ + type: 'drawer/closeDrawer' })) })); @@ -739,6 +742,26 @@ describe('ShowMoreView', () => { }); describe('Delete Icon Functionality', () => { + it('should not show delete button when currentEntity status is DELETED', () => { + const dataWithCount = [ + { typeName: 'Tag1' } + ]; + + render( + + + + ); + + expect(screen.queryByTestId('chip-ondelete-button')).not.toBeInTheDocument(); + }); + + it('should show count when isDeleteIcon is true and count > 1', () => { const dataWithCount = [ { typeName: 'Tag1', count: 2 }, diff --git a/dashboard/src/utils/EntityStatus.ts b/dashboard/src/utils/EntityStatus.ts new file mode 100644 index 00000000000..10e5d616f2b --- /dev/null +++ b/dashboard/src/utils/EntityStatus.ts @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +export enum EntityStatus { + ACTIVE = "ACTIVE", + DELETED = "DELETED" +} diff --git a/dashboard/src/views/DashboardOverview/ClassificationCoverage.tsx b/dashboard/src/views/DashboardOverview/ClassificationCoverage.tsx index 03c27b94dca..faa54da6ae6 100644 --- a/dashboard/src/views/DashboardOverview/ClassificationCoverage.tsx +++ b/dashboard/src/views/DashboardOverview/ClassificationCoverage.tsx @@ -289,7 +289,7 @@ const ClassificationCoverage = memo( aria-label="Open classification search" > {numberFormatWithComma(typesInUse)} of{" "} - {numberFormatWithComma(classificationTypeDefinitions)} + {numberFormatWithComma(classificationTypeDefinitions)}{" "} classification types are in use (have at least one entity). diff --git a/dashboard/src/views/DetailPage/DetailPageAttributes.tsx b/dashboard/src/views/DetailPage/DetailPageAttributes.tsx index 3bbe6fe402f..12cc51154a0 100644 --- a/dashboard/src/views/DetailPage/DetailPageAttributes.tsx +++ b/dashboard/src/views/DetailPage/DetailPageAttributes.tsx @@ -41,6 +41,7 @@ const getDescriptionForDisplay = (desc: unknown): string => { }; import { useState } from "react"; import { useAppSelector } from "@hooks/reducerHook"; +import { EntityStatus } from "@utils/EntityStatus"; import { toast } from "react-toastify"; import EditOutlinedIcon from "@mui/icons-material/EditOutlined"; import { removeClassification } from "@api/apiMethods/classificationApiMethod"; @@ -147,7 +148,7 @@ const DetailPageAttribute = ({ {name}{" "} - {isEmpty(bmguid) && ( + {isEmpty(bmguid) && !loading && data?.status !== EntityStatus.DELETED && ( Classifications - - { - setOpenAddTagModal(true); - }} - > - {" "} - - + {!loading && data?.status !== EntityStatus.DELETED && ( + + { + setOpenAddTagModal(true); + }} + > + {" "} + + + )} Terms - - { - if (!hasAnyGlossaryTerms) { - toast.dismiss(); - toast.info("There are no available terms"); - return; - } - setOpenAddTermModal(true); - }} - > - {" "} - - + {!loading && data?.status !== EntityStatus.DELETED && ( + + { + if (!hasAnyGlossaryTerms) { + toast.dismiss(); + toast.info("There are no available terms"); + return; + } + setOpenAddTermModal(true); + }} + > + {" "} + + + )} { let entityObj = !isEmpty(entityDefObj) && !isEmpty(entity) ? entityDefObj.find((obj: { name: string }) => { - return obj.name == entity.typeName; - }) + return obj.name == entity.typeName; + }) : {}; let superTypes = !isEmpty(entityDefObj) ? getNestedSuperTypes({ - data: entityObj, - collection: entityDefObj - }) + data: entityObj, + collection: entityDefObj + }) : []; let isLineageRender: boolean | null = superTypes.find((type) => { if (type === "DataSet" || type === "Process") { @@ -298,7 +299,7 @@ const EntityDetailPage: React.FC = () => { className="detail-page-paper" variant="outlined" > - {loading ? ( + {loading || detailPageData === null ? ( { }} > - {loading ? ( + {loading || detailPageData === null ? ( { > Classifications - - { - setOpenAddTagModal(true); - }} - > - {" "} - - + {entity?.status !== EntityStatus.DELETED && ( + + { + setOpenAddTagModal(true); + }} + > + {" "} + + + )} { {!entity?.typeName?.includes("AtlasGlossary") && ( - {loading ? ( + {loading || detailPageData === null ? ( { > Terms - - { - if (!hasAnyGlossaryTerms) { - toast.dismiss(); - toast.info("There are no available terms"); - return; - } - setOpenAddTermModal(true); - }} - > - - - + {entity?.status !== EntityStatus.DELETED && ( + + { + if (!hasAnyGlossaryTerms) { + toast.dismiss(); + toast.info("There are no available terms"); + return; + } + setOpenAddTermModal(true); + }} + > + + + + )} { - {entityUpdate && ( + {entityUpdate && !loading && entity?.status !== EntityStatus.DELETED && ( = ({ let values = info.row.original; return ( - {(guid == values?.entityGuid || + {!loading && entity?.status !== EntityStatus.DELETED && (guid == values?.entityGuid || (guid != values?.entityGuid && values.entityStatus == "DELETED")) && ( @@ -279,7 +280,7 @@ const ClassificationsTab: React.FC = ({ )} - {guid == values?.entityGuid && ( + {!loading && entity?.status !== EntityStatus.DELETED && guid == values?.entityGuid && ( = ({ enableSorting: false } ], - [updateTable] + [updateTable, entity] ); return ( diff --git a/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/BMAttributes.tsx b/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/BMAttributes.tsx index 2fb291ebdd4..30c673952e5 100644 --- a/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/BMAttributes.tsx +++ b/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/BMAttributes.tsx @@ -57,6 +57,7 @@ import { toast } from "react-toastify"; import { cloneDeep } from "@utils/Helper"; import moment from "moment-timezone"; import { fetchDetailPageData } from "@redux/slice/detailPageSlice"; +import { EntityStatus } from "@utils/EntityStatus"; const defaultField = { key: null, @@ -376,22 +377,24 @@ const BMAttributes = ({ loading, bmAttributes, entity }: any) => { {addLabel ? ( - void }) => { - e.stopPropagation(); - setExpanded("bmDataPanel"); - setAddLabel(false); - if (!isEmpty(defaultFieldValues)) { - reset({ businessMetadata: defaultFieldValues }); - } - }} - > - {!isEmpty(bmAttributes) ? "Edit" : "Add"} - + !loading && entity?.status !== EntityStatus.DELETED && ( + void }) => { + e.stopPropagation(); + setExpanded("bmDataPanel"); + setAddLabel(false); + if (!isEmpty(defaultFieldValues)) { + reset({ businessMetadata: defaultFieldValues }); + } + }} + > + {!isEmpty(bmAttributes) ? "Edit" : "Add"} + + ) ) : ( <> { justifyContent="center" > - No properties have been created yet. To add a - property, click{" "} - void }) => { - e.stopPropagation(); - setAddLabel(false); - }} - style={{ textDecoration: "underline" }} - > - here - + {entity?.status === EntityStatus.DELETED ? ( + "No properties have been created yet." + ) : ( + <> + No properties have been created yet. To add a + property, click{" "} + void }) => { + e.stopPropagation(); + setAddLabel(false); + }} + style={{ textDecoration: "underline" }} + > + here + + + )} )} ) : ( <> - - { - e.stopPropagation(); - append(defaultField); - }} - startIcon={} - > - Add New Attributes - - + {!loading && entity?.status !== EntityStatus.DELETED && ( + + { + e.stopPropagation(); + append(defaultField); + }} + startIcon={} + > + Add New Attributes + + + )} {fields.map((field, index) => { const keySelected = !isEmpty( bmAttributesValues?.[index]?.key diff --git a/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/Labels.tsx b/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/Labels.tsx index 77b4f21b7cd..d6ed16741b5 100644 --- a/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/Labels.tsx +++ b/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/Labels.tsx @@ -43,10 +43,11 @@ import { useParams } from "react-router-dom"; import { getLabels } from "@api/apiMethods/detailpageApiMethod"; import { useAppDispatch } from "@hooks/reducerHook"; import { fetchDetailPageData } from "@redux/slice/detailPageSlice"; +import { EntityStatus } from "@utils/EntityStatus"; const filter = createFilterOptions(); -const Labels = ({ loading, labels }: any) => { +const Labels = ({ loading, labels, entity }: any) => { const { guid }: any = useParams(); const toastId: any = useRef(null); const dispatchApi = useAppDispatch(); @@ -189,19 +190,21 @@ const Labels = ({ loading, labels }: any) => { {addLabel ? ( - void }) => { - e.stopPropagation(); - setExpanded("labelsPanel"); - setAddLabel(false); - }} - > - {!isEmpty(labels) ? "Edit" : "Add"} - + !loading && entity?.status !== EntityStatus.DELETED && ( + void }) => { + e.stopPropagation(); + setExpanded("labelsPanel"); + setAddLabel(false); + }} + > + {!isEmpty(labels) ? "Edit" : "Add"} + + ) ) : ( <> { }) ) : ( - No labels have been created yet. To add a labels, click{" "} - void }) => { - e.stopPropagation(); - setAddLabel(false); - }} - style={{ textDecoration: "underline" }} - > - here - + {entity?.status === EntityStatus.DELETED ? ( + "No labels have been created yet." + ) : ( + <> + No labels have been created yet. To add a labels, click{" "} + void }) => { + e.stopPropagation(); + setAddLabel(false); + }} + style={{ textDecoration: "underline" }} + > + here + + + )} )} diff --git a/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/PropertiesTab.tsx b/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/PropertiesTab.tsx index 0a473032082..8b8705a9ee5 100644 --- a/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/PropertiesTab.tsx +++ b/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/PropertiesTab.tsx @@ -56,7 +56,7 @@ const PropertiesTab = (props: { customAttributes={customAttributes} entity={entity} /> - + { {addLabel ? ( - void }) => { - e.stopPropagation(); - setExpanded("userDefinedPanel"); - setAddLabel(false); - if (!isEmpty(defaultFieldValues)) { - reset({ customAttributes: defaultFieldValues }); - } - }} - > - {!isEmpty(customAttributes) ? "Edit" : "Add"} - + !loading && entity?.status !== EntityStatus.DELETED && ( + void }) => { + e.stopPropagation(); + setExpanded("userDefinedPanel"); + setAddLabel(false); + if (!isEmpty(defaultFieldValues)) { + reset({ customAttributes: defaultFieldValues }); + } + }} + > + {!isEmpty(customAttributes) ? "Edit" : "Add"} + + ) ) : ( <> { }) ) : ( - No properties have been created yet. To add a - property,click{" "} - void }) => { - e.stopPropagation(); - setAddLabel(false); - }} - style={{ textDecoration: "underline" }} - > - here - + {entity?.status === EntityStatus.DELETED ? ( + "No properties have been created yet." + ) : ( + <> + No properties have been created yet. To add a + property,click{" "} + void }) => { + e.stopPropagation(); + setAddLabel(false); + }} + style={{ textDecoration: "underline" }} + > + here + + + )} )}