mirror of
https://github.com/datahub-project/datahub.git
synced 2025-10-05 05:56:45 +00:00
feat(ui): Add context paths for Data Products (#14802)
This commit is contained in:
parent
04b76b5664
commit
01b3ef27d4
@ -3,6 +3,7 @@ import React from 'react';
|
||||
import { GenericEntityProperties } from '@app/entity/shared/types';
|
||||
import { EntityMenuActions, IconStyleType, PreviewType } from '@app/entityV2/Entity';
|
||||
import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuActions';
|
||||
import { getParentEntities } from '@app/entityV2/shared/containers/profile/header/getParentEntities';
|
||||
import DefaultPreviewCard from '@app/previewV2/DefaultPreviewCard';
|
||||
import { useEntityRegistry } from '@app/useEntityRegistry';
|
||||
|
||||
@ -58,7 +59,7 @@ export const Preview = ({
|
||||
tags={globalTags || undefined}
|
||||
owners={owners}
|
||||
domain={domain}
|
||||
parentEntities={domain ? [domain] : []}
|
||||
parentEntities={data ? getParentEntities(data, EntityType.DataProduct) : []}
|
||||
glossaryTerms={glossaryTerms || undefined}
|
||||
entityCount={entityCount}
|
||||
externalUrl={externalUrl}
|
||||
|
@ -134,7 +134,7 @@ export const DefaultEntityHeader = ({
|
||||
const displayedEntityType = getDisplayedEntityType(entityData, entityRegistry, entityType);
|
||||
const { platform, platforms } = getEntityPlatforms(entityType, entityData);
|
||||
|
||||
const contextPath = getParentEntities(entityData);
|
||||
const contextPath = getParentEntities(entityData, entityType);
|
||||
return (
|
||||
<>
|
||||
<Row>
|
||||
|
@ -2,7 +2,7 @@ import { GenericEntityProperties } from '@app/entity/shared/types';
|
||||
import { getParentEntities } from '@app/entityV2/shared/containers/profile/header/getParentEntities';
|
||||
import { dataPlatform } from '@src/Mocks';
|
||||
|
||||
import { EntityType } from '@types';
|
||||
import { DataProduct, EntityType } from '@types';
|
||||
|
||||
const PARENT_CONTAINERS: GenericEntityProperties['parentContainers'] = {
|
||||
containers: [
|
||||
@ -45,6 +45,20 @@ const PARENT: GenericEntityProperties = {
|
||||
platform: dataPlatform,
|
||||
};
|
||||
|
||||
const dataProduct: DataProduct = {
|
||||
urn: 'urn:li:dataProduct:test',
|
||||
type: EntityType.DataProduct,
|
||||
domain: {
|
||||
associatedUrn: '',
|
||||
domain: {
|
||||
urn: 'urn:li:domain:bebdad41-c523-469f-9b62-de94f938f603',
|
||||
id: 'bebdad41-c523-469f-9b62-de94f938f603',
|
||||
type: EntityType.Domain,
|
||||
parentDomains: PARENT_DOMAINS,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('getContextPath', () => {
|
||||
it('returns empty array by default', () => {
|
||||
const entityData = {};
|
||||
@ -100,4 +114,14 @@ describe('getContextPath', () => {
|
||||
const contextPath = getParentEntities(entityData);
|
||||
expect(contextPath).toEqual([PARENT]);
|
||||
});
|
||||
|
||||
it('returns correct context path for data products', () => {
|
||||
const entityData = dataProduct;
|
||||
|
||||
const contextPath = getParentEntities(entityData, EntityType.DataProduct);
|
||||
expect(contextPath).toEqual([
|
||||
dataProduct.domain?.domain,
|
||||
...(dataProduct.domain?.domain?.parentDomains?.domains || []),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -1,18 +1,40 @@
|
||||
import { GenericEntityProperties } from '@app/entity/shared/types';
|
||||
|
||||
import { Entity } from '@types';
|
||||
import { DataProduct, Entity, EntityType } from '@types';
|
||||
|
||||
type GetContextPathInput = Pick<
|
||||
GenericEntityProperties,
|
||||
'parent' | 'parentContainers' | 'parentDomains' | 'parentNodes'
|
||||
'parent' | 'parentContainers' | 'parentDomains' | 'parentNodes' | 'domain'
|
||||
>;
|
||||
|
||||
export function getParentEntities(entityData: GetContextPathInput | null): Entity[] {
|
||||
const containerPath =
|
||||
entityData?.parentContainers?.containers ||
|
||||
entityData?.parentDomains?.domains ||
|
||||
entityData?.parentNodes?.nodes ||
|
||||
[];
|
||||
const parentPath: Entity[] = entityData?.parent ? [entityData.parent as Entity] : [];
|
||||
return containerPath.length ? containerPath : parentPath;
|
||||
export function getParentEntities(entityData: GetContextPathInput | null, entityType?: EntityType): Entity[] {
|
||||
if (!entityData) return [];
|
||||
|
||||
switch (entityType) {
|
||||
case EntityType.DataProduct: {
|
||||
const domain = (entityData as DataProduct).domain?.domain;
|
||||
return domain ? [domain, ...(domain.parentDomains?.domains || [])] : [];
|
||||
}
|
||||
|
||||
case EntityType.GlossaryTerm:
|
||||
case EntityType.GlossaryNode:
|
||||
return entityData.parentNodes?.nodes || [];
|
||||
|
||||
case EntityType.Domain:
|
||||
return entityData.parentDomains?.domains || [];
|
||||
|
||||
default: {
|
||||
// generic fallback
|
||||
const containerPath =
|
||||
entityData.parentContainers?.containers ||
|
||||
entityData.parentDomains?.domains ||
|
||||
entityData.parentNodes?.nodes ||
|
||||
[];
|
||||
if (containerPath.length) return containerPath;
|
||||
|
||||
if (entityData.parent) return [entityData.parent as Entity];
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,13 @@ import React, { useMemo, useRef, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import analytics, { EntityActionType, EventType } from '@app/analytics';
|
||||
import { IconStyleType } from '@app/entityV2/Entity';
|
||||
import { getParentEntities } from '@app/entityV2/shared/containers/profile/header/getParentEntities';
|
||||
import { handleBatchError } from '@app/entityV2/shared/utils';
|
||||
import { useModulesContext } from '@app/homeV3/module/context/ModulesContext';
|
||||
import ContextPath from '@app/previewV2/ContextPath';
|
||||
import { useEnterKeyListener } from '@app/shared/useEnterKeyListener';
|
||||
import { useEntityRegistry } from '@app/useEntityRegistry';
|
||||
import { Button } from '@src/alchemy-components';
|
||||
import { Button, Text } from '@src/alchemy-components';
|
||||
import { ANTD_GRAY } from '@src/app/entityV2/shared/constants';
|
||||
import { ModalButtonContainer } from '@src/app/shared/button/styledComponents';
|
||||
import { useGetRecommendations } from '@src/app/shared/recommendation';
|
||||
@ -21,14 +22,6 @@ import { useBatchSetDataProductMutation } from '@graphql/dataProduct.generated';
|
||||
import { useGetAutoCompleteMultipleResultsLazyQuery } from '@graphql/search.generated';
|
||||
import { DataHubPageModuleType, DataProduct, Entity, EntityType } from '@types';
|
||||
|
||||
const OptionWrapper = styled.div`
|
||||
padding: 2px 0;
|
||||
|
||||
svg {
|
||||
margin-right: 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
const LoadingWrapper = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@ -179,15 +172,23 @@ export default function SetDataProductModal({
|
||||
value: 'loading',
|
||||
};
|
||||
|
||||
const options = displayedDataProducts.map((result) => ({
|
||||
label: (
|
||||
<OptionWrapper>
|
||||
{entityRegistry.getIcon(EntityType.DataProduct, 12, IconStyleType.ACCENT, 'black')}
|
||||
{entityRegistry.getDisplayName(EntityType.DataProduct, result)}
|
||||
</OptionWrapper>
|
||||
),
|
||||
value: result.urn,
|
||||
}));
|
||||
const options = displayedDataProducts.map((result) => {
|
||||
return {
|
||||
label: (
|
||||
<>
|
||||
<Text size="md">{entityRegistry.getDisplayName(EntityType.DataProduct, result)}</Text>
|
||||
<ContextPath
|
||||
entityType={EntityType.DataProduct}
|
||||
displayedEntityType="Data product"
|
||||
parentEntities={getParentEntities(result as DataProduct, EntityType.DataProduct)}
|
||||
entityTitleWidth={200}
|
||||
numVisible={3}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
value: result.urn,
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Modal
|
||||
|
@ -7,6 +7,7 @@ import EntityTitleLoadingSection from '@app/entityV2/shared/containers/profile/h
|
||||
import EntityName from '@app/entityV2/shared/containers/profile/header/EntityName';
|
||||
import PlatformHeaderIcons from '@app/entityV2/shared/containers/profile/header/PlatformContent/PlatformHeaderIcons';
|
||||
import StructuredPropertyBadge from '@app/entityV2/shared/containers/profile/header/StructuredPropertyBadge';
|
||||
import { getParentEntities } from '@app/entityV2/shared/containers/profile/header/getParentEntities';
|
||||
import { getDisplayedEntityType } from '@app/entityV2/shared/containers/profile/header/utils';
|
||||
import VersioningBadge from '@app/entityV2/shared/versioning/VersioningBadge';
|
||||
import ContextPath from '@app/previewV2/ContextPath';
|
||||
@ -15,7 +16,7 @@ import NotesIcon from '@app/previewV2/NotesIcon';
|
||||
import HorizontalScroller from '@app/sharedV2/carousel/HorizontalScroller';
|
||||
import { useEntityRegistry } from '@app/useEntityRegistry';
|
||||
|
||||
import { DataPlatform, Entity, EntityType, Post } from '@types';
|
||||
import { DataPlatform, EntityType, Post } from '@types';
|
||||
|
||||
const TitleContainer = styled(HorizontalScroller)`
|
||||
display: flex;
|
||||
@ -49,13 +50,7 @@ const SidebarEntityHeader = () => {
|
||||
const platforms =
|
||||
entityType === EntityType.SchemaField ? entityData?.parent?.siblingPlatforms : entityData?.siblingPlatforms;
|
||||
|
||||
const containerPath =
|
||||
entityData?.parentContainers?.containers ||
|
||||
entityData?.parentDomains?.domains ||
|
||||
entityData?.parentNodes?.nodes ||
|
||||
[];
|
||||
const parentPath: Entity[] = entityData?.parent ? [entityData.parent as Entity] : [];
|
||||
const parentEntities = containerPath.length ? containerPath : parentPath;
|
||||
const parentEntities = getParentEntities(entityData, entityType);
|
||||
|
||||
if (loading) {
|
||||
return <EntityTitleLoadingSection />;
|
||||
|
@ -228,6 +228,18 @@ fragment autoCompleteFields on Entity {
|
||||
properties {
|
||||
name
|
||||
}
|
||||
domain {
|
||||
domain {
|
||||
urn
|
||||
type
|
||||
properties {
|
||||
name
|
||||
}
|
||||
parentDomains {
|
||||
...parentDomainsFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on Application {
|
||||
properties {
|
||||
|
Loading…
x
Reference in New Issue
Block a user