Minor: add base class for entity utils (#14651)

* Minor: add base class for entity utils

* test: add unit test for entity util class

* add user and team entity type case
This commit is contained in:
Sachin Chaurasiya 2024-01-10 12:09:19 +05:30 committed by GitHub
parent dcac5c2367
commit 6646641b77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 346 additions and 182 deletions

View File

@ -41,7 +41,6 @@ jest.mock('../../../../utils/CommonUtils', () => ({
}));
jest.mock('../../../../utils/TableUtils', () => ({
getEntityLink: jest.fn(),
getTierTags: jest.fn(),
getTagsWithoutTier: jest.fn(),
}));

View File

@ -28,7 +28,9 @@ import {
getEntityFQN,
getEntityType,
} from '../../../../utils/FeedUtils';
import { getEntityLink } from '../../../../utils/TableUtils';
import { EntityType } from '../../../../enums/entity.enum';
import entityUtilClassBase from '../../../../utils/EntityUtilClassBase';
import UserPopOverCard from '../../../common/PopOverCard/UserPopOverCard';
import './feed-card-header-v1.style.less';
@ -53,6 +55,7 @@ const FeedCardHeaderV1 = ({
const entityFQN = getEntityFQN(entityLink) ?? '';
const entityField = getEntityField(entityLink) ?? '';
const entityCheck = !isUndefined(entityFQN) && !isUndefined(entityType);
const isUserOrTeam = [EntityType.USER, EntityType.TEAM].includes(entityType);
const getFeedLinkElement = entityCheck && (
<span className="font-normal" data-testid="headerText">
@ -64,14 +67,28 @@ const FeedCardHeaderV1 = ({
) : (
<>
<span data-testid="entityType">{entityType} </span>
<EntityPopOverCard entityFQN={entityFQN} entityType={entityType}>
<Link
className="break-all"
data-testid="entitylink"
to={getEntityLink(entityType, entityFQN)}>
<span>{entityDisplayName(entityType, entityFQN)}</span>
</Link>
</EntityPopOverCard>
{isUserOrTeam ? (
<UserPopOverCard
showUserName
showUserProfile={false}
userName={createdBy}>
<Link
className="break-all"
data-testid="entitylink"
to={entityUtilClassBase.getEntityLink(entityType, entityFQN)}>
<span>{entityDisplayName(entityType, entityFQN)}</span>
</Link>
</UserPopOverCard>
) : (
<EntityPopOverCard entityFQN={entityFQN} entityType={entityType}>
<Link
className="break-all"
data-testid="entitylink"
to={entityUtilClassBase.getEntityLink(entityType, entityFQN)}>
<span>{entityDisplayName(entityType, entityFQN)}</span>
</Link>
</EntityPopOverCard>
)}
</>
)}
</span>

View File

@ -18,6 +18,7 @@ import React, { FC } from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import CloseIcon from '../../../components/Modals/CloseIcon.component';
import entityUtilClassBase from '../../../utils/EntityUtilClassBase';
import {
entityDisplayName,
getEntityField,
@ -26,7 +27,6 @@ import {
getEntityType,
getFeedPanelHeaderText,
} from '../../../utils/FeedUtils';
import { getEntityLink } from '../../../utils/TableUtils';
import { FeedPanelHeaderProp } from './ActivityFeedPanel.interface';
const FeedPanelHeader: FC<FeedPanelHeaderProp> = ({
@ -57,7 +57,7 @@ const FeedPanelHeader: FC<FeedPanelHeaderProp> = ({
<Link
className="break-all"
data-testid="entitylink"
to={getEntityLink(entityType, entityFQN)}>
to={entityUtilClassBase.getEntityLink(entityType, entityFQN)}>
<span>{entityDisplayName(entityType, entityFQN)}</span>
</Link>
)}

View File

@ -58,10 +58,6 @@ jest.mock('../../../utils/TasksUtils', () => ({
getTaskDetailPath: jest.fn().mockReturnValue('/'),
}));
jest.mock('../../../utils/TableUtils', () => ({
getEntityLink: jest.fn().mockReturnValue('/'),
}));
jest.mock('../../../utils/FeedUtils', () => ({
getEntityFQN: jest.fn().mockReturnValue('entityFQN'),
getEntityType: jest.fn().mockReturnValue('entityType'),

View File

@ -35,7 +35,8 @@ import {
} from '../../../utils/date-time/DateTimeUtils';
import EntityLink from '../../../utils/EntityLink';
import { getEntityFQN, getEntityType } from '../../../utils/FeedUtils';
import { getEntityLink } from '../../../utils/TableUtils';
import entityUtilClassBase from '../../../utils/EntityUtilClassBase';
import { getTaskDetailPath } from '../../../utils/TasksUtils';
import ProfilePicture from '../../common/ProfilePicture/ProfilePicture';
import { useActivityFeedProvider } from '../ActivityFeedProvider/ActivityFeedProvider';
@ -123,7 +124,7 @@ const TaskFeedCard = ({
<Link
className="break-all"
data-testid="entity-link"
to={getEntityLink(entityType, entityFQN)}
to={entityUtilClassBase.getEntityLink(entityType, entityFQN)}
onClick={(e) => e.stopPropagation()}>
{getNameFromFQN(entityFQN)}
</Link>

View File

@ -25,9 +25,9 @@ import { CSMode } from '../../../enums/codemirror.enum';
import { EntityType } from '../../../enums/entity.enum';
import { getNameFromFQN } from '../../../utils/CommonUtils';
import { getLineageDetailsObject } from '../../../utils/EntityLineageUtils';
import entityUtilClassBase from '../../../utils/EntityUtilClassBase';
import { getEntityName } from '../../../utils/EntityUtils';
import { getEncodedFqn } from '../../../utils/StringsUtils';
import { getEntityLink } from '../../../utils/TableUtils';
import Loader from '../../Loader/Loader';
import { ModalWithQueryEditor } from '../../Modals/ModalWithQueryEditor/ModalWithQueryEditor';
import SchemaEditor from '../../SchemaEditor/SchemaEditor';
@ -75,7 +75,7 @@ const EdgeInfoDrawer = ({
value: sourceData && getEntityName(sourceData?.data?.node),
link:
sourceData &&
getEntityLink(
entityUtilClassBase.getEntityLink(
data.sourceType,
sourceData.data.node.fullyQualifiedName
),
@ -89,7 +89,7 @@ const EdgeInfoDrawer = ({
value: targetData ? getEntityName(targetData?.data?.node) : undefined,
link:
targetData &&
getEntityLink(
entityUtilClassBase.getEntityLink(
data.targetData,
targetData.data.node.fullyQualifiedName
),
@ -105,7 +105,7 @@ const EdgeInfoDrawer = ({
: undefined,
link:
data?.edge?.pipeline &&
getEntityLink(
entityUtilClassBase.getEntityLink(
data?.edge?.pipeline.type,
getEncodedFqn(data?.edge?.pipeline.fullyQualifiedName)
),

View File

@ -16,8 +16,9 @@ import { isEmpty } from 'lodash';
import React, { FunctionComponent } from 'react';
import { Link } from 'react-router-dom';
import { EntityReference } from '../../../generated/entity/type';
import entityUtilClassBase from '../../../utils/EntityUtilClassBase';
import { getEntityName } from '../../../utils/EntityUtils';
import { getEntityIcon, getEntityLink } from '../../../utils/TableUtils';
import { getEntityIcon } from '../../../utils/TableUtils';
import EntityListSkeleton from '../../Skeleton/MyData/EntityListSkeleton/EntityListSkeleton.component';
import './entity.less';
@ -68,7 +69,7 @@ export const EntityListWithV1: FunctionComponent<AntdEntityListProp> = ({
<div className="flex items-center">
<Link
className="font-medium"
to={getEntityLink(
to={entityUtilClassBase.getEntityLink(
item.type || '',
item.fullyQualifiedName ?? ''
)}>

View File

@ -18,7 +18,7 @@ import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import { EntityType } from '../../enums/entity.enum';
import { MlFeature } from '../../generated/entity/data/mlmodel';
import { getEntityLink } from '../../utils/TableUtils';
import entityUtilClassBase from '../../utils/EntityUtilClassBase';
import './source-list.less';
const SourceList = ({ feature }: { feature: MlFeature }) => {
@ -77,7 +77,7 @@ const SourceList = ({ feature }: { feature: MlFeature }) => {
</Col>
<Col flex="auto">
<Link
to={getEntityLink(
to={entityUtilClassBase.getEntityLink(
EntityType.TABLE,
source.dataSource?.fullyQualifiedName ||
source.dataSource?.name ||

View File

@ -28,8 +28,9 @@ import { SearchIndex } from '../../../enums/search.enum';
import { WidgetCommonProps } from '../../../pages/CustomizablePage/CustomizablePage.interface';
import { searchData } from '../../../rest/miscAPI';
import { Transi18next } from '../../../utils/CommonUtils';
import entityUtilClassBase from '../../../utils/EntityUtilClassBase';
import { getEntityName } from '../../../utils/EntityUtils';
import { getEntityIcon, getEntityLink } from '../../../utils/TableUtils';
import { getEntityIcon } from '../../../utils/TableUtils';
import { useAuthContext } from '../../Auth/AuthProviders/AuthProvider';
import ErrorPlaceHolder from '../../common/ErrorWithPlaceholder/ErrorPlaceHolder';
import { SourceType } from '../../SearchedData/SearchedData.interface';
@ -163,7 +164,7 @@ const MyDataWidgetInternal = ({
<div className="d-flex items-center">
<Link
className=""
to={getEntityLink(
to={entityUtilClassBase.getEntityLink(
item.entityType ?? '',
item.fullyQualifiedName as string
)}>

View File

@ -64,7 +64,6 @@ jest.mock('../../../utils/EntityUtils', () => ({
}));
jest.mock('../../../utils/TableUtils', () => ({
getEntityLink: jest.fn().mockImplementation((link) => link),
getEntityIcon: jest.fn().mockImplementation((obj) => obj.name),
}));

View File

@ -88,10 +88,6 @@ jest.mock('../../../utils/FeedUtils', () => ({
getEntityFQN: jest.fn().mockReturnValue('getEntityFQN'),
}));
jest.mock('../../../utils/TableUtils', () => ({
getEntityLink: jest.fn().mockReturnValue('getEntityLink'),
}));
jest.mock('../../../utils/TasksUtils', () => ({
fetchOptions: jest.fn().mockReturnValue('getEntityLink'),
getTaskDetailPath: jest.fn().mockReturnValue('/'),

View File

@ -76,10 +76,10 @@ import { updateTask, updateThread } from '../../../rest/feedsAPI';
import { postTestCaseIncidentStatus } from '../../../rest/incidentManagerAPI';
import { getNameFromFQN } from '../../../utils/CommonUtils';
import EntityLink from '../../../utils/EntityLink';
import entityUtilClassBase from '../../../utils/EntityUtilClassBase';
import { getEntityName } from '../../../utils/EntityUtils';
import { getEntityFQN } from '../../../utils/FeedUtils';
import { checkPermission } from '../../../utils/PermissionsUtils';
import { getEntityLink } from '../../../utils/TableUtils';
import {
fetchOptions,
getTaskDetailPath,
@ -202,7 +202,7 @@ export const TaskTab = ({
<Link
className="break-all p-r-xss"
data-testid="entitylink"
to={getEntityLink(entityType, entityFQN)}
to={entityUtilClassBase.getEntityLink(entityType, entityFQN)}
onClick={(e) => e.stopPropagation()}>
<Typography.Text className="text-md font-medium text-color-inherit">
{' '}

View File

@ -25,8 +25,9 @@ import {
getRecentlyViewedData,
prepareLabel,
} from '../../../utils/CommonUtils';
import entityUtilClassBase from '../../../utils/EntityUtilClassBase';
import { getEntityName } from '../../../utils/EntityUtils';
import { getEntityIcon, getEntityLink } from '../../../utils/TableUtils';
import { getEntityIcon } from '../../../utils/TableUtils';
import ErrorPlaceHolder from '../../common/ErrorWithPlaceholder/ErrorPlaceHolder';
import EntityListSkeleton from '../../Skeleton/MyData/EntityListSkeleton/EntityListSkeleton.component';
import './recently-viewed.less';
@ -126,7 +127,7 @@ const RecentlyViewed = ({
<div className=" flex items-center">
<Link
className=""
to={getEntityLink(
to={entityUtilClassBase.getEntityLink(
item.type || '',
item.fullyQualifiedName as string
)}>

View File

@ -17,7 +17,6 @@ import { MemoryRouter } from 'react-router-dom';
import TableDataCardV2 from './TableDataCardV2';
jest.mock('../../../utils/TableUtils', () => ({
getEntityLink: jest.fn().mockReturnValue('EntityLink'),
getServiceIcon: jest.fn(),
getEntityIcon: jest.fn().mockReturnValue(<p>icon</p>),
getUsagePercentile: jest

View File

@ -29,7 +29,6 @@ import { EntityType } from '../../enums/entity.enum';
import { DatabaseSchema } from '../../generated/entity/data/databaseSchema';
import { Table } from '../../generated/entity/data/table';
import { getEntityName } from '../../utils/EntityUtils';
import { getEntityLink } from '../../utils/TableUtils';
interface SchemaTablesTabProps {
databaseSchemaDetails: DatabaseSchema;
@ -81,10 +80,7 @@ function SchemaTablesTab({
<Link
className="break-word"
data-testid="table-name-link"
to={getEntityLink(
EntityType.TABLE,
record.fullyQualifiedName as string
)}>
to={(EntityType.TABLE, record.fullyQualifiedName as string)}>
{getEntityName(record)}
</Link>
</div>

View File

@ -60,7 +60,6 @@ jest.mock('../../utils/StringsUtils', () => ({
}));
jest.mock('../../utils/TableUtils', () => ({
getEntityLink: jest.fn().mockImplementation((link) => link),
getTableExpandableConfig: jest.fn(),
}));

View File

@ -28,9 +28,9 @@ import { Paging } from '../../generated/type/paging';
import { usePaging } from '../../hooks/paging/usePaging';
import { ServicePageData } from '../../pages/ServiceDetailsPage/ServiceDetailsPage';
import { getStoredProceduresList } from '../../rest/storedProceduresAPI';
import entityUtilClassBase from '../../utils/EntityUtilClassBase';
import { getEntityName } from '../../utils/EntityUtils';
import { getDecodedFqn } from '../../utils/StringsUtils';
import { getEntityLink } from '../../utils/TableUtils';
import { showErrorToast } from '../../utils/ToastUtils';
const StoredProcedureTab = () => {
@ -101,7 +101,7 @@ const StoredProcedureTab = () => {
<div className="d-inline-flex w-max-90">
<Link
className="break-word"
to={getEntityLink(
to={entityUtilClassBase.getEntityLink(
EntityType.STORED_PROCEDURE,
record.fullyQualifiedName ?? ''
)}>

View File

@ -20,7 +20,8 @@ import { SUPPORTED_TABLE_CONSTRAINTS } from '../../../constants/Table.constants'
import { EntityType, FqnPart } from '../../../enums/entity.enum';
import { ConstraintType, Table } from '../../../generated/entity/data/table';
import { getPartialNameFromTableFQN } from '../../../utils/CommonUtils';
import { getEntityLink } from '../../../utils/TableUtils';
import entityUtilClassBase from '../../../utils/EntityUtilClassBase';
import ForeignKeyConstraint from './ForeignKeyConstraint';
import PrimaryKeyConstraint from './PrimaryKeyConstraint';
import './table-constraints.less';
@ -96,7 +97,7 @@ const TableConstraints: FC<TableConstraintsProps> = ({ constraints }) => {
trigger="hover">
<Link
className="no-underline"
to={getEntityLink(
to={entityUtilClassBase.getEntityLink(
EntityType.TABLE,
getPartialNameFromTableFQN(
referredColumn,

View File

@ -73,8 +73,8 @@ import {
getPartialNameFromTableFQN,
prepareLabel,
} from './CommonUtils';
import entityUtilClassBase from './EntityUtilClassBase';
import { getDecodedFqn } from './StringsUtils';
import { getEntityLink } from './TableUtils';
import { showErrorToast } from './ToastUtils';
export const MAX_LINEAGE_LENGTH = 20;
@ -100,7 +100,7 @@ export const getHeaderLabel = (
className="m-b-0 text-base"
level={5}
title={name || prepareLabel(type, fqn, false)}>
<Link className="" to={getEntityLink(type, fqn)}>
<Link className="" to={entityUtilClassBase.getEntityLink(type, fqn)}>
<Button
className="text-base font-semibold p-0"
data-testid="link-button"

View File

@ -0,0 +1,126 @@
/*
* Copyright 2024 Collate.
* Licensed 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.
*/
import {
getDashboardDetailsPath,
getDatabaseDetailsPath,
getDatabaseSchemaDetailsPath,
getPipelineDetailsPath,
getTableDetailsPath,
getTopicDetailsPath,
} from '../constants/constants';
import { EntityType } from '../enums/entity.enum';
import { SearchIndex } from '../enums/search.enum';
import { EntityUtilClassBase } from './EntityUtilClassBase';
import { getGlossaryPath } from './RouterUtils';
jest.mock('../constants/constants', () => ({
getContainerDetailPath: jest.fn(),
getDashboardDetailsPath: jest.fn(),
getDatabaseDetailsPath: jest.fn(),
getDatabaseSchemaDetailsPath: jest.fn(),
getDataModelDetailsPath: jest.fn(),
getEditWebhookPath: jest.fn(),
getMlModelPath: jest.fn(),
getPipelineDetailsPath: jest.fn(),
getServiceDetailsPath: jest.fn(),
getStoredProcedureDetailPath: jest.fn(),
getTableDetailsPath: jest.fn(),
getTableTabPath: jest.fn(),
getTagsDetailsPath: jest.fn(),
getTopicDetailsPath: jest.fn(),
getUserPath: jest.fn(),
}));
jest.mock('./CommonUtils', () => ({
getTableFQNFromColumnFQN: jest.fn(),
}));
jest.mock('./RouterUtils', () => ({
getDataProductsDetailsPath: jest.fn(),
getDomainDetailsPath: jest.fn(),
getGlossaryPath: jest.fn(),
getSettingPath: jest.fn(),
getTeamsWithFqnPath: jest.fn(),
}));
jest.mock('./SearchIndexUtils', () => ({
getSearchIndexDetailsPath: jest.fn(),
}));
jest.mock('./StringsUtils', () => ({
getDecodedFqn: jest.fn().mockImplementation((fqn: string) => fqn),
}));
describe('EntityUtilClassBase', () => {
let entityUtil: EntityUtilClassBase;
beforeEach(() => {
entityUtil = new EntityUtilClassBase();
});
it('should return topic details path for topic index type', () => {
const fqn = 'test.topic';
entityUtil.getEntityLink(SearchIndex.TOPIC, fqn);
expect(getTopicDetailsPath).toHaveBeenCalledWith(fqn);
});
it('should return dashboard details path for dashboard index type', () => {
const fqn = 'test.dashboard';
entityUtil.getEntityLink(SearchIndex.DASHBOARD, fqn);
expect(getDashboardDetailsPath).toHaveBeenCalledWith(fqn);
});
it('should return pipeline details path for pipeline index type', () => {
const fqn = 'test.pipeline';
entityUtil.getEntityLink(SearchIndex.PIPELINE, fqn);
expect(getPipelineDetailsPath).toHaveBeenCalledWith(fqn);
});
it('Should return database details path for database EntityType', () => {
const fqn = 'test.database';
entityUtil.getEntityLink(EntityType.DATABASE, fqn);
expect(getDatabaseDetailsPath).toHaveBeenCalledWith(fqn);
});
it('Should return database schema details path for database EntityType', () => {
const fqn = 'test.database.schema';
entityUtil.getEntityLink(EntityType.DATABASE_SCHEMA, fqn);
expect(getDatabaseSchemaDetailsPath).toHaveBeenCalledWith(fqn);
});
it('Should return glossary details path for database EntityType', () => {
const fqn = 'testingGlossary';
entityUtil.getEntityLink(EntityType.GLOSSARY, fqn);
expect(getGlossaryPath).toHaveBeenCalledWith(fqn);
});
it('should return table details path for table index type', () => {
const fqn = 'test.table';
entityUtil.getEntityLink(SearchIndex.TABLE, fqn);
expect(getTableDetailsPath).toHaveBeenCalledWith(fqn);
});
it('should return table details path for default case', () => {
const fqn = 'test.default';
entityUtil.getEntityLink('default', fqn);
expect(getTableDetailsPath).toHaveBeenCalledWith(fqn);
});
});

View File

@ -0,0 +1,147 @@
/*
* Copyright 2024 Collate.
* Licensed 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.
*/
import {
getContainerDetailPath,
getDashboardDetailsPath,
getDatabaseDetailsPath,
getDatabaseSchemaDetailsPath,
getDataModelDetailsPath,
getEditWebhookPath,
getMlModelPath,
getPipelineDetailsPath,
getServiceDetailsPath,
getStoredProcedureDetailPath,
getTableDetailsPath,
getTableTabPath,
getTagsDetailsPath,
getTopicDetailsPath,
getUserPath,
} from '../constants/constants';
import { GlobalSettingsMenuCategory } from '../constants/GlobalSettings.constants';
import { EntityTabs, EntityType } from '../enums/entity.enum';
import { SearchIndex } from '../enums/search.enum';
import { getTableFQNFromColumnFQN } from './CommonUtils';
import {
getDataProductsDetailsPath,
getDomainDetailsPath,
getGlossaryPath,
getSettingPath,
getTeamsWithFqnPath,
} from './RouterUtils';
import { getSearchIndexDetailsPath } from './SearchIndexUtils';
import { getDecodedFqn } from './StringsUtils';
class EntityUtilClassBase {
public getEntityLink(indexType: string, fullyQualifiedName: string) {
// encode the FQN for entities that can have "/" in their names
fullyQualifiedName = encodeURIComponent(fullyQualifiedName);
switch (indexType) {
case SearchIndex.TOPIC:
case EntityType.TOPIC:
return getTopicDetailsPath(getDecodedFqn(fullyQualifiedName));
case SearchIndex.DASHBOARD:
case EntityType.DASHBOARD:
return getDashboardDetailsPath(getDecodedFqn(fullyQualifiedName));
case SearchIndex.PIPELINE:
case EntityType.PIPELINE:
return getPipelineDetailsPath(getDecodedFqn(fullyQualifiedName));
case EntityType.DATABASE:
return getDatabaseDetailsPath(getDecodedFqn(fullyQualifiedName));
case EntityType.DATABASE_SCHEMA:
return getDatabaseSchemaDetailsPath(getDecodedFqn(fullyQualifiedName));
case EntityType.GLOSSARY:
case EntityType.GLOSSARY_TERM:
case SearchIndex.GLOSSARY:
return getGlossaryPath(getDecodedFqn(fullyQualifiedName));
case EntityType.DATABASE_SERVICE:
case EntityType.DASHBOARD_SERVICE:
case EntityType.MESSAGING_SERVICE:
case EntityType.PIPELINE_SERVICE:
case EntityType.MLMODEL_SERVICE:
case EntityType.METADATA_SERVICE:
case EntityType.STORAGE_SERVICE:
case EntityType.SEARCH_SERVICE:
return getServiceDetailsPath(fullyQualifiedName, `${indexType}s`);
case EntityType.WEBHOOK:
return getEditWebhookPath(fullyQualifiedName);
case EntityType.TYPE:
return getSettingPath(
GlobalSettingsMenuCategory.CUSTOM_ATTRIBUTES,
`${fullyQualifiedName}s`
);
case EntityType.MLMODEL:
case SearchIndex.MLMODEL:
return getMlModelPath(fullyQualifiedName);
case EntityType.CONTAINER:
case SearchIndex.CONTAINER:
return getContainerDetailPath(getDecodedFqn(fullyQualifiedName));
case SearchIndex.TAG:
return getTagsDetailsPath(fullyQualifiedName);
case SearchIndex.DASHBOARD_DATA_MODEL:
case EntityType.DASHBOARD_DATA_MODEL:
return getDataModelDetailsPath(getDecodedFqn(fullyQualifiedName));
case SearchIndex.STORED_PROCEDURE:
case EntityType.STORED_PROCEDURE:
return getStoredProcedureDetailPath(getDecodedFqn(fullyQualifiedName));
case EntityType.TEST_CASE:
return `${getTableTabPath(
getTableFQNFromColumnFQN(fullyQualifiedName),
EntityTabs.PROFILER
)}?activeTab=Data Quality`;
case EntityType.SEARCH_INDEX:
case SearchIndex.SEARCH_INDEX:
return getSearchIndexDetailsPath(fullyQualifiedName);
case EntityType.DOMAIN:
case SearchIndex.DOMAIN:
return getDomainDetailsPath(fullyQualifiedName);
case EntityType.DATA_PRODUCT:
case SearchIndex.DATA_PRODUCT:
return getDataProductsDetailsPath(fullyQualifiedName);
case EntityType.USER:
case SearchIndex.USER:
return getUserPath(fullyQualifiedName);
case EntityType.TEAM:
case SearchIndex.TEAM:
return getTeamsWithFqnPath(fullyQualifiedName);
case SearchIndex.TABLE:
case EntityType.TABLE:
default:
return getTableDetailsPath(getDecodedFqn(fullyQualifiedName));
}
}
}
const entityUtilClassBase = new EntityUtilClassBase();
export default entityUtilClassBase;
export { EntityUtilClassBase };

View File

@ -99,10 +99,6 @@ jest.mock('./StringsUtils', () => ({
getEncodedFqn: jest.fn().mockImplementation((fqn) => fqn),
}));
jest.mock('./TableUtils', () => ({
getEntityLink: jest.fn(),
}));
jest.mock('./FeedUtils', () => ({
...jest.requireActual('./FeedUtils'),
getEntityField: jest.fn().mockReturnValue('entityField'),

View File

@ -68,6 +68,7 @@ import {
} from './CommonUtils';
import { getRelativeCalendar } from './date-time/DateTimeUtils';
import EntityLink from './EntityLink';
import entityUtilClassBase from './EntityUtilClassBase';
import { ENTITY_LINK_SEPARATOR, getEntityBreadcrumbs } from './EntityUtils';
import Fqn from './Fqn';
import {
@ -75,7 +76,6 @@ import {
ImageQuality,
} from './ProfilerUtils';
import { getEncodedFqn } from './StringsUtils';
import { getEntityLink } from './TableUtils';
import { showErrorToast } from './ToastUtils';
export const getEntityType = (entityLink: string) => {
@ -561,7 +561,7 @@ export const prepareFeedLink = (entityType: string, entityFQN: string) => {
EntityType.TYPE,
];
const entityLink = getEntityLink(entityType, entityFQN);
const entityLink = entityUtilClassBase.getEntityLink(entityType, entityFQN);
if (!withoutFeedEntities.includes(entityType as EntityType)) {
return `${entityLink}/${TabSpecificField.ACTIVITY_FEED}`;
@ -602,7 +602,7 @@ export const entityDisplayName = (entityType: string, entityFQN: string) => {
) {
displayName = entityFQN.split(FQN_SEPARATOR_CHAR).pop();
} else {
displayName = getPartialNameFromFQN(entityFQN, ['database']);
displayName = getPartialNameFromFQN(entityFQN, ['database']) || entityFQN;
}
// Remove quotes if the name is wrapped in quotes

View File

@ -52,9 +52,9 @@ import {
replaceAllSpacialCharWith_,
} from './CommonUtils';
import { getDashboardURL } from './DashboardServiceUtils';
import entityUtilClassBase from './EntityUtilClassBase';
import { getBrokers } from './MessagingServiceUtils';
import { getEncodedFqn } from './StringsUtils';
import { getEntityLink } from './TableUtils';
import { showErrorToast } from './ToastUtils';
export const getFormattedGuideText = (
@ -456,22 +456,22 @@ export const getEntityTypeFromServiceCategory = (
export const getLinkForFqn = (serviceCategory: ServiceTypes, fqn: string) => {
switch (serviceCategory) {
case ServiceCategory.MESSAGING_SERVICES:
return getEntityLink(SearchIndex.TOPIC, fqn);
return entityUtilClassBase.getEntityLink(SearchIndex.TOPIC, fqn);
case ServiceCategory.DASHBOARD_SERVICES:
return getEntityLink(SearchIndex.DASHBOARD, fqn);
return entityUtilClassBase.getEntityLink(SearchIndex.DASHBOARD, fqn);
case ServiceCategory.PIPELINE_SERVICES:
return getEntityLink(SearchIndex.PIPELINE, fqn);
return entityUtilClassBase.getEntityLink(SearchIndex.PIPELINE, fqn);
case ServiceCategory.ML_MODEL_SERVICES:
return getEntityLink(SearchIndex.MLMODEL, fqn);
return entityUtilClassBase.getEntityLink(SearchIndex.MLMODEL, fqn);
case ServiceCategory.STORAGE_SERVICES:
return getEntityLink(EntityType.CONTAINER, fqn);
return entityUtilClassBase.getEntityLink(EntityType.CONTAINER, fqn);
case ServiceCategory.SEARCH_SERVICES:
return getEntityLink(EntityType.SEARCH_INDEX, fqn);
return entityUtilClassBase.getEntityLink(EntityType.SEARCH_INDEX, fqn);
case ServiceCategory.DATABASE_SERVICES:
default:

View File

@ -56,25 +56,10 @@ import { SourceType } from '../components/SearchedData/SearchedData.interface';
import { FQN_SEPARATOR_CHAR } from '../constants/char.constants';
import {
DE_ACTIVE_COLOR,
getContainerDetailPath,
getDashboardDetailsPath,
getDatabaseDetailsPath,
getDatabaseSchemaDetailsPath,
getDataModelDetailsPath,
getEditWebhookPath,
getMlModelPath,
getPipelineDetailsPath,
getServiceDetailsPath,
getStoredProcedureDetailPath,
getTableDetailsPath,
getTableTabPath,
getTagsDetailsPath,
getTopicDetailsPath,
PRIMERY_COLOR,
TEXT_BODY_COLOR,
} from '../constants/constants';
import { GlobalSettingsMenuCategory } from '../constants/GlobalSettings.constants';
import { EntityTabs, EntityType, FqnPart } from '../enums/entity.enum';
import { EntityType, FqnPart } from '../enums/entity.enum';
import { SearchIndex } from '../enums/search.enum';
import { ConstraintTypes, PrimaryTableDataTypes } from '../enums/table.enum';
import { SearchIndexField } from '../generated/entity/data/searchIndex';
@ -90,15 +75,8 @@ import {
getTableFQNFromColumnFQN,
sortTagsCaseInsensitive,
} from './CommonUtils';
import {
getDataProductsDetailsPath,
getDomainDetailsPath,
getGlossaryPath,
getSettingPath,
} from './RouterUtils';
import { getSearchIndexDetailsPath } from './SearchIndexUtils';
import serviceUtilClassBase from './ServiceUtilClassBase';
import { getDecodedFqn, ordinalize } from './StringsUtils';
import { ordinalize } from './StringsUtils';
import { TableFieldsInfoCommonEntities } from './TableUtils.interface';
export const getUsagePercentile = (pctRank: number, isLiteral = false) => {
@ -210,98 +188,6 @@ export const getConstraintIcon = ({
);
};
export const getEntityLink = (
indexType: string,
fullyQualifiedName: string
) => {
// encode the FQN for entities that can have "/" in their names
fullyQualifiedName = encodeURIComponent(fullyQualifiedName);
switch (indexType) {
case SearchIndex.TOPIC:
case EntityType.TOPIC:
return getTopicDetailsPath(getDecodedFqn(fullyQualifiedName));
case SearchIndex.DASHBOARD:
case EntityType.DASHBOARD:
return getDashboardDetailsPath(getDecodedFqn(fullyQualifiedName));
case SearchIndex.PIPELINE:
case EntityType.PIPELINE:
return getPipelineDetailsPath(getDecodedFqn(fullyQualifiedName));
case EntityType.DATABASE:
return getDatabaseDetailsPath(getDecodedFqn(fullyQualifiedName));
case EntityType.DATABASE_SCHEMA:
return getDatabaseSchemaDetailsPath(getDecodedFqn(fullyQualifiedName));
case EntityType.GLOSSARY:
case EntityType.GLOSSARY_TERM:
case SearchIndex.GLOSSARY:
return getGlossaryPath(getDecodedFqn(fullyQualifiedName));
case EntityType.DATABASE_SERVICE:
case EntityType.DASHBOARD_SERVICE:
case EntityType.MESSAGING_SERVICE:
case EntityType.PIPELINE_SERVICE:
case EntityType.MLMODEL_SERVICE:
case EntityType.METADATA_SERVICE:
case EntityType.STORAGE_SERVICE:
case EntityType.SEARCH_SERVICE:
return getServiceDetailsPath(fullyQualifiedName, `${indexType}s`);
case EntityType.WEBHOOK:
return getEditWebhookPath(fullyQualifiedName);
case EntityType.TYPE:
return getSettingPath(
GlobalSettingsMenuCategory.CUSTOM_ATTRIBUTES,
`${fullyQualifiedName}s`
);
case EntityType.MLMODEL:
case SearchIndex.MLMODEL:
return getMlModelPath(fullyQualifiedName);
case EntityType.CONTAINER:
case SearchIndex.CONTAINER:
return getContainerDetailPath(getDecodedFqn(fullyQualifiedName));
case SearchIndex.TAG:
return getTagsDetailsPath(fullyQualifiedName);
case SearchIndex.DASHBOARD_DATA_MODEL:
case EntityType.DASHBOARD_DATA_MODEL:
return getDataModelDetailsPath(getDecodedFqn(fullyQualifiedName));
case SearchIndex.STORED_PROCEDURE:
case EntityType.STORED_PROCEDURE:
return getStoredProcedureDetailPath(getDecodedFqn(fullyQualifiedName));
case EntityType.TEST_CASE:
return `${getTableTabPath(
getTableFQNFromColumnFQN(fullyQualifiedName),
EntityTabs.PROFILER
)}?activeTab=Data Quality`;
case EntityType.SEARCH_INDEX:
case SearchIndex.SEARCH_INDEX:
return getSearchIndexDetailsPath(fullyQualifiedName);
case EntityType.DOMAIN:
case SearchIndex.DOMAIN:
return getDomainDetailsPath(fullyQualifiedName);
case EntityType.DATA_PRODUCT:
case SearchIndex.DATA_PRODUCT:
return getDataProductsDetailsPath(fullyQualifiedName);
case SearchIndex.TABLE:
case EntityType.TABLE:
default:
return getTableDetailsPath(getDecodedFqn(fullyQualifiedName));
}
};
export const getServiceIcon = (source: SourceType) => {
if (source.entityType === EntityType.GLOSSARY_TERM) {
return (

View File

@ -76,6 +76,7 @@ import { DatabaseFields } from './Database/Database.util';
import { defaultFields as DatabaseSchemaFields } from './DatabaseSchemaDetailsUtils';
import { defaultFields as DataModelFields } from './DataModelsUtils';
import { defaultFields as TableFields } from './DatasetDetailsUtils';
import entityUtilClassBase from './EntityUtilClassBase';
import { getEntityName } from './EntityUtils';
import { getEntityFQN, getEntityType } from './FeedUtils';
import { getGlossaryBreadcrumbs } from './GlossaryUtils';
@ -84,7 +85,6 @@ import { defaultFields as PipelineFields } from './PipelineDetailsUtils';
import serviceUtilClassBase from './ServiceUtilClassBase';
import { STORED_PROCEDURE_DEFAULT_FIELDS } from './StoredProceduresUtils';
import { getDecodedFqn, getEncodedFqn } from './StringsUtils';
import { getEntityLink } from './TableUtils';
import { showErrorToast } from './ToastUtils';
export const getRequestDescriptionPath = (
@ -299,7 +299,10 @@ export const getBreadCrumbList = (
) => {
const activeEntity = {
name: getEntityName(entityData),
url: getEntityLink(entityType, entityData.fullyQualifiedName || ''),
url: entityUtilClassBase.getEntityLink(
entityType,
entityData.fullyQualifiedName || ''
),
};
const database = {