Skip to content

Commit a1a20b2

Browse files
authored
feat(ui/lineageV2): Show version pill in lineage sidebar and node (#12599)
1 parent 6531f0d commit a1a20b2

File tree

17 files changed

+116
-33
lines changed

17 files changed

+116
-33
lines changed

datahub-web-react/src/alchemy-components/components/Pills/Pill.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export function Pill({
4545
onPillClick,
4646
customStyle,
4747
customIconRenderer,
48+
className,
4849
}: PillProps) {
4950
if (!SUPPORTED_CONFIGURATIONS[variant].includes(color)) {
5051
console.debug(`Unsupported configuration for Pill: variant=${variant}, color=${color}`);
@@ -62,6 +63,7 @@ export function Pill({
6263
style={{
6364
backgroundColor: customStyle?.backgroundColor,
6465
}}
66+
className={className}
6567
>
6668
{customIconRenderer
6769
? customIconRenderer()

datahub-web-react/src/alchemy-components/components/Pills/components.ts

-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,4 @@ export const PillText = styled.span({
3030
whiteSpace: 'nowrap',
3131
overflow: 'hidden',
3232
textOverflow: 'ellipsis',
33-
fontSize: '12px',
34-
fontWeight: 400,
3533
});

datahub-web-react/src/alchemy-components/components/Pills/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export interface PillProps extends Partial<PillPropsDefaults>, Omit<HTMLAttribut
1818
onClickRightIcon?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;
1919
onClickLeftIcon?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;
2020
onPillClick?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;
21+
className?: string;
2122
}
2223

2324
export type PillStyleProps = PillPropsDefaults & Pick<PillProps, 'color'>;

datahub-web-react/src/alchemy-components/components/Pills/utils.ts

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ const getPillFontStyles = (variant: PillVariantOptions, size: SizeOptions): CSSO
7979
md: { fontSize: getFontSize(size), lineHeight: '24px' },
8080
lg: { fontSize: getFontSize(size), lineHeight: '30px' },
8181
xl: { fontSize: getFontSize(size), lineHeight: '34px' },
82+
inherit: { fontSize: 'inherit', lineHeight: 'inherit' },
8283
};
8384

8485
const variantOverrides: Partial<Record<PillVariantOptions, CSSObject>> = {

datahub-web-react/src/alchemy-components/theme/config/types.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export enum SizeValues {
55
md = 'md',
66
lg = 'lg',
77
xl = 'xl',
8+
inherit = 'inherit',
89
}
910
export type SizeOptions = keyof typeof SizeValues;
1011
export function getSizeName(size: SizeOptions): string {
@@ -73,8 +74,9 @@ export enum FontSizeValues {
7374
'2xl' = '2xl',
7475
'3xl' = '3xl',
7576
'4xl' = '4xl',
77+
inherit = 'inherit',
7678
}
77-
export type FontSizeOptions = keyof typeof FontSizeValues;
79+
export type FontSizeOptions = keyof typeof SizeValues | keyof typeof FontSizeValues;
7880
export type FontWeightOptions = 'normal' | 'medium' | 'semiBold' | 'bold';
7981
export type FontColorOptions = MiscColorOptions | ColorOptions;
8082

datahub-web-react/src/alchemy-components/theme/utils.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@ export const getColor = (color?: MiscColorOptions | ColorOptions, value: number
2727
@param size - the size of the font
2828
*/
2929
export const getFontSize = (size?: FontSizeOptions) => {
30-
let sizeValue = size || '';
31-
if (!size) sizeValue = 'md';
32-
return typography.fontSizes[sizeValue];
30+
if (size === 'inherit') return 'inherit';
31+
return typography.fontSizes[size || 'md'];
3332
};
3433

3534
/*

datahub-web-react/src/app/entityV2/EntityRegistry.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ export default class EntityRegistry {
251251
canEditLineage: genericEntityProperties.privileges?.canEditLineage ?? undefined,
252252
lineageSiblingIcon: genericEntityProperties?.lineageSiblingIcon,
253253
structuredProperties: genericEntityProperties.structuredProperties ?? undefined,
254+
versionProperties: genericEntityProperties.versionProperties ?? undefined,
254255
};
255256
}
256257

datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/SidebarEntityHeader.tsx

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import VersioningBadge from '@app/entityV2/shared/versioning/VersioningBadge';
12
import React from 'react';
23
import styled from 'styled-components';
34
import { useEntityData, useRefetch } from '../../../../../entity/shared/EntityContext';
@@ -91,6 +92,10 @@ const SidebarEntityHeader = () => {
9192
)}
9293
{entityData?.health && <HealthIcon urn={urn} health={entityData.health} baseUrl={entityUrl} />}
9394
<StructuredPropertyBadge structuredProperties={entityData?.structuredProperties} />
95+
<VersioningBadge
96+
versionProperties={entityData?.versionProperties ?? undefined}
97+
showPopover={false}
98+
/>
9499
</NameWrapper>
95100
<ContextPath
96101
instanceId={entityData?.dataPlatformInstance?.instanceId}

datahub-web-react/src/app/entityV2/shared/versioning/VersioningBadge.tsx

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
import { VersionPill } from '@app/entityV2/shared/versioning/common';
22
import VersionsPreview from '@app/entityV2/shared/versioning/VersionsPreview';
33
import { Popover } from '@components';
4+
import { PillStyleProps } from '@components/components/Pills/types';
45
import { Space } from 'antd';
56
import React from 'react';
67
import { VersionProperties } from '@types';
78

89
interface Props {
910
versionProperties?: VersionProperties;
1011
showPopover: boolean;
12+
className?: string;
1113
}
1214

13-
export default function VersioningBadge({ showPopover, versionProperties }: Props) {
15+
export default function VersioningBadge({
16+
showPopover,
17+
versionProperties,
18+
className,
19+
...props
20+
}: Props & Partial<PillStyleProps>) {
1421
if (!versionProperties?.version.versionTag) {
1522
return null;
1623
}
@@ -19,9 +26,11 @@ export default function VersioningBadge({ showPopover, versionProperties }: Prop
1926
<Popover content={showPopover && <VersionsPreview versionSet={versionProperties.versionSet ?? undefined} />}>
2027
<Space>
2128
<VersionPill
29+
{...props}
2230
label={versionProperties?.version.versionTag}
2331
isLatest={versionProperties.isLatest}
24-
clickable
32+
clickable={showPopover}
33+
className={className}
2534
/>
2635
</Space>
2736
</Popover>

datahub-web-react/src/app/lineageV2/LineageEntityNode/NodeContents.tsx

+16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { LoadingOutlined } from '@ant-design/icons';
2+
import VersioningBadge from '@app/entityV2/shared/versioning/VersioningBadge';
23
import ContainerPath from '@app/lineageV2/LineageEntityNode/ContainerPath';
34
import GhostEntityMenu from '@app/lineageV2/LineageEntityNode/GhostEntityMenu';
45
import SchemaFieldNodeContents from '@app/lineageV2/LineageEntityNode/SchemaFieldNodeContents';
@@ -222,6 +223,12 @@ const PropertyBadgeWrapper = styled.div`
222223
top: -16px;
223224
`;
224225

226+
const StyledVersioningBadge = styled(VersioningBadge)`
227+
padding: 0 4px;
228+
line-height: 1;
229+
max-width: 100px;
230+
`;
231+
225232
interface Props {
226233
urn: string;
227234
type: EntityType;
@@ -441,6 +448,15 @@ function NodeContents(props: Props & LineageEntity & DisplayedColumns) {
441448
title={entity?.name}
442449
highlightText={searchQuery}
443450
highlightColor={highlightColor}
451+
extra={
452+
entity?.versionProperties && (
453+
<StyledVersioningBadge
454+
showPopover={false}
455+
versionProperties={entity.versionProperties}
456+
size="inherit"
457+
/>
458+
)
459+
}
444460
/>
445461
{entity?.deprecation?.deprecated && (
446462
<DeprecationIcon

datahub-web-react/src/app/lineageV2/LineageExplorer.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import useShouldHideTransformations from '@app/lineageV2/useShouldHideTransformations';
2+
import useShouldShowDataProcessInstances from '@app/lineageV2/useShouldShowDataProcessInstances';
23
import React, { useContext, useEffect, useState } from 'react';
34
import { ReactFlowProvider } from 'reactflow';
45
import { EntityType, LineageDirection } from '../../types.generated';
@@ -36,7 +37,7 @@ export default function LineageExplorer(props: Props) {
3637
const [columnEdgeVersion, setColumnEdgeVersion] = useState(0);
3738
const [displayVersion, setDisplayVersion] = useState<[number, string[]]>([0, []]);
3839
const [hideTransformations, setHideTransformations] = useShouldHideTransformations();
39-
const [showDataProcessInstances, setShowDataProcessInstances] = useState(false);
40+
const [showDataProcessInstances, setShowDataProcessInstances] = useShouldShowDataProcessInstances();
4041

4142
const [showGhostEntities, setShowGhostEntities] = useState(false);
4243

datahub-web-react/src/app/lineageV2/LineageFilterNode/useFetchFilterNodeContents.ts

+5-10
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { DBT_URN } from '@app/ingest/source/builder/constants';
21
import { useGetLineageTimeParams } from '@app/lineage/utils/useGetLineageTimeParams';
32
import { LineageNodesContext } from '@app/lineageV2/common';
43
import computeOrFilters from '@app/lineageV2/LineageFilterNode/computeOrFilters';
4+
import { DEFAULT_IGNORE_AS_HOPS, DEFAULT_SEARCH_FLAGS } from '@app/lineageV2/useSearchAcrossLineage';
55
import { DEGREE_FILTER_NAME } from '@app/search/utils/constants';
66
import { useContext } from 'react';
77
import { PlatformFieldsFragment } from '../../../graphql/fragments.generated';
88
import { useAggregateAcrossLineageQuery } from '../../../graphql/search.generated';
9-
import { AggregationMetadata, EntityType, LineageDirection } from '../../../types.generated';
9+
import { AggregationMetadata, LineageDirection } from '../../../types.generated';
1010
import { ENTITY_SUB_TYPE_FILTER_NAME, FILTER_DELIMITER, PLATFORM_FILTER_NAME } from '../../searchV2/utils/constants';
1111

1212
export type PlatformAggregate = readonly [string, number, PlatformFieldsFragment];
@@ -25,7 +25,7 @@ export default function useFetchFilterNodeContents(parent: string, direction: Li
2525
const orFilters = computeOrFilters(
2626
[{ field: DEGREE_FILTER_NAME, values: ['1'] }],
2727
hideTransformations,
28-
showDataProcessInstances,
28+
!showDataProcessInstances,
2929
);
3030
const { data } = useAggregateAcrossLineageQuery({
3131
skip,
@@ -39,15 +39,10 @@ export default function useFetchFilterNodeContents(parent: string, direction: Li
3939
lineageFlags: {
4040
startTimeMillis,
4141
endTimeMillis,
42-
ignoreAsHops: [
43-
{
44-
entityType: EntityType.Dataset,
45-
platforms: [DBT_URN],
46-
},
47-
{ entityType: EntityType.DataJob },
48-
],
42+
ignoreAsHops: DEFAULT_IGNORE_AS_HOPS,
4943
},
5044
searchFlags: {
45+
...DEFAULT_SEARCH_FLAGS,
5146
skipCache: true, // TODO: Figure how to get around not needing this
5247
},
5348
},

datahub-web-react/src/app/lineageV2/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
SchemaMetadata,
1212
Status,
1313
StructuredProperties,
14+
VersionProperties,
1415
} from '@types';
1516

1617
export enum LineageAssetType {
@@ -67,6 +68,7 @@ export interface FetchedEntityV2 {
6768
inputFields?: InputFields;
6869
canEditLineage?: boolean;
6970
health?: Health[];
71+
versionProperties?: VersionProperties;
7072
lineageAssets?: Map<string, LineageAsset>;
7173
lineageSiblingIcon?: string;
7274
containers?: GenericEntityProperties[];

datahub-web-react/src/app/lineageV2/useSearchAcrossLineage.ts

+20-13
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ import {
2222

2323
const PER_HOP_LIMIT = 2;
2424

25+
export const DEFAULT_IGNORE_AS_HOPS = [
26+
{
27+
entityType: EntityType.Dataset,
28+
platforms: [DBT_URN],
29+
},
30+
{
31+
entityType: EntityType.SchemaField,
32+
platforms: [DBT_URN],
33+
},
34+
{ entityType: EntityType.DataJob },
35+
{ entityType: EntityType.DataProcessInstance },
36+
];
37+
38+
export const DEFAULT_SEARCH_FLAGS = {
39+
groupingSpec: { groupingCriteria: [] },
40+
filterNonLatestVersions: false,
41+
};
42+
2543
/**
2644
* Fetches the lineage structure for a given urn and direction, and updates the nodes map with the results.
2745
* @param urn Urn for which to fetch lineage
@@ -68,22 +86,11 @@ export default function useSearchAcrossLineage(
6886
startTimeMillis,
6987
endTimeMillis,
7088
entitiesExploredPerHopLimit: PER_HOP_LIMIT,
71-
ignoreAsHops: [
72-
{
73-
entityType: EntityType.Dataset,
74-
platforms: [DBT_URN],
75-
},
76-
{
77-
entityType: EntityType.SchemaField,
78-
platforms: [DBT_URN],
79-
},
80-
{ entityType: EntityType.DataJob },
81-
{ entityType: EntityType.DataProcessInstance },
82-
],
89+
ignoreAsHops: DEFAULT_IGNORE_AS_HOPS,
8390
},
8491
searchFlags: {
92+
...DEFAULT_SEARCH_FLAGS,
8593
skipCache: !!skipCache,
86-
groupingSpec: { groupingCriteria: [] },
8794
},
8895
};
8996

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { useCallback, useState } from 'react';
2+
3+
export default function useShouldShowDataProcessInstances(): [boolean, (value: boolean) => void] {
4+
const defaultValue = inLocalStorage() ? loadFromLocalStorage() : true;
5+
const [showInstances, setShowInstances] = useState(defaultValue);
6+
const setter = useCallback((value: boolean) => {
7+
setShowInstances(value);
8+
saveToLocalStorage(value);
9+
}, []);
10+
11+
return [showInstances, setter];
12+
}
13+
14+
const SHOW_DATA_PROCESS_INSTANCES_KEY = 'lineageV2__showDataProcessInstances';
15+
16+
function inLocalStorage(): boolean {
17+
return localStorage.getItem(SHOW_DATA_PROCESS_INSTANCES_KEY) !== null;
18+
}
19+
20+
function loadFromLocalStorage(): boolean {
21+
return localStorage.getItem(SHOW_DATA_PROCESS_INSTANCES_KEY) === 'true';
22+
}
23+
24+
function saveToLocalStorage(showInstances: boolean) {
25+
localStorage.setItem(SHOW_DATA_PROCESS_INSTANCES_KEY, String(showInstances));
26+
}

datahub-web-react/src/app/sharedV2/text/OverflowTitle.tsx

+14-1
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,30 @@ const Wrapper = styled.div<{ scale: number; computedRatio: boolean }>`
2323
}
2424
`;
2525

26+
const ExtraWrapper = styled.span`
27+
margin-left: 0.4em;
28+
`;
29+
2630
const MIN_SCALE = 2 / 3;
2731
const TOOLTIP_THRESHOLD = 0.8; // Show tooltip if text is smaller than TOOLTIP_THRESHOLD em
2832

2933
interface Props {
3034
title?: string;
3135
highlightText?: string;
3236
highlightColor?: string;
37+
extra?: React.ReactNode;
3338
className?: string;
3439
placement?: TooltipProps['placement'];
3540
}
3641

37-
export default function OverflowTitle({ title, highlightText, highlightColor, className, placement = 'top' }: Props) {
42+
export default function OverflowTitle({
43+
title,
44+
highlightText,
45+
highlightColor,
46+
extra,
47+
className,
48+
placement = 'top',
49+
}: Props) {
3850
const [scale, setScale] = React.useState<number>(1);
3951
const [ratio, setRatio] = React.useState<number | undefined>(undefined);
4052

@@ -59,6 +71,7 @@ export default function OverflowTitle({ title, highlightText, highlightColor, cl
5971
<Wrapper className={className} ref={ref} scale={scale} computedRatio={!!ratio}>
6072
<Highlight search={highlightText} matchStyle={{ backgroundColor: highlightColor }}>
6173
{title}
74+
{!!extra && <ExtraWrapper>{extra}</ExtraWrapper>}
6275
</Highlight>
6376
</Wrapper>
6477
</OptionalTooltip>

datahub-web-react/src/graphql/lineage.graphql

+5
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,11 @@ fragment entityLineageV2 on Entity {
694694
...lineageV2Result
695695
}
696696
}
697+
... on SupportsVersions {
698+
versionProperties {
699+
...versionProperties
700+
}
701+
}
697702
... on SchemaFieldEntity {
698703
fieldPath
699704
parent {

0 commit comments

Comments
 (0)