From 879c9f1bb591fcde9d878127684325943715c01e Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Tue, 5 Mar 2024 09:55:05 -0500 Subject: [PATCH 01/16] . --- .../src/asset-data/AssetLiveDataProvider.tsx | 1 + .../types/AssetLiveDataProvider.types.ts | 2 + .../ui-core/src/asset-graph/AssetNode.tsx | 16 +- .../ui-core/src/asset-graph/Utils.tsx | 5 +- .../__fixtures__/AssetNode.fixtures.ts | 155 +++++++++- .../__stories__/AssetNode.stories.tsx | 6 +- .../src/assets/AssetPartitionDetail.tsx | 8 +- .../packages/ui-core/src/assets/AssetView.tsx | 8 +- .../assets/LastMaterializationMetadata.tsx | 6 +- .../packages/ui-core/src/assets/Stale.tsx | 286 +++++++++++++----- 10 files changed, 391 insertions(+), 102 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-data/AssetLiveDataProvider.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-data/AssetLiveDataProvider.tsx index 8f05021cef6b1..5b5ce73222821 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-data/AssetLiveDataProvider.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-data/AssetLiveDataProvider.tsx @@ -166,6 +166,7 @@ export const ASSET_NODE_LIVE_FRAGMENT = gql` } } } + changedReasons freshnessInfo { ...AssetNodeLiveFreshnessInfo } diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-data/types/AssetLiveDataProvider.types.ts b/js_modules/dagster-ui/packages/ui-core/src/asset-data/types/AssetLiveDataProvider.types.ts index 574b4e11c949a..841e2f5661593 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-data/types/AssetLiveDataProvider.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-data/types/AssetLiveDataProvider.types.ts @@ -27,6 +27,7 @@ export type AssetNodeLiveFragment = { __typename: 'AssetNode'; id: string; opNames: Array; + changedReasons: Array; staleStatus: Types.StaleStatus | null; repository: {__typename: 'Repository'; id: string}; assetKey: {__typename: 'AssetKey'; path: Array}; @@ -119,6 +120,7 @@ export type AssetGraphLiveQuery = { __typename: 'AssetNode'; id: string; opNames: Array; + changedReasons: Array; staleStatus: Types.StaleStatus | null; repository: {__typename: 'Repository'; id: string}; assetKey: {__typename: 'AssetKey'; path: Array}; diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx index 608d6f5b1650d..c6e7fac74581a 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx @@ -15,7 +15,7 @@ import {AssetNodeFragment} from './types/AssetNode.types'; import {withMiddleTruncation} from '../app/Util'; import {useAssetLiveData} from '../asset-data/AssetLiveDataProvider'; import {PartitionCountTags} from '../assets/AssetNodePartitionCounts'; -import {StaleReasonsTags} from '../assets/Stale'; +import {StaleReasonsTag} from '../assets/Stale'; import {AssetChecksStatusSummary} from '../assets/asset-checks/AssetChecksStatusSummary'; import {assetDetailsPathForKey} from '../assets/assetDetailsPathForKey'; import {AssetComputeKindTag} from '../graph/OpTags'; @@ -34,7 +34,7 @@ export const AssetNode = React.memo(({definition, selected}: Props) => { return ( - + @@ -63,7 +63,6 @@ export const AssetNode = React.memo(({definition, selected}: Props) => { {definition.isPartitioned && !definition.isSource && ( )} - @@ -77,17 +76,6 @@ export const AssetNode = React.memo(({definition, selected}: Props) => { ); }, isEqual); -interface AssetTopTagsProps { - definition: AssetNodeFragment; - liveData?: LiveDataForNode; -} - -const AssetTopTags = ({definition, liveData}: AssetTopTagsProps) => ( - - - -); - const AssetNodeRowBox = styled(Box)` white-space: nowrap; line-height: 12px; diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/Utils.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/Utils.tsx index 03b3191d33a90..e5c9f71e5dbef 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/Utils.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/Utils.tsx @@ -14,7 +14,7 @@ import { AssetNodeLiveMaterializationFragment, AssetNodeLiveObservationFragment, } from '../asset-data/types/AssetLiveDataProvider.types'; -import {RunStatus, StaleStatus} from '../graphql/types'; +import {ChangeReason, RunStatus, StaleStatus} from '../graphql/types'; /** * IMPORTANT: This file is used by the WebWorker so make sure we don't indirectly import React or anything that relies on window/document @@ -154,6 +154,7 @@ export interface LiveDataForNode { staleStatus: StaleStatus | null; staleCauses: AssetGraphLiveQuery['assetNodes'][0]['staleCauses']; assetChecks: AssetCheckLiveFragment[]; + changedReason: Array; partitionStats: { numMaterialized: number; numMaterializing: number; @@ -165,6 +166,7 @@ export interface LiveDataForNode { export const MISSING_LIVE_DATA: LiveDataForNode = { unstartedRunIds: [], + changedReason: [], inProgressRunIds: [], runWhichFailedToMaterialize: null, freshnessInfo: null, @@ -217,6 +219,7 @@ export const buildLiveDataForNode = ( return { lastMaterialization, + changedReason: [], lastMaterializationRunStatus: latestRunForAsset && lastMaterialization?.runId === latestRunForAsset?.id ? latestRunForAsset.status diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__fixtures__/AssetNode.fixtures.ts b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__fixtures__/AssetNode.fixtures.ts index 1357d5c377c55..cc157af6c0085 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__fixtures__/AssetNode.fixtures.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__fixtures__/AssetNode.fixtures.ts @@ -1,6 +1,7 @@ import { AssetCheckExecutionResolvedStatus, AssetCheckSeverity, + ChangeReason, RunStatus, StaleCause, StaleCauseCategory, @@ -24,7 +25,7 @@ export const MockStaleReasonData: StaleCause = { __typename: 'AssetKey', }, partitionKey: null, - reason: 'updated data version', + reason: 'has a new data version', category: StaleCauseCategory.DATA, dependency: { path: ['asset0'], @@ -40,7 +41,7 @@ export const MockStaleReasonCode: StaleCause = { __typename: 'AssetKey', }, partitionKey: null, - reason: 'code version changed', + reason: 'has a new code version', category: StaleCauseCategory.CODE, dependency: { path: ['asset1'], @@ -64,6 +65,12 @@ export const AssetNodeFragmentBasic: AssetNodeFragment = buildAssetNode({ jobNames: ['job1'], opNames: ['asset1'], opVersion: '1', + changedReasons: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], }); export const AssetNodeFragmentSource = buildAssetNode({ @@ -96,6 +103,12 @@ export const AssetNodeFragmentPartitioned: AssetNodeFragment = buildAssetNode({ export const LiveDataForNodeRunStartedNotMaterializing: LiveDataForNode = { stepKey: 'asset2', unstartedRunIds: ['ABCDEF'], + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], inProgressRunIds: [], lastMaterialization: null, lastMaterializationRunStatus: null, @@ -112,6 +125,12 @@ export const LiveDataForNodeRunStartedNotMaterializing: LiveDataForNode = { export const LiveDataForNodeRunStartedMaterializing: LiveDataForNode = { stepKey: 'asset3', unstartedRunIds: [], + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], inProgressRunIds: ['ABCDEF'], lastMaterialization: null, lastMaterializationRunStatus: null, @@ -128,6 +147,12 @@ export const LiveDataForNodeRunStartedMaterializing: LiveDataForNode = { export const LiveDataForNodeRunFailed: LiveDataForNode = { stepKey: 'asset4', unstartedRunIds: [], + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], inProgressRunIds: [], lastMaterialization: null, lastMaterializationRunStatus: null, @@ -150,6 +175,12 @@ export const LiveDataForNodeNeverMaterialized: LiveDataForNode = { stepKey: 'asset5', unstartedRunIds: [], inProgressRunIds: [], + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], lastMaterialization: null, lastMaterializationRunStatus: null, lastObservation: null, @@ -165,6 +196,12 @@ export const LiveDataForNodeNeverMaterialized: LiveDataForNode = { export const LiveDataForNodeMaterialized: LiveDataForNode = { stepKey: 'asset6', unstartedRunIds: [], + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], inProgressRunIds: [], lastMaterialization: buildMaterializationEvent({ runId: 'ABCDEF', @@ -183,6 +220,12 @@ export const LiveDataForNodeMaterialized: LiveDataForNode = { export const LiveDataForNodeMaterializedWithChecks: LiveDataForNode = { stepKey: 'asset7', + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], unstartedRunIds: [], inProgressRunIds: [], lastMaterialization: buildMaterializationEvent({ @@ -260,6 +303,12 @@ export const LiveDataForNodeMaterializedWithChecksOk: LiveDataForNode = { export const LiveDataForNodeMaterializedAndStale: LiveDataForNode = { stepKey: 'asset8', + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], unstartedRunIds: [], inProgressRunIds: [], lastMaterialization: buildMaterializationEvent({ @@ -279,6 +328,12 @@ export const LiveDataForNodeMaterializedAndStale: LiveDataForNode = { export const LiveDataForNodeMaterializedAndStaleAndOverdue: LiveDataForNode = { stepKey: 'asset9', + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], unstartedRunIds: [], inProgressRunIds: [], lastMaterialization: buildMaterializationEvent({ @@ -301,6 +356,12 @@ export const LiveDataForNodeMaterializedAndStaleAndOverdue: LiveDataForNode = { export const LiveDataForNodeMaterializedAndStaleAndFresh: LiveDataForNode = { stepKey: 'asset10', + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], unstartedRunIds: [], inProgressRunIds: [], lastMaterialization: buildMaterializationEvent({ @@ -323,6 +384,12 @@ export const LiveDataForNodeMaterializedAndStaleAndFresh: LiveDataForNode = { export const LiveDataForNodeMaterializedAndFresh: LiveDataForNode = { stepKey: 'asset11', + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], unstartedRunIds: [], inProgressRunIds: [], lastMaterialization: buildMaterializationEvent({ @@ -345,6 +412,12 @@ export const LiveDataForNodeMaterializedAndFresh: LiveDataForNode = { export const LiveDataForNodeMaterializedAndOverdue: LiveDataForNode = { stepKey: 'asset12', + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], unstartedRunIds: [], inProgressRunIds: [], lastMaterialization: buildMaterializationEvent({ @@ -370,6 +443,12 @@ export const LiveDataForNodeFailedAndOverdue: LiveDataForNode = { unstartedRunIds: [], inProgressRunIds: [], lastMaterializationRunStatus: null, + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], lastObservation: null, lastMaterialization: null, runWhichFailedToMaterialize: buildRun({ @@ -391,6 +470,12 @@ export const LiveDataForNodeSourceNeverObserved: LiveDataForNode = { stepKey: 'source_asset2', unstartedRunIds: [], inProgressRunIds: [], + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], lastMaterialization: null, lastMaterializationRunStatus: null, lastObservation: null, @@ -408,6 +493,12 @@ export const LiveDataForNodeSourceObservationRunning: LiveDataForNode = { stepKey: 'source_asset3', unstartedRunIds: [], inProgressRunIds: ['ABCDEF'], + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], lastMaterialization: null, lastMaterializationRunStatus: null, lastObservation: null, @@ -433,6 +524,12 @@ export const LiveDataForNodeSourceObservedUpToDate: LiveDataForNode = { runWhichFailedToMaterialize: null, staleStatus: StaleStatus.FRESH, staleCauses: [], + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], assetChecks: [], freshnessInfo: null, opNames: [], @@ -451,6 +548,12 @@ export const LiveDataForNodePartitionedSomeMissing: LiveDataForNode = { lastMaterializationRunStatus: null, lastObservation: null, runWhichFailedToMaterialize: null, + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], staleStatus: StaleStatus.FRESH, staleCauses: [], assetChecks: [], @@ -473,6 +576,12 @@ export const LiveDataForNodePartitionedSomeFailed: LiveDataForNode = { runId: 'ABCDEF', timestamp: TIMESTAMP, }, + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], lastMaterializationRunStatus: null, lastObservation: null, runWhichFailedToMaterialize: null, @@ -501,6 +610,12 @@ export const LiveDataForNodePartitionedNoneMissing: LiveDataForNode = { lastMaterializationRunStatus: null, lastObservation: null, runWhichFailedToMaterialize: null, + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], staleStatus: StaleStatus.FRESH, staleCauses: [], assetChecks: [], @@ -519,6 +634,12 @@ export const LiveDataForNodePartitionedNeverMaterialized: LiveDataForNode = { unstartedRunIds: [], inProgressRunIds: [], lastMaterialization: null, + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], lastMaterializationRunStatus: null, lastObservation: null, runWhichFailedToMaterialize: null, @@ -547,6 +668,12 @@ export const LiveDataForNodePartitionedMaterializing: LiveDataForNode = { staleCauses: [], assetChecks: [], freshnessInfo: null, + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], partitionStats: { numMaterialized: 0, numMaterializing: 5, @@ -571,6 +698,12 @@ export const LiveDataForNodePartitionedStale: LiveDataForNode = { staleStatus: StaleStatus.STALE, staleCauses: [MockStaleReasonData], assetChecks: [], + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], freshnessInfo: null, partitionStats: { numMaterialized: 1500, @@ -584,6 +717,12 @@ export const LiveDataForNodePartitionedStale: LiveDataForNode = { export const LiveDataForNodePartitionedOverdue: LiveDataForNode = { stepKey: 'asset23', unstartedRunIds: [], + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], inProgressRunIds: [], lastMaterialization: { __typename: 'MaterializationEvent', @@ -635,10 +774,22 @@ export const LiveDataForNodePartitionedFresh: LiveDataForNode = { numFailed: 0, }, opNames: [], + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], }; export const LiveDataForNodePartitionedLatestRunFailed: LiveDataForNode = { stepKey: 'asset25', + changedReason: [ + ChangeReason.NEW, + ChangeReason.CODE_VERSION, + ChangeReason.INPUTS, + ChangeReason.PARTITIONS_DEFINITION, + ], unstartedRunIds: [], inProgressRunIds: [], lastMaterialization: null, diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__stories__/AssetNode.stories.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__stories__/AssetNode.stories.tsx index 778ea8463786d..2d0ec9d2175b8 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__stories__/AssetNode.stories.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__stories__/AssetNode.stories.tsx @@ -22,7 +22,7 @@ export const LiveStates = () => { ...scenario.definition, assetKey: { ...scenario.definition.assetKey, - path: [], + path: [] as string[], }, }; definitionCopy.assetKey.path = scenario.liveData @@ -38,6 +38,10 @@ export const LiveStates = () => { return null; } + if (definitionCopy.assetKey.path.includes('asset10')) { + console.log(scenario); + } + return ( <> diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx index 0c4a4b5c45567..e472026e5ac51 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx @@ -20,7 +20,7 @@ import {AssetEventMetadataEntriesTable} from './AssetEventMetadataEntriesTable'; import {AssetEventSystemTags} from './AssetEventSystemTags'; import {AssetMaterializationUpstreamData} from './AssetMaterializationUpstreamData'; import {FailedRunSinceMaterializationBanner} from './FailedRunSinceMaterializationBanner'; -import {StaleReasonsTags} from './Stale'; +import {StaleReasonsTag} from './Stale'; import {AssetEventGroup} from './groupByPartition'; import {AssetKey} from './types'; import { @@ -248,11 +248,7 @@ export const AssetPartitionDetail = ({ {hasStaleLoadingState ? ( ) : staleCauses && staleStatus ? ( - + ) : undefined} ) : ( diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetView.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetView.tsx index e1c064d0015a2..88de74ae54c48 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetView.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetView.tsx @@ -45,7 +45,7 @@ import { tokenForAssetKey, } from '../asset-graph/Utils'; import {useAssetGraphData} from '../asset-graph/useAssetGraphData'; -import {StaleReasonsTags} from '../assets/Stale'; +import {StaleReasonsTag} from '../assets/Stale'; import {AssetComputeKindTag} from '../graph/OpTags'; import {useQueryPersistedState} from '../hooks/useQueryPersistedState'; import {RepositoryLink} from '../nav/RepositoryLink'; @@ -526,11 +526,10 @@ const AssetViewPageHeaderTags = ({ return ( <> {definition ? ( - ) : null} {definition?.isSource ? ( @@ -568,11 +567,10 @@ const AssetViewPageHeaderTags = ({ )} {definition && ( - )} {definition && ( diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/LastMaterializationMetadata.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/LastMaterializationMetadata.tsx index 9ca98e9f1488c..b72b1e1016bcf 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/LastMaterializationMetadata.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/LastMaterializationMetadata.tsx @@ -3,7 +3,7 @@ import {Link} from 'react-router-dom'; import styled from 'styled-components'; import {AssetLineageElements} from './AssetLineageElements'; -import {StaleReasonsTags} from './Stale'; +import {StaleReasonsTag} from './Stale'; import {isRunlessEvent} from './isRunlessEvent'; import { AssetMaterializationFragment, @@ -117,9 +117,7 @@ export const LatestMaterializationMetadata = ({ - {liveData && ( - - )} + {liveData && } diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx index c99b68f218388..5e78ee5553ddd 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx @@ -4,21 +4,26 @@ import { Box, ButtonLink, Caption, - CaptionMono, + CaptionSubtitle, Colors, Icon, Popover, + Subtitle2, + Tag, + ifPlural, } from '@dagster-io/ui-components'; import groupBy from 'lodash/groupBy'; import isEqual from 'lodash/isEqual'; +import {useMemo} from 'react'; import {Link} from 'react-router-dom'; import {assetDetailsPathForKey} from './assetDetailsPathForKey'; import {LiveDataForNode, displayNameForAssetKey} from '../asset-graph/Utils'; import {AssetNodeKeyFragment} from '../asset-graph/types/AssetNode.types'; -import {AssetKeyInput, StaleCauseCategory, StaleStatus} from '../graphql/types'; +import {AssetKeyInput, ChangeReason, StaleCauseCategory, StaleStatus} from '../graphql/types'; +import {numberFormatter} from '../ui/formatters'; -type StaleDataForNode = Pick; +type StaleDataForNode = Pick; export const isAssetMissing = (liveData?: Pick) => liveData && liveData.staleStatus === StaleStatus.MISSING; @@ -39,6 +44,30 @@ const LABELS = { }, }; +function getCollapsedHeaderLabel(isSelf: boolean, category: StaleCauseCategory, count: number) { + const upstreamString = isSelf ? ' ' : ' upstream '; + switch (category) { + case StaleCauseCategory.CODE: + if (count === 1) { + return `1${upstreamString}code version change`; + } else { + return `${count}${upstreamString}code version changes`; + } + case StaleCauseCategory.DATA: + if (count === 1) { + return `1${upstreamString}data version change`; + } else { + return `${count}${upstreamString}data version changes`; + } + case StaleCauseCategory.DEPENDENCIES: + if (count === 1) { + return `1${upstreamString}dependency change`; + } else { + return `${count}${upstreamString}dependency changes`; + } + } +} + export const StaleReasonsLabel = ({ liveData, include, @@ -56,7 +85,9 @@ export const StaleReasonsLabel = ({ } + content={ + + } interactionKind="hover" className="chunk-popover-target" > @@ -66,49 +97,64 @@ export const StaleReasonsLabel = ({ ); }; -export const StaleReasonsTags = ({ - liveData, - include, +export const StaleReasonsTag = ({ assetKey, + liveData, + include = 'all', onClick, }: { assetKey: AssetKeyInput; - include: 'all' | 'upstream' | 'self'; liveData?: StaleDataForNode; + include?: 'all' | 'upstream' | 'self'; onClick?: () => void; }) => { - if (!isAssetStale(liveData) || !liveData?.staleCauses.length) { - return null; - } + const staleTag = useMemo(() => { + if (!isAssetStale(liveData) || !liveData?.staleCauses.length) { + return
; + } + const label = ( + Outdated ({numberFormatter.format(liveData.staleCauses.length)}) + ); + return ( + + } + position="top" + interactionKind="hover" + className="chunk-popover-target" + > + } + label={ + onClick ? ( + + {label} + + ) : ( + label + ) + } + /> + + ); + }, [assetKey, include, liveData, onClick]); + + const isNew = liveData?.changedReason.includes(ChangeReason.NEW); return ( - <> - {Object.entries(groupedCauses(assetKey, include, liveData)).map(([label, causes]) => ( - } - position="top" - interactionKind="hover" - className="chunk-popover-target" - > - } - label={ - onClick ? ( - - {label} - - ) : ( - label - ) - } - /> - - ))} - + + {staleTag} + {isNew ? ( + + ) : null} + ); }; @@ -127,23 +173,51 @@ function groupedCauses( return groupBy(all, (cause) => cause.label); } -const StaleCausesPopoverSummary = ({causes}: {causes: LiveDataForNode['staleCauses']}) => ( - - - Changes since last materialization: - - e.stopPropagation()}> - {causes.map((cause, idx) => ( - 0 ? 'top' : null} padding={{vertical: 8, horizontal: 12}}> - - {displayNameForAssetKey(cause.key)} - - - - ))} +const StaleCausesPopoverSummary = ({ + assetKey, + liveData, + include, +}: { + assetKey: AssetKeyInput; + liveData?: StaleDataForNode; + include: 'all' | 'upstream' | 'self'; +}) => { + const grouped = groupedCauses(assetKey, include, liveData); + const totalCauses = liveData?.staleCauses.length; + + if (!totalCauses) { + // Should never happen since the parent of this component should check that the asset is stale before rendering the popover + return
; + } + return ( + + + + {numberFormatter.format(totalCauses)} {ifPlural(totalCauses, 'change', 'changes')} since + last materialization + + + {Object.entries(grouped).map(([label, causes], idx) => { + const isSelf = isEqual(assetKey.path, causes[0]!.key.path); + return ( + + + + {getCollapsedHeaderLabel(isSelf, causes[0]!.category, causes.length)} + + + {causes.map((cause, idx) => ( + + ))} + + ); + })} - -); + ); +}; const StaleReason = ({ reason, @@ -152,25 +226,99 @@ const StaleReason = ({ reason: string; dependency: AssetNodeKeyFragment | null; }) => { - if (!dependency) { - return {` ${reason}`}; - } + const content = useMemo(() => { + if (!dependency) { + return {` ${reason}`}; + } + + const dependencyName = displayNameForAssetKey(dependency); + const dependencyPythonName = dependencyName.replace(/ /g, ''); + if (reason.endsWith(`${dependencyPythonName}`)) { + const reasonUpToDep = reason.slice(0, -dependencyPythonName.length); + return ( + <> + {reasonUpToDep} + + {dependencyName} + + + ); + } - const dependencyName = displayNameForAssetKey(dependency); - const dependencyPythonName = dependencyName.replace(/ /g, ''); - if (reason.endsWith(`${dependencyPythonName}`)) { - const reasonUpToDep = reason.slice(0, -dependencyPythonName.length); return ( - - {` ${reasonUpToDep}`} - {dependencyName} - + <> + + {dependencyName} + + {` ${reason} `} + ); - } + }, [dependency, reason]); + return ( + + {content} + + ); +}; +export const NewInBranchTag = ({ + changedReason, + assetKey, +}: { + changedReason: ChangeReason[]; + assetKey: AssetKeyInput; +}) => { + const changes = changedReason.filter((reason) => reason !== ChangeReason.NEW); + + function getDescription(change: ChangeReason) { + switch (change) { + case ChangeReason.NEW: + return ''; + case ChangeReason.CODE_VERSION: + return 'has a modified code version'; + case ChangeReason.INPUTS: + return 'has modified dependencies'; + case ChangeReason.PARTITIONS_DEFINITION: + return 'has a modified partition definition'; + } + } return ( - - {` ${reason} `}({dependencyName}) - + + + + {numberFormatter.format(changes.length)}{' '} + {ifPlural(changes.length, 'change', 'changes')} in this branch + + + {changes.map((change) => { + return ( + + {displayNameForAssetKey(assetKey)} + {getDescription(change)} + + ); + })} + + } + interactionKind="hover" + className="chunk-popover-target" + > + } + /> + ); }; From d46027417b2d02286ff7180a72660d7fff507f24 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Tue, 5 Mar 2024 09:55:53 -0500 Subject: [PATCH 02/16] rm console.log --- .../ui-core/src/asset-graph/__stories__/AssetNode.stories.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__stories__/AssetNode.stories.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__stories__/AssetNode.stories.tsx index 2d0ec9d2175b8..b7857dc3d6f23 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__stories__/AssetNode.stories.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__stories__/AssetNode.stories.tsx @@ -38,10 +38,6 @@ export const LiveStates = () => { return null; } - if (definitionCopy.assetKey.path.includes('asset10')) { - console.log(scenario); - } - return ( <> From 1fcca4b0bf6ea058b97b4ec23b5898573629fd32 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Tue, 5 Mar 2024 10:38:24 -0500 Subject: [PATCH 03/16] update mocks --- .../ui-components/src/components/Icon.tsx | 2 + .../src/icon-svgs/new_in_branch.svg | 10 + .../ui-core/src/asset-graph/AssetNode.tsx | 1 + .../ui-core/src/asset-graph/Utils.tsx | 6 +- .../__fixtures__/AssetNode.fixtures.ts | 48 +- .../src/asset-graph/types/AssetNode.types.ts | 1 + .../types/useAssetGraphData.types.ts | 2 + .../ui-core/src/assets/AssetEvents.tsx | 1 + .../src/assets/AssetPartitionDetail.tsx | 7 +- .../packages/ui-core/src/assets/Stale.tsx | 12 +- .../__fixtures__/AssetTables.fixtures.ts | 460 ++++++++---------- .../assets/types/AssetNodeDefinition.types.ts | 1 + .../src/assets/types/AssetView.types.ts | 2 + .../packages/ui-core/src/testing/mocking.ts | 6 +- 14 files changed, 277 insertions(+), 282 deletions(-) create mode 100644 js_modules/dagster-ui/packages/ui-components/src/icon-svgs/new_in_branch.svg diff --git a/js_modules/dagster-ui/packages/ui-components/src/components/Icon.tsx b/js_modules/dagster-ui/packages/ui-components/src/components/Icon.tsx index e18eebdb39c08..9bce5a4c8547f 100644 --- a/js_modules/dagster-ui/packages/ui-components/src/components/Icon.tsx +++ b/js_modules/dagster-ui/packages/ui-components/src/components/Icon.tsx @@ -106,6 +106,7 @@ import menu_book from '../icon-svgs/menu_book.svg'; import more_horiz from '../icon-svgs/more_horiz.svg'; import ms_teams from '../icon-svgs/ms_teams.svg'; import multi_asset from '../icon-svgs/multi_asset.svg'; +import new_in_branch from '../icon-svgs/new_in_branch.svg'; import nightlight from '../icon-svgs/nightlight.svg'; import no_access from '../icon-svgs/no_access.svg'; import observation from '../icon-svgs/observation.svg'; @@ -310,6 +311,7 @@ export const Icons = { menu, menu_book, more_horiz, + new_in_branch, nightlight, no_access, people, diff --git a/js_modules/dagster-ui/packages/ui-components/src/icon-svgs/new_in_branch.svg b/js_modules/dagster-ui/packages/ui-components/src/icon-svgs/new_in_branch.svg new file mode 100644 index 0000000000000..e50f8bf288075 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-components/src/icon-svgs/new_in_branch.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx index c6e7fac74581a..2da858adfd9db 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx @@ -207,6 +207,7 @@ export const ASSET_NODE_FRAGMENT = gql` graphName hasMaterializePermission jobNames + changedReasons opNames opVersion description diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/Utils.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/Utils.tsx index e5c9f71e5dbef..1bd830bd31a84 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/Utils.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/Utils.tsx @@ -154,7 +154,7 @@ export interface LiveDataForNode { staleStatus: StaleStatus | null; staleCauses: AssetGraphLiveQuery['assetNodes'][0]['staleCauses']; assetChecks: AssetCheckLiveFragment[]; - changedReason: Array; + changedReasons?: Array; partitionStats: { numMaterialized: number; numMaterializing: number; @@ -166,7 +166,7 @@ export interface LiveDataForNode { export const MISSING_LIVE_DATA: LiveDataForNode = { unstartedRunIds: [], - changedReason: [], + changedReasons: [], inProgressRunIds: [], runWhichFailedToMaterialize: null, freshnessInfo: null, @@ -219,7 +219,7 @@ export const buildLiveDataForNode = ( return { lastMaterialization, - changedReason: [], + changedReasons: [], lastMaterializationRunStatus: latestRunForAsset && lastMaterialization?.runId === latestRunForAsset?.id ? latestRunForAsset.status diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__fixtures__/AssetNode.fixtures.ts b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__fixtures__/AssetNode.fixtures.ts index cc157af6c0085..189dca3508d37 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__fixtures__/AssetNode.fixtures.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__fixtures__/AssetNode.fixtures.ts @@ -103,7 +103,7 @@ export const AssetNodeFragmentPartitioned: AssetNodeFragment = buildAssetNode({ export const LiveDataForNodeRunStartedNotMaterializing: LiveDataForNode = { stepKey: 'asset2', unstartedRunIds: ['ABCDEF'], - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -125,7 +125,7 @@ export const LiveDataForNodeRunStartedNotMaterializing: LiveDataForNode = { export const LiveDataForNodeRunStartedMaterializing: LiveDataForNode = { stepKey: 'asset3', unstartedRunIds: [], - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -147,7 +147,7 @@ export const LiveDataForNodeRunStartedMaterializing: LiveDataForNode = { export const LiveDataForNodeRunFailed: LiveDataForNode = { stepKey: 'asset4', unstartedRunIds: [], - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -175,7 +175,7 @@ export const LiveDataForNodeNeverMaterialized: LiveDataForNode = { stepKey: 'asset5', unstartedRunIds: [], inProgressRunIds: [], - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -196,7 +196,7 @@ export const LiveDataForNodeNeverMaterialized: LiveDataForNode = { export const LiveDataForNodeMaterialized: LiveDataForNode = { stepKey: 'asset6', unstartedRunIds: [], - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -220,7 +220,7 @@ export const LiveDataForNodeMaterialized: LiveDataForNode = { export const LiveDataForNodeMaterializedWithChecks: LiveDataForNode = { stepKey: 'asset7', - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -303,7 +303,7 @@ export const LiveDataForNodeMaterializedWithChecksOk: LiveDataForNode = { export const LiveDataForNodeMaterializedAndStale: LiveDataForNode = { stepKey: 'asset8', - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -328,7 +328,7 @@ export const LiveDataForNodeMaterializedAndStale: LiveDataForNode = { export const LiveDataForNodeMaterializedAndStaleAndOverdue: LiveDataForNode = { stepKey: 'asset9', - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -356,7 +356,7 @@ export const LiveDataForNodeMaterializedAndStaleAndOverdue: LiveDataForNode = { export const LiveDataForNodeMaterializedAndStaleAndFresh: LiveDataForNode = { stepKey: 'asset10', - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -384,7 +384,7 @@ export const LiveDataForNodeMaterializedAndStaleAndFresh: LiveDataForNode = { export const LiveDataForNodeMaterializedAndFresh: LiveDataForNode = { stepKey: 'asset11', - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -412,7 +412,7 @@ export const LiveDataForNodeMaterializedAndFresh: LiveDataForNode = { export const LiveDataForNodeMaterializedAndOverdue: LiveDataForNode = { stepKey: 'asset12', - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -443,7 +443,7 @@ export const LiveDataForNodeFailedAndOverdue: LiveDataForNode = { unstartedRunIds: [], inProgressRunIds: [], lastMaterializationRunStatus: null, - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -470,7 +470,7 @@ export const LiveDataForNodeSourceNeverObserved: LiveDataForNode = { stepKey: 'source_asset2', unstartedRunIds: [], inProgressRunIds: [], - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -493,7 +493,7 @@ export const LiveDataForNodeSourceObservationRunning: LiveDataForNode = { stepKey: 'source_asset3', unstartedRunIds: [], inProgressRunIds: ['ABCDEF'], - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -524,7 +524,7 @@ export const LiveDataForNodeSourceObservedUpToDate: LiveDataForNode = { runWhichFailedToMaterialize: null, staleStatus: StaleStatus.FRESH, staleCauses: [], - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -548,7 +548,7 @@ export const LiveDataForNodePartitionedSomeMissing: LiveDataForNode = { lastMaterializationRunStatus: null, lastObservation: null, runWhichFailedToMaterialize: null, - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -576,7 +576,7 @@ export const LiveDataForNodePartitionedSomeFailed: LiveDataForNode = { runId: 'ABCDEF', timestamp: TIMESTAMP, }, - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -610,7 +610,7 @@ export const LiveDataForNodePartitionedNoneMissing: LiveDataForNode = { lastMaterializationRunStatus: null, lastObservation: null, runWhichFailedToMaterialize: null, - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -634,7 +634,7 @@ export const LiveDataForNodePartitionedNeverMaterialized: LiveDataForNode = { unstartedRunIds: [], inProgressRunIds: [], lastMaterialization: null, - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -668,7 +668,7 @@ export const LiveDataForNodePartitionedMaterializing: LiveDataForNode = { staleCauses: [], assetChecks: [], freshnessInfo: null, - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -698,7 +698,7 @@ export const LiveDataForNodePartitionedStale: LiveDataForNode = { staleStatus: StaleStatus.STALE, staleCauses: [MockStaleReasonData], assetChecks: [], - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -717,7 +717,7 @@ export const LiveDataForNodePartitionedStale: LiveDataForNode = { export const LiveDataForNodePartitionedOverdue: LiveDataForNode = { stepKey: 'asset23', unstartedRunIds: [], - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -774,7 +774,7 @@ export const LiveDataForNodePartitionedFresh: LiveDataForNode = { numFailed: 0, }, opNames: [], - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, @@ -784,7 +784,7 @@ export const LiveDataForNodePartitionedFresh: LiveDataForNode = { export const LiveDataForNodePartitionedLatestRunFailed: LiveDataForNode = { stepKey: 'asset25', - changedReason: [ + changedReasons: [ ChangeReason.NEW, ChangeReason.CODE_VERSION, ChangeReason.INPUTS, diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/AssetNode.types.ts b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/AssetNode.types.ts index d9d9e76bdf19f..9d1d4b5b920ea 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/AssetNode.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/AssetNode.types.ts @@ -8,6 +8,7 @@ export type AssetNodeFragment = { graphName: string | null; hasMaterializePermission: boolean; jobNames: Array; + changedReasons: Array; opNames: Array; opVersion: string | null; description: string | null; diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/useAssetGraphData.types.ts b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/useAssetGraphData.types.ts index ee4cc66ed3b78..9b05aee106d61 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/useAssetGraphData.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/useAssetGraphData.types.ts @@ -17,6 +17,7 @@ export type AssetGraphQuery = { hasMaterializePermission: boolean; graphName: string | null; jobNames: Array; + changedReasons: Array; opNames: Array; opVersion: string | null; description: string | null; @@ -44,6 +45,7 @@ export type AssetNodeForGraphQueryFragment = { hasMaterializePermission: boolean; graphName: string | null; jobNames: Array; + changedReasons: Array; opNames: Array; opVersion: string | null; description: string | null; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetEvents.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetEvents.tsx index 1974d6038f12a..a4c243a1e8836 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetEvents.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetEvents.tsx @@ -207,6 +207,7 @@ export const AssetEvents = ({ assetKey={assetKey} stepKey={assetNode ? stepKeyForAsset(assetNode) : undefined} latestRunForPartition={null} + changedReasons={assetNode?.changedReasons} /> ) : ( diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx index e472026e5ac51..36cf565226e0a 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx @@ -181,6 +181,7 @@ export const AssetPartitionDetail = ({ latestRunForPartition, staleCauses, staleStatus, + changedReasons, }: { assetKey: AssetKey; group: AssetEventGroup; @@ -191,6 +192,7 @@ export const AssetPartitionDetail = ({ stepKey?: string; staleCauses?: LiveDataForNode['staleCauses']; staleStatus?: LiveDataForNode['staleStatus']; + changedReasons?: LiveDataForNode['changedReasons']; }) => { const {latest, partition, all} = group; @@ -248,7 +250,10 @@ export const AssetPartitionDetail = ({ {hasStaleLoadingState ? ( ) : staleCauses && staleStatus ? ( - + ) : undefined}
) : ( diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx index 5e78ee5553ddd..9f97c905e0493 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx @@ -23,7 +23,7 @@ import {AssetNodeKeyFragment} from '../asset-graph/types/AssetNode.types'; import {AssetKeyInput, ChangeReason, StaleCauseCategory, StaleStatus} from '../graphql/types'; import {numberFormatter} from '../ui/formatters'; -type StaleDataForNode = Pick; +type StaleDataForNode = Pick; export const isAssetMissing = (liveData?: Pick) => liveData && liveData.staleStatus === StaleStatus.MISSING; @@ -142,7 +142,7 @@ export const StaleReasonsTag = ({ ); }, [assetKey, include, liveData, onClick]); - const isNew = liveData?.changedReason.includes(ChangeReason.NEW); + const isNew = liveData?.changedReasons?.includes(ChangeReason.NEW); return ( {staleTag} {isNew ? ( - + ) : null} ); @@ -265,13 +265,13 @@ const StaleReason = ({ }; export const NewInBranchTag = ({ - changedReason, + changedReasons, assetKey, }: { - changedReason: ChangeReason[]; + changedReasons: ChangeReason[]; assetKey: AssetKeyInput; }) => { - const changes = changedReason.filter((reason) => reason !== ChangeReason.NEW); + const changes = changedReasons.filter((reason) => reason !== ChangeReason.NEW); function getDescription(change: ChangeReason) { switch (change) { diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetTables.fixtures.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetTables.fixtures.ts index 88d2a67d9000b..1b234213e3cb6 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetTables.fixtures.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetTables.fixtures.ts @@ -1,61 +1,71 @@ -import {MockedResponse} from '@apollo/client/testing'; - import {ASSETS_GRAPH_LIVE_QUERY} from '../../asset-data/AssetLiveDataProvider'; -import {AssetGraphLiveQuery} from '../../asset-data/types/AssetLiveDataProvider.types'; +import { + AssetGraphLiveQuery, + AssetGraphLiveQueryVariables, +} from '../../asset-data/types/AssetLiveDataProvider.types'; import {MockStaleReasonData} from '../../asset-graph/__fixtures__/AssetNode.fixtures'; import { + Asset, RunStatus, StaleStatus, + buildAsset, buildAssetChecks, + buildAssetConnection, + buildAssetFreshnessInfo, buildAssetKey, + buildAssetLatestInfo, buildAssetNode, buildFreshnessPolicy, + buildMaterializationEvent, + buildObservationEvent, buildPartitionDefinition, + buildPartitionStats, buildRepository, buildRepositoryLocation, + buildRun, } from '../../graphql/types'; +import {buildQueryMock} from '../../testing/mocking'; import {SINGLE_NON_SDA_ASSET_QUERY} from '../../workspace/VirtualizedAssetRow'; -import {SingleNonSdaAssetQuery} from '../../workspace/types/VirtualizedAssetRow.types'; +import { + SingleNonSdaAssetQuery, + SingleNonSdaAssetQueryVariables, +} from '../../workspace/types/VirtualizedAssetRow.types'; import {ASSET_CATALOG_GROUP_TABLE_QUERY, ASSET_CATALOG_TABLE_QUERY} from '../AssetsCatalogTable'; import { AssetCatalogGroupTableQuery, + AssetCatalogGroupTableQueryVariables, AssetCatalogTableQuery, + AssetCatalogTableQueryVariables, } from '../types/AssetsCatalogTable.types'; -export const AssetCatalogGroupTableMock: MockedResponse = { - request: { - query: ASSET_CATALOG_GROUP_TABLE_QUERY, - }, - result: { - data: { - __typename: 'Query', - assetNodes: [], - }, +export const AssetCatalogGroupTableMock = buildQueryMock< + AssetCatalogGroupTableQuery, + AssetCatalogGroupTableQueryVariables +>({ + query: ASSET_CATALOG_GROUP_TABLE_QUERY, + data: { + assetNodes: [], }, -}; +}); -export const SingleAssetQueryTrafficDashboard: MockedResponse = { - request: { - query: SINGLE_NON_SDA_ASSET_QUERY, - variables: {input: {path: ['dashboards', 'traffic_dashboard']}}, - }, - result: { - data: { - __typename: 'Query', - assetOrError: { - id: '["dashboards", "traffic_dashboard"]', - assetMaterializations: [ - { - timestamp: '1674603883946', - runId: 'db44ed48-0dca-4942-803b-5edc439c73eb', - __typename: 'MaterializationEvent', - }, - ], - __typename: 'Asset', - }, - }, +export const SingleAssetQueryTrafficDashboard = buildQueryMock< + SingleNonSdaAssetQuery, + SingleNonSdaAssetQueryVariables +>({ + query: SINGLE_NON_SDA_ASSET_QUERY, + variables: {input: {path: ['dashboards', 'traffic_dashboard']}}, + data: { + assetOrError: buildAsset({ + id: '["dashboards", "traffic_dashboard"]', + assetMaterializations: [ + buildMaterializationEvent({ + timestamp: '1674603883946', + runId: 'db44ed48-0dca-4942-803b-5edc439c73eb', + }), + ], + }), }, -}; +}); const repository = buildRepository({ id: 'c22d9677b8089be89b1e014b9de34284962f83a7', @@ -63,211 +73,177 @@ const repository = buildRepository({ location: buildRepositoryLocation({ id: 'test.py', name: 'test.py', - __typename: 'RepositoryLocation', }), - __typename: 'Repository', }); -export const SingleAssetQueryMaterializedWithLatestRun: MockedResponse = { - request: { - query: ASSETS_GRAPH_LIVE_QUERY, - variables: {assetKeys: [{path: ['good_asset']}]}, - }, - result: { - data: { - __typename: 'Query', - assetNodes: [ - { - id: 'test.py.repo.["good_asset"]', - opNames: ['good_asset'], - repository, - partitionStats: null, - assetKey: { - path: ['good_asset'], - __typename: 'AssetKey', - }, - assetMaterializations: [ - { - timestamp: '1674603883946', - runId: 'db44ed48-0dca-4942-803b-5edc439c73eb', - __typename: 'MaterializationEvent', - }, - ], - assetChecksOrError: buildAssetChecks(), - freshnessInfo: null, - assetObservations: [ - { - timestamp: '1674764717707', - runId: 'ae107ad2-8827-44fb-bc62-a4cdacb78438', - __typename: 'ObservationEvent', - }, - ], - staleStatus: StaleStatus.FRESH, - staleCauses: [], - __typename: 'AssetNode', - }, - ], - assetsLatestInfo: [ - { - id: 'test.py.repo.["good_asset"]', - assetKey: { - path: ['good_asset'], - __typename: 'AssetKey', - }, - unstartedRunIds: [], - inProgressRunIds: [], - latestRun: { - id: 'db44ed48-0dca-4942-803b-5edc439c73eb', - status: RunStatus.SUCCESS, - endTime: 1674603891.34749, - __typename: 'Run', - }, - __typename: 'AssetLatestInfo', - }, - ], - }, +export const SingleAssetQueryMaterializedWithLatestRun = buildQueryMock< + AssetGraphLiveQuery, + AssetGraphLiveQueryVariables +>({ + query: ASSETS_GRAPH_LIVE_QUERY, + variables: {assetKeys: [{path: ['good_asset']}]}, + data: { + assetNodes: [ + buildAssetNode({ + id: 'test.py.repo.["good_asset"]', + opNames: ['good_asset'], + repository, + partitionStats: null, + assetKey: buildAssetKey({ + path: ['good_asset'], + }), + assetMaterializations: [ + buildMaterializationEvent({ + timestamp: '1674603883946', + runId: 'db44ed48-0dca-4942-803b-5edc439c73eb', + }), + ], + assetChecksOrError: buildAssetChecks(), + freshnessInfo: null, + assetObservations: [ + buildObservationEvent({ + timestamp: '1674764717707', + runId: 'ae107ad2-8827-44fb-bc62-a4cdacb78438', + }), + ], + staleStatus: StaleStatus.FRESH, + staleCauses: [], + }), + ], + assetsLatestInfo: [ + buildAssetLatestInfo({ + id: 'test.py.repo.["good_asset"]', + assetKey: buildAssetKey({ + path: ['good_asset'], + }), + unstartedRunIds: [], + inProgressRunIds: [], + latestRun: buildRun({ + id: 'db44ed48-0dca-4942-803b-5edc439c73eb', + status: RunStatus.SUCCESS, + endTime: 1674603891.34749, + }), + }), + ], }, -}; +}); -export const SingleAssetQueryMaterializedStaleAndLate: MockedResponse = { - request: { - query: ASSETS_GRAPH_LIVE_QUERY, - variables: {assetKeys: [{path: ['late_asset']}]}, - }, - result: { - data: { - __typename: 'Query', - assetNodes: [ - { - id: 'test.py.repo.["late_asset"]', - opNames: ['late_asset'], - repository, - partitionStats: null, - assetKey: { - path: ['late_asset'], - __typename: 'AssetKey', - }, - assetChecksOrError: buildAssetChecks(), - assetMaterializations: [ - { - timestamp: '1674603891025', - runId: 'db44ed48-0dca-4942-803b-5edc439c73eb', - __typename: 'MaterializationEvent', - }, - ], - freshnessInfo: { - currentMinutesLate: 21657.2618512, - __typename: 'AssetFreshnessInfo', - }, - assetObservations: [], - staleStatus: StaleStatus.STALE, - staleCauses: [MockStaleReasonData], - __typename: 'AssetNode', +export const SingleAssetQueryMaterializedStaleAndLate = buildQueryMock< + AssetGraphLiveQuery, + AssetGraphLiveQueryVariables +>({ + query: ASSETS_GRAPH_LIVE_QUERY, + variables: {assetKeys: [{path: ['late_asset']}]}, + data: { + assetNodes: [ + buildAssetNode({ + id: 'test.py.repo.["late_asset"]', + opNames: ['late_asset'], + repository, + partitionStats: null, + assetKey: { + path: ['late_asset'], + __typename: 'AssetKey', }, - ], - assetsLatestInfo: [ - { - id: 'test.py.repo.["late_asset"]', - assetKey: { - path: ['late_asset'], - __typename: 'AssetKey', - }, - unstartedRunIds: [], - inProgressRunIds: [], - latestRun: { - id: 'db44ed48-0dca-4942-803b-5edc439c73eb', - status: RunStatus.SUCCESS, - endTime: 1674603891.34749, - __typename: 'Run', - }, - __typename: 'AssetLatestInfo', - }, - ], - }, + assetChecksOrError: buildAssetChecks(), + assetMaterializations: [ + buildMaterializationEvent({ + timestamp: '1674603891025', + runId: 'db44ed48-0dca-4942-803b-5edc439c73eb', + }), + ], + freshnessInfo: buildAssetFreshnessInfo({ + currentMinutesLate: 21657.2618512, + }), + assetObservations: [], + staleStatus: StaleStatus.STALE, + staleCauses: [MockStaleReasonData], + }), + ], + assetsLatestInfo: [ + buildAssetLatestInfo({ + id: 'test.py.repo.["late_asset"]', + assetKey: buildAssetKey({ + path: ['late_asset'], + }), + unstartedRunIds: [], + inProgressRunIds: [], + latestRun: buildRun({ + id: 'db44ed48-0dca-4942-803b-5edc439c73eb', + status: RunStatus.SUCCESS, + endTime: 1674603891.34749, + }), + }), + ], }, -}; +}); -export const SingleAssetQueryLastRunFailed: MockedResponse = { - request: { - query: ASSETS_GRAPH_LIVE_QUERY, - variables: {assetKeys: [{path: ['run_failing_asset']}]}, - }, - result: { - data: { - __typename: 'Query', - assetNodes: [ - { - id: 'test.py.repo.["run_failing_asset"]', - opNames: ['run_failing_asset'], - repository, - partitionStats: { - __typename: 'PartitionStats', - numMaterialized: 8, - numMaterializing: 0, - numPartitions: 11, - numFailed: 0, - }, - assetKey: { - path: ['run_failing_asset'], - __typename: 'AssetKey', - }, - assetChecksOrError: buildAssetChecks(), - assetMaterializations: [ - { - timestamp: '1666373060112', - runId: 'e23b2cd2-7a4e-43d2-bdc6-892125375e8f', - __typename: 'MaterializationEvent', - }, - ], +export const SingleAssetQueryLastRunFailed = buildQueryMock< + AssetGraphLiveQuery, + AssetGraphLiveQueryVariables +>({ + query: ASSETS_GRAPH_LIVE_QUERY, + variables: {assetKeys: [{path: ['run_failing_asset']}]}, + data: { + assetNodes: [ + buildAssetNode({ + id: 'test.py.repo.["run_failing_asset"]', + opNames: ['run_failing_asset'], + repository, + partitionStats: buildPartitionStats({ + numMaterialized: 8, + numMaterializing: 0, + numPartitions: 11, + numFailed: 0, + }), + assetKey: buildAssetKey({ + path: ['run_failing_asset'], + }), + assetChecksOrError: buildAssetChecks(), + assetMaterializations: [ + buildMaterializationEvent({ + timestamp: '1666373060112', + runId: 'e23b2cd2-7a4e-43d2-bdc6-892125375e8f', + }), + ], - freshnessInfo: null, - assetObservations: [], - staleStatus: StaleStatus.MISSING, - staleCauses: [], - __typename: 'AssetNode', - }, - ], - assetsLatestInfo: [ - { - id: 'test.py.repo.["run_failing_asset"]', - assetKey: { - path: ['run_failing_asset'], - __typename: 'AssetKey', - }, - unstartedRunIds: [], - inProgressRunIds: [], - latestRun: { - id: '4678865f-6191-4a35-bb47-2122d57ec9a6', - status: RunStatus.FAILURE, - endTime: 1669067250.48091, - __typename: 'Run', - }, - __typename: 'AssetLatestInfo', - }, - ], - }, + freshnessInfo: null, + assetObservations: [], + staleStatus: StaleStatus.MISSING, + staleCauses: [], + }), + ], + assetsLatestInfo: [ + buildAssetLatestInfo({ + id: 'test.py.repo.["run_failing_asset"]', + assetKey: buildAssetKey({ + path: ['run_failing_asset'], + }), + unstartedRunIds: [], + inProgressRunIds: [], + latestRun: buildRun({ + id: '4678865f-6191-4a35-bb47-2122d57ec9a6', + status: RunStatus.FAILURE, + endTime: 1669067250.48091, + }), + }), + ], }, -}; +}); -export const AssetCatalogTableMockAssets: Extract< - AssetCatalogTableQuery['assetsOrError'], - {__typename: 'AssetConnection'} ->['nodes'] = [ - { +export const AssetCatalogTableMockAssets: Asset[] = [ + buildAsset({ id: '["dashboards", "cost_dashboard"]', - __typename: 'Asset', key: buildAssetKey({path: ['dashboards', 'cost_dashboard']}), definition: null, - }, - { + }), + buildAsset({ id: '["dashboards", "traffic_dashboard"]', - __typename: 'Asset', key: buildAssetKey({path: ['dashboards', 'traffic_dashboard']}), definition: null, - }, - { + }), + buildAsset({ id: 'test.py.repo.["good_asset"]', - __typename: 'Asset', key: buildAssetKey({path: ['good_asset']}), definition: buildAssetNode({ id: 'test.py.repo.["good_asset"]', @@ -279,10 +255,9 @@ export const AssetCatalogTableMockAssets: Extract< 'This is a super long description that could involve some level of SQL and is just generally very long', repository, }), - }, - { + }), + buildAsset({ id: 'test.py.repo.["late_asset"]', - __typename: 'Asset', key: buildAssetKey({path: ['late_asset']}), definition: buildAssetNode({ id: 'test.py.repo.["late_asset"]', @@ -298,10 +273,9 @@ export const AssetCatalogTableMockAssets: Extract< description: null, repository, }), - }, - { + }), + buildAsset({ id: 'test.py.repo.["run_failing_asset"]', - __typename: 'Asset', key: buildAssetKey({path: ['run_failing_asset']}), definition: buildAssetNode({ id: 'test.py.repo.["run_failing_asset"]', @@ -315,10 +289,9 @@ export const AssetCatalogTableMockAssets: Extract< computeKind: 'sql', repository, }), - }, - { + }), + buildAsset({ id: 'test.py.repo.["asset_with_a_very_long_key_that_will_require_truncation"]', - __typename: 'Asset', key: buildAssetKey({path: ['asset_with_a_very_long_key_that_will_require_truncation']}), definition: buildAssetNode({ id: 'test.py.repo.["asset_with_a_very_long_key_that_will_require_truncation"]', @@ -329,20 +302,17 @@ export const AssetCatalogTableMockAssets: Extract< computeKind: 'ipynb', repository, }), - }, + }), ]; -export const AssetCatalogTableMock: MockedResponse = { - request: { - query: ASSET_CATALOG_TABLE_QUERY, - }, - result: { - data: { - __typename: 'Query', - assetsOrError: { - __typename: 'AssetConnection', - nodes: AssetCatalogTableMockAssets, - }, - }, +export const AssetCatalogTableMock = buildQueryMock< + AssetCatalogTableQuery, + AssetCatalogTableQueryVariables +>({ + query: ASSET_CATALOG_TABLE_QUERY, + data: { + assetsOrError: buildAssetConnection({ + nodes: AssetCatalogTableMockAssets, + }), }, -}; +}); diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetNodeDefinition.types.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetNodeDefinition.types.ts index fc7964be4fd23..702d98a4372a2 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetNodeDefinition.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetNodeDefinition.types.ts @@ -14,6 +14,7 @@ export type AssetNodeDefinitionFragment = { isSource: boolean; isExecutable: boolean; hasMaterializePermission: boolean; + changedReasons: Array; computeKind: string | null; isPartitioned: boolean; isObservable: boolean; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetView.types.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetView.types.ts index 8ecbe6adf02f5..c3890cb9124d1 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetView.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetView.types.ts @@ -30,6 +30,7 @@ export type AssetViewDefinitionQuery = { isSource: boolean; isExecutable: boolean; hasMaterializePermission: boolean; + changedReasons: Array; computeKind: string | null; isPartitioned: boolean; isObservable: boolean; @@ -15855,6 +15856,7 @@ export type AssetViewDefinitionNodeFragment = { isSource: boolean; isExecutable: boolean; hasMaterializePermission: boolean; + changedReasons: Array; computeKind: string | null; isPartitioned: boolean; isObservable: boolean; diff --git a/js_modules/dagster-ui/packages/ui-core/src/testing/mocking.ts b/js_modules/dagster-ui/packages/ui-core/src/testing/mocking.ts index 29a83a024ab98..54aa8c72f5c21 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/testing/mocking.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/testing/mocking.ts @@ -1,11 +1,11 @@ -import {DocumentNode} from '@apollo/client'; +import {DocumentNode, OperationVariables} from '@apollo/client'; import {MockedResponse} from '@apollo/client/testing'; import deepmerge from 'deepmerge'; import {GraphQLError} from 'graphql'; export function buildQueryMock< TQuery extends {__typename: 'Query'}, - TVariables extends Record, + TVariables extends OperationVariables, >({ query, variables, @@ -14,7 +14,7 @@ export function buildQueryMock< ...rest }: Partial> & { query: DocumentNode; - variables: TVariables; + variables?: TVariables; data?: Omit; errors?: ReadonlyArray; }): MockedResponse { From 16534df398f49134b8f5ccb48dcbeea62b13e7ed Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Tue, 5 Mar 2024 11:21:50 -0500 Subject: [PATCH 04/16] more mocks --- .../assets/__tests__/buildAssetTabs.test.tsx | 76 ++++++++----------- 1 file changed, 32 insertions(+), 44 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx index 22f6daa022812..9f23488835e51 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx @@ -9,6 +9,8 @@ import { buildConfigTypeField, buildDimensionPartitionKeys, buildPartitionDefinition, + buildRegularConfigType, + buildRegularDagsterType, buildRepository, buildRepositoryLocation, } from '../../graphql/types'; @@ -135,22 +137,19 @@ describe('buildAssetTabs', () => { }); // Copied from browser - const definitionWithoutPartition: AssetViewDefinitionNodeFragment = { + const definitionWithoutPartition = buildAssetNode({ id: 'dagster_test.toys.repo.auto_materialize_repo_1.["lazy_downstream_1"]', groupName: 'default', partitionDefinition: null, partitionKeysByDimension: [], - repository: { + repository: buildRepository({ id: '4d9fd77c222a797eb8427fcbe1968799ebc24de8', name: 'auto_materialize_repo_1', - location: { + location: buildRepositoryLocation({ id: 'dagster_test.toys.repo', name: 'dagster_test.toys.repo', - __typename: 'RepositoryLocation', - }, - __typename: 'Repository', - }, - __typename: 'AssetNode', + }), + }), description: null, graphName: null, targetingInstigators: [], @@ -161,34 +160,30 @@ describe('buildAssetTabs', () => { backfillPolicy: null, freshnessPolicy: null, requiredResources: [], - configField: { + configField: buildConfigTypeField({ name: 'config', isRequired: false, - configType: { + configType: buildRegularConfigType({ givenName: 'Any', - __typename: 'RegularConfigType', key: 'Any', description: null, isSelector: false, typeParamKeys: [], recursiveConfigTypes: [], - }, - __typename: 'ConfigTypeField', - }, + }), + }), hasMaterializePermission: true, computeKind: null, isPartitioned: false, isObservable: false, isExecutable: true, isSource: false, - assetKey: { + assetKey: buildAssetKey({ path: ['lazy_downstream_1'], - __typename: 'AssetKey', - }, + }), metadataEntries: [], owners: [], - type: { - __typename: 'RegularDagsterType', + type: buildRegularDagsterType({ key: 'Any', name: 'Any', displayName: 'Any', @@ -198,78 +193,71 @@ describe('buildAssetTabs', () => { isBuiltin: true, isNothing: false, metadataEntries: [], - inputSchemaType: { + inputSchemaType: buildCompositeConfigType({ key: 'Selector.f2fe6dfdc60a1947a8f8e7cd377a012b47065bc4', description: null, isSelector: true, typeParamKeys: [], fields: [ - { + buildConfigTypeField({ name: 'json', description: null, isRequired: true, configTypeKey: 'Shape.4b53b73df342381d0d05c5f36183dc99cb9676e2', defaultValueAsJson: null, - __typename: 'ConfigTypeField', - }, - { + }), + buildConfigTypeField({ name: 'pickle', description: null, isRequired: true, configTypeKey: 'Shape.4b53b73df342381d0d05c5f36183dc99cb9676e2', defaultValueAsJson: null, - __typename: 'ConfigTypeField', - }, - { + }), + buildConfigTypeField({ name: 'value', description: null, isRequired: true, configTypeKey: 'Any', defaultValueAsJson: null, - __typename: 'ConfigTypeField', - }, + }), ], - __typename: 'CompositeConfigType', recursiveConfigTypes: [ - { + buildCompositeConfigType({ key: 'Shape.4b53b73df342381d0d05c5f36183dc99cb9676e2', description: null, isSelector: false, typeParamKeys: [], fields: [ - { + buildConfigTypeField({ name: 'path', description: null, isRequired: true, configTypeKey: 'String', defaultValueAsJson: null, - __typename: 'ConfigTypeField', - }, + }), ], - __typename: 'CompositeConfigType', - }, - { + }), + buildRegularConfigType({ givenName: 'String', __typename: 'RegularConfigType', key: 'String', description: '', isSelector: false, typeParamKeys: [], - }, - { + }), + buildRegularConfigType({ givenName: 'Any', - __typename: 'RegularConfigType', key: 'Any', description: null, isSelector: false, typeParamKeys: [], - }, + }), ], - }, + }), outputSchemaType: null, innerTypes: [], - }, - }; + }), + }); const params = {}; it('shows all tabs', () => { From c1731fb4f69378013fe95535604ef360ace8f16a Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Tue, 5 Mar 2024 12:06:16 -0500 Subject: [PATCH 05/16] update mocks again --- .../src/asset-graph/__fixtures__/AssetNode.fixtures.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__fixtures__/AssetNode.fixtures.ts b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__fixtures__/AssetNode.fixtures.ts index 189dca3508d37..796b086c404ea 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__fixtures__/AssetNode.fixtures.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/__fixtures__/AssetNode.fixtures.ts @@ -870,14 +870,14 @@ export const AssetNodeScenariosBase = [ title: 'Materialized and Stale', liveData: LiveDataForNodeMaterializedAndStale, definition: AssetNodeFragmentBasic, - expectedText: ['Upstream code version', 'Feb'], + expectedText: ['Outdated', 'Feb'], }, { title: 'Materialized and Stale and Overdue', liveData: LiveDataForNodeMaterializedAndStaleAndOverdue, definition: AssetNodeFragmentBasic, - expectedText: ['Upstream code version', 'Overdue', 'Feb'], + expectedText: ['Outdated', 'Overdue', 'Feb'], }, { From 2eda7dff0b05c5b2e2ab0fa1f3193352732c2b8e Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Tue, 5 Mar 2024 12:07:56 -0500 Subject: [PATCH 06/16] mock mocks --- .../assets/__tests__/buildAssetTabs.test.tsx | 32 ++----------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx index 9f23488835e51..df9a6c4bafeaf 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx @@ -51,18 +51,11 @@ describe('buildAssetTabs', () => { name: 'dagster_test.toys.repo', }), }), - description: null, - graphName: null, targetingInstigators: [], opNames: ['eager_downstream_3_partitioned'], - opVersion: null, jobNames: ['__ASSET_JOB_0'], autoMaterializePolicy, - backfillPolicy: null, - freshnessPolicy: null, - requiredResources: [], hasMaterializePermission: true, - computeKind: null, isPartitioned: true, isObservable: false, isExecutable: true, @@ -70,70 +63,50 @@ describe('buildAssetTabs', () => { assetKey: buildAssetKey({ path: ['eager_downstream_3_partitioned'], }), - metadataEntries: [], - type: { - __typename: 'RegularDagsterType', + type: buildRegularDagsterType({ key: 'Any', name: 'Any', displayName: 'Any', - description: null, isNullable: false, isList: false, isBuiltin: true, isNothing: false, - metadataEntries: [], inputSchemaType: buildCompositeConfigType({ key: 'Selector.f2fe6dfdc60a1947a8f8e7cd377a012b47065bc4', - description: null, isSelector: true, typeParamKeys: [], fields: [ buildConfigTypeField({ name: 'json', - description: null, isRequired: true, configTypeKey: 'Shape.4b53b73df342381d0d05c5f36183dc99cb9676e2', - defaultValueAsJson: null, }), buildConfigTypeField({ name: 'pickle', - description: null, isRequired: true, configTypeKey: 'Shape.4b53b73df342381d0d05c5f36183dc99cb9676e2', - defaultValueAsJson: null, - __typename: 'ConfigTypeField', }), buildConfigTypeField({ name: 'value', - description: null, isRequired: true, configTypeKey: 'Any', - defaultValueAsJson: null, - __typename: 'ConfigTypeField', }), ], recursiveConfigTypes: [ buildCompositeConfigType({ key: 'Shape.4b53b73df342381d0d05c5f36183dc99cb9676e2', - description: null, isSelector: false, - typeParamKeys: [], fields: [ buildConfigTypeField({ name: 'path', - description: null, isRequired: true, configTypeKey: 'String', - defaultValueAsJson: null, - __typename: 'ConfigTypeField', }), ], }), ], }), - outputSchemaType: null, - innerTypes: [], - }, + }), }); // Copied from browser @@ -239,7 +212,6 @@ describe('buildAssetTabs', () => { }), buildRegularConfigType({ givenName: 'String', - __typename: 'RegularConfigType', key: 'String', description: '', isSelector: false, From 7f0489153e363775e0a074b7ef44b18996b2f24e Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Tue, 5 Mar 2024 17:57:56 -0500 Subject: [PATCH 07/16] . --- .../packages/ui-core/src/asset-graph/Utils.tsx | 2 +- .../src/assets/AssetPartitionDetail.tsx | 4 ++-- .../packages/ui-core/src/assets/Stale.tsx | 18 +++++++++++++----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/Utils.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/Utils.tsx index 1bd830bd31a84..a8c8834dd7c70 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/Utils.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/Utils.tsx @@ -219,7 +219,7 @@ export const buildLiveDataForNode = ( return { lastMaterialization, - changedReasons: [], + changedReasons: assetNode.changedReasons, lastMaterializationRunStatus: latestRunForAsset && lastMaterialization?.runId === latestRunForAsset?.id ? latestRunForAsset.status diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx index 36cf565226e0a..52a7ae696abfc 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx @@ -249,12 +249,12 @@ export const AssetPartitionDetail = ({ ) : undefined} {hasStaleLoadingState ? ( - ) : staleCauses && staleStatus ? ( + ) : ( - ) : undefined} + )}
) : ( No partition selected diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx index 9f97c905e0493..84ecf13aca957 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx @@ -23,7 +23,9 @@ import {AssetNodeKeyFragment} from '../asset-graph/types/AssetNode.types'; import {AssetKeyInput, ChangeReason, StaleCauseCategory, StaleStatus} from '../graphql/types'; import {numberFormatter} from '../ui/formatters'; -type StaleDataForNode = Pick; +type StaleDataForNode = Partial< + Pick +>; export const isAssetMissing = (liveData?: Pick) => liveData && liveData.staleStatus === StaleStatus.MISSING; @@ -77,7 +79,7 @@ export const StaleReasonsLabel = ({ include: 'all' | 'upstream' | 'self'; liveData?: StaleDataForNode; }) => { - if (!isAssetStale(liveData) || !liveData?.staleCauses.length) { + if (!isAssetStale(liveData) || !liveData?.staleCauses?.length) { return null; } @@ -109,7 +111,7 @@ export const StaleReasonsTag = ({ onClick?: () => void; }) => { const staleTag = useMemo(() => { - if (!isAssetStale(liveData) || !liveData?.staleCauses.length) { + if (!isAssetStale(liveData) || !liveData?.staleCauses?.length) { return
; } const label = ( @@ -183,7 +185,7 @@ const StaleCausesPopoverSummary = ({ include: 'all' | 'upstream' | 'self'; }) => { const grouped = groupedCauses(assetKey, include, liveData); - const totalCauses = liveData?.staleCauses.length; + const totalCauses = liveData?.staleCauses?.length; if (!totalCauses) { // Should never happen since the parent of this component should check that the asset is stale before rendering the popover @@ -210,7 +212,12 @@ const StaleCausesPopoverSummary = ({ {causes.map((cause, idx) => ( - + ))} ); @@ -223,6 +230,7 @@ const StaleReason = ({ reason, dependency, }: { + assetKey: AssetKeyInput; reason: string; dependency: AssetNodeKeyFragment | null; }) => { From 6c5ce25ec147f4db4d372390fd36679e0ef2c4ae Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Wed, 6 Mar 2024 11:19:28 -0500 Subject: [PATCH 08/16] minimal asset node dots --- .../ui-core/src/asset-graph/AssetNode.tsx | 48 ++++++++++++++++++- .../packages/ui-core/src/assets/Stale.tsx | 10 ++-- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx index 2da858adfd9db..863f3c9c9e47b 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx @@ -15,7 +15,7 @@ import {AssetNodeFragment} from './types/AssetNode.types'; import {withMiddleTruncation} from '../app/Util'; import {useAssetLiveData} from '../asset-data/AssetLiveDataProvider'; import {PartitionCountTags} from '../assets/AssetNodePartitionCounts'; -import {StaleReasonsTag} from '../assets/Stale'; +import {StaleReasonsTag, isAssetStale} from '../assets/Stale'; import {AssetChecksStatusSummary} from '../assets/asset-checks/AssetChecksStatusSummary'; import {assetDetailsPathForKey} from '../assets/assetDetailsPathForKey'; import {AssetComputeKindTag} from '../graph/OpTags'; @@ -169,6 +169,9 @@ export const AssetNodeMinimal = ({ const {border, background} = buildAssetNodeStatusContent({assetKey, definition, liveData}); const displayName = assetKey.path[assetKey.path.length - 1]!; + const isChanged = liveData?.changedReasons?.length; + const isStale = isAssetStale(liveData); + return ( @@ -184,6 +187,8 @@ export const AssetNodeMinimal = ({ $background={background} $border={border} > + {isChanged ? : null} + {isStale ? : null} @@ -357,3 +362,44 @@ export const AssetDescription = styled.div<{$color: string}>` const TooltipStyled = styled(Tooltip)` height: 100%; `; + +const MinimalNodeChangedDot = styled.div` + position: absolute; + right: 6px; + top: 6px; + height: 20px; + width: 20px; + border-radius: 50%; + background-color: ${Colors.backgroundCyan()}; + &:after { + display: block; + position: absolute; + content: ' '; + left: 5px; + top: 5px; + height: 10px; + width: 10px; + border-radius: 50%; + background-color: ${Colors.accentCyan()}; + } +`; +const MinimalNodeStaleDot = styled.div` + position: absolute; + left: 6px; + top: 6px; + height: 20px; + width: 20px; + border-radius: 50%; + background-color: ${Colors.backgroundYellow()}; + &:after { + display: block; + position: absolute; + content: ' '; + left: 5px; + top: 5px; + height: 10px; + width: 10px; + border-radius: 50%; + background-color: ${Colors.accentYellow()}; + } +`; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx index 84ecf13aca957..85e07c8468155 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx @@ -153,8 +153,8 @@ export const StaleReasonsTag = ({ style={{height: 24}} > {staleTag} - {isNew ? ( - + {liveData?.changedReasons?.length ? ( + ) : null} ); @@ -262,6 +262,7 @@ const StaleReason = ({ ); }, [dependency, reason]); + return ( @@ -324,7 +326,7 @@ export const NewInBranchTag = ({ } /> From 16bf8519a06dbe2eaeb4caaa0a851df9bd2b8381 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Wed, 6 Mar 2024 11:26:01 -0500 Subject: [PATCH 09/16] modified; --- js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx index 85e07c8468155..37a9cd699f649 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx @@ -326,7 +326,7 @@ export const NewOrChangedInBranchTag = ({ } /> From 3db3f59ac59ef3f3df6a16c874f63a545da3ad53 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Wed, 6 Mar 2024 13:01:40 -0500 Subject: [PATCH 10/16] popover on dot hover --- .../ui-core/src/asset-graph/AssetNode.tsx | 53 +----- .../src/assets/AssetPartitionDetail.tsx | 9 +- .../packages/ui-core/src/assets/AssetView.tsx | 41 +++-- .../ui-core/src/assets/ChangedReasons.tsx | 129 ++++++++++++++ .../assets/LastMaterializationMetadata.tsx | 11 +- .../packages/ui-core/src/assets/Stale.tsx | 163 ++++++++---------- 6 files changed, 252 insertions(+), 154 deletions(-) create mode 100644 js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx index 863f3c9c9e47b..f4c01c3a4a755 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx @@ -15,7 +15,8 @@ import {AssetNodeFragment} from './types/AssetNode.types'; import {withMiddleTruncation} from '../app/Util'; import {useAssetLiveData} from '../asset-data/AssetLiveDataProvider'; import {PartitionCountTags} from '../assets/AssetNodePartitionCounts'; -import {StaleReasonsTag, isAssetStale} from '../assets/Stale'; +import {MinimalNodeChangedDot} from '../assets/ChangedReasons'; +import {MinimalNodeStaleDot, StaleReasonsTag, isAssetStale} from '../assets/Stale'; import {AssetChecksStatusSummary} from '../assets/asset-checks/AssetChecksStatusSummary'; import {assetDetailsPathForKey} from '../assets/assetDetailsPathForKey'; import {AssetComputeKindTag} from '../graph/OpTags'; @@ -187,8 +188,13 @@ export const AssetNodeMinimal = ({ $background={background} $border={border} > - {isChanged ? : null} - {isStale ? : null} + {isChanged ? ( + + ) : null} + {isStale ? : null} @@ -362,44 +368,3 @@ export const AssetDescription = styled.div<{$color: string}>` const TooltipStyled = styled(Tooltip)` height: 100%; `; - -const MinimalNodeChangedDot = styled.div` - position: absolute; - right: 6px; - top: 6px; - height: 20px; - width: 20px; - border-radius: 50%; - background-color: ${Colors.backgroundCyan()}; - &:after { - display: block; - position: absolute; - content: ' '; - left: 5px; - top: 5px; - height: 10px; - width: 10px; - border-radius: 50%; - background-color: ${Colors.accentCyan()}; - } -`; -const MinimalNodeStaleDot = styled.div` - position: absolute; - left: 6px; - top: 6px; - height: 20px; - width: 20px; - border-radius: 50%; - background-color: ${Colors.backgroundYellow()}; - &:after { - display: block; - position: absolute; - content: ' '; - left: 5px; - top: 5px; - height: 10px; - width: 10px; - border-radius: 50%; - background-color: ${Colors.accentYellow()}; - } -`; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx index 52a7ae696abfc..2ac275e37102e 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx @@ -19,6 +19,7 @@ import {AllIndividualEventsButton} from './AllIndividualEventsButton'; import {AssetEventMetadataEntriesTable} from './AssetEventMetadataEntriesTable'; import {AssetEventSystemTags} from './AssetEventSystemTags'; import {AssetMaterializationUpstreamData} from './AssetMaterializationUpstreamData'; +import {ChangedReasonsTag} from './ChangedReasons'; import {FailedRunSinceMaterializationBanner} from './FailedRunSinceMaterializationBanner'; import {StaleReasonsTag} from './Stale'; import {AssetEventGroup} from './groupByPartition'; @@ -250,10 +251,10 @@ export const AssetPartitionDetail = ({ {hasStaleLoadingState ? ( ) : ( - + <> + + + )}
) : ( diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetView.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetView.tsx index 88de74ae54c48..b90ab13b1fb8a 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetView.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetView.tsx @@ -21,6 +21,7 @@ import {AssetAutomaterializePolicyPage} from './AutoMaterializePolicyPage/AssetA import {AssetAutomaterializePolicyPageOld} from './AutoMaterializePolicyPageOld/AssetAutomaterializePolicyPage'; import {useAutoMaterializeSensorFlag} from './AutoMaterializeSensorFlag'; import {AutomaterializeDaemonStatusTag} from './AutomaterializeDaemonStatusTag'; +import {ChangedReasonsTag} from './ChangedReasons'; import {LaunchAssetExecutionButton} from './LaunchAssetExecutionButton'; import {LaunchAssetObservationButton} from './LaunchAssetObservationButton'; import {OverdueTag} from './OverdueTag'; @@ -526,11 +527,17 @@ const AssetViewPageHeaderTags = ({ return ( <> {definition ? ( - + <> + + + ) : null} {definition?.isSource ? ( Source Asset @@ -566,16 +573,20 @@ const AssetViewPageHeaderTags = ({ {definition && definition.freshnessPolicy && ( )} - {definition && ( - - )} - {definition && ( - - )} + {definition ? ( + <> + + + + + ) : null} ); }; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx new file mode 100644 index 0000000000000..99532a9419f74 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx @@ -0,0 +1,129 @@ +import { + BaseTag, + Box, + Colors, + Icon, + Popover, + Subtitle2, + Tag, + ifPlural, +} from '@dagster-io/ui-components'; +import styled from 'styled-components'; + +import {displayNameForAssetKey} from '../asset-graph/Utils'; +import {AssetKeyInput, ChangeReason} from '../graphql/types'; +import {numberFormatter} from '../ui/formatters'; + +export const ChangedReasonsTag = ({ + changedReasons, + assetKey, +}: { + changedReasons?: ChangeReason[]; + assetKey: AssetKeyInput; +}) => { + if (!changedReasons) { + return null; + } + return ( + + } + /> + + ); +}; + +export const ChangedReasonsPopover = ({ + changedReasons, + assetKey, + children, +}: { + changedReasons: ChangeReason[]; + assetKey: AssetKeyInput; + children: React.ReactNode; +}) => { + const modifiedChanges = changedReasons.filter((reason) => reason !== ChangeReason.NEW); + function getDescription(change: ChangeReason) { + switch (change) { + case ChangeReason.NEW: + return ''; + case ChangeReason.CODE_VERSION: + return 'has a modified code version'; + case ChangeReason.INPUTS: + return 'has modified dependencies'; + case ChangeReason.PARTITIONS_DEFINITION: + return 'has a modified partition definition'; + } + } + return ( + + + + {numberFormatter.format(modifiedChanges.length)}{' '} + {ifPlural(modifiedChanges.length, 'change', 'changes')} in this branch + + + {modifiedChanges.map((change) => { + return ( + + {displayNameForAssetKey(assetKey)} + {getDescription(change)} + + ); + })} + + } + interactionKind="hover" + className="chunk-popover-target" + > + {children} + + ); +}; + +export const MinimalNodeChangedDot = ({ + changedReasons, + assetKey, +}: { + changedReasons: ChangeReason[]; + assetKey: AssetKeyInput; +}) => { + return ( + + + + ); +}; + +const MinimalNodeChangedDotContainer = styled.div` + position: absolute; + right: 6px; + top: 6px; + height: 20px; + width: 20px; + border-radius: 50%; + background-color: ${Colors.backgroundCyan()}; + &:after { + display: block; + position: absolute; + content: ' '; + left: 5px; + top: 5px; + height: 10px; + width: 10px; + border-radius: 50%; + background-color: ${Colors.accentCyan()}; + } +`; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/LastMaterializationMetadata.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/LastMaterializationMetadata.tsx index b72b1e1016bcf..954017e59a5e1 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/LastMaterializationMetadata.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/LastMaterializationMetadata.tsx @@ -3,6 +3,7 @@ import {Link} from 'react-router-dom'; import styled from 'styled-components'; import {AssetLineageElements} from './AssetLineageElements'; +import {ChangedReasonsTag} from './ChangedReasons'; import {StaleReasonsTag} from './Stale'; import {isRunlessEvent} from './isRunlessEvent'; import { @@ -117,7 +118,15 @@ export const LatestMaterializationMetadata = ({ - {liveData && } + {liveData && ( + <> + + + + )} diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx index 37a9cd699f649..27a87e22496bd 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx @@ -14,19 +14,21 @@ import { } from '@dagster-io/ui-components'; import groupBy from 'lodash/groupBy'; import isEqual from 'lodash/isEqual'; -import {useMemo} from 'react'; +import React, {useMemo} from 'react'; import {Link} from 'react-router-dom'; +import styled from 'styled-components'; import {assetDetailsPathForKey} from './assetDetailsPathForKey'; import {LiveDataForNode, displayNameForAssetKey} from '../asset-graph/Utils'; import {AssetNodeKeyFragment} from '../asset-graph/types/AssetNode.types'; -import {AssetKeyInput, ChangeReason, StaleCauseCategory, StaleStatus} from '../graphql/types'; +import {AssetKeyInput, StaleCauseCategory, StaleStatus} from '../graphql/types'; import {numberFormatter} from '../ui/formatters'; -type StaleDataForNode = Partial< - Pick ->; - +type StaleDataForNode = { + staleCauses?: LiveDataForNode['staleCauses']; + staleStatus?: LiveDataForNode['staleStatus']; + changedReasons?: LiveDataForNode['changedReasons']; +}; export const isAssetMissing = (liveData?: Pick) => liveData && liveData.staleStatus === StaleStatus.MISSING; @@ -99,6 +101,7 @@ export const StaleReasonsLabel = ({ ); }; +// Includes the cha export const StaleReasonsTag = ({ assetKey, liveData, @@ -110,22 +113,17 @@ export const StaleReasonsTag = ({ include?: 'all' | 'upstream' | 'self'; onClick?: () => void; }) => { - const staleTag = useMemo(() => { - if (!isAssetStale(liveData) || !liveData?.staleCauses?.length) { - return
; - } - const label = ( - Outdated ({numberFormatter.format(liveData.staleCauses.length)}) - ); - return ( - - } - position="top" - interactionKind="hover" - className="chunk-popover-target" - > + if (!isAssetStale(liveData) || !liveData?.staleCauses?.length) { + return
; + } + const label = Outdated ({numberFormatter.format(liveData.staleCauses.length)}); + return ( + + - - ); - }, [assetKey, include, liveData, onClick]); - - const isNew = liveData?.changedReasons?.includes(ChangeReason.NEW); + + + ); +}; +export const StaleCausesPopover = ({ + liveData, + assetKey, + include, + children, +}: { + assetKey: AssetKeyInput; + liveData?: StaleDataForNode; + include?: 'all' | 'upstream' | 'self'; + children: React.ReactNode; +}) => { return ( - + } + position="top-left" + interactionKind="hover" + className="chunk-popover-target" > - {staleTag} - {liveData?.changedReasons?.length ? ( - - ) : null} - + {children} + ); }; @@ -178,11 +186,11 @@ function groupedCauses( const StaleCausesPopoverSummary = ({ assetKey, liveData, - include, + include = 'all', }: { assetKey: AssetKeyInput; liveData?: StaleDataForNode; - include: 'all' | 'upstream' | 'self'; + include?: 'all' | 'upstream' | 'self'; }) => { const grouped = groupedCauses(assetKey, include, liveData); const totalCauses = liveData?.staleCauses?.length; @@ -273,62 +281,37 @@ const StaleReason = ({ ); }; -export const NewOrChangedInBranchTag = ({ - changedReasons, +export const MinimalNodeStaleDot = ({ + liveData, assetKey, }: { - changedReasons: ChangeReason[]; + liveData?: StaleDataForNode; assetKey: AssetKeyInput; }) => { - const changes = changedReasons.filter((reason) => reason !== ChangeReason.NEW); - - function getDescription(change: ChangeReason) { - switch (change) { - case ChangeReason.NEW: - return ''; - case ChangeReason.CODE_VERSION: - return 'has a modified code version'; - case ChangeReason.INPUTS: - return 'has modified dependencies'; - case ChangeReason.PARTITIONS_DEFINITION: - return 'has a modified partition definition'; - } - } return ( - - - - {numberFormatter.format(changes.length)}{' '} - {ifPlural(changes.length, 'change', 'changes')} in this branch - - - {changes.map((change) => { - return ( - - {displayNameForAssetKey(assetKey)} - {getDescription(change)} - - ); - })} - - } - interactionKind="hover" - className="chunk-popover-target" - > - } - /> - + + + ); }; + +const MinimalNodeStaleDotElement = styled.div` + position: absolute; + left: 6px; + top: 6px; + height: 20px; + width: 20px; + border-radius: 50%; + background-color: ${Colors.backgroundYellow()}; + &:after { + display: block; + position: absolute; + content: ' '; + left: 5px; + top: 5px; + height: 10px; + width: 10px; + border-radius: 50%; + background-color: ${Colors.accentYellow()}; + } +`; From 5cd746bbf21a422e4b46ec032364b6dbc4ee4539 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Wed, 6 Mar 2024 13:18:17 -0500 Subject: [PATCH 11/16] feedback --- .../ui-core/src/asset-graph/AssetNode.tsx | 4 +- .../packages/ui-core/src/assets/Stale.tsx | 62 +++++++++---------- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx index f4c01c3a4a755..e5eb84acc6a74 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx @@ -194,7 +194,9 @@ export const AssetNodeMinimal = ({ assetKey={assetKey} /> ) : null} - {isStale ? : null} + {isStale ? ( + + ) : null} diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx index 27a87e22496bd..ade109d3ab732 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/Stale.tsx @@ -14,7 +14,7 @@ import { } from '@dagster-io/ui-components'; import groupBy from 'lodash/groupBy'; import isEqual from 'lodash/isEqual'; -import React, {useMemo} from 'react'; +import React from 'react'; import {Link} from 'react-router-dom'; import styled from 'styled-components'; @@ -220,12 +220,17 @@ const StaleCausesPopoverSummary = ({ {causes.map((cause, idx) => ( - + > + + ))} ); @@ -242,54 +247,45 @@ const StaleReason = ({ reason: string; dependency: AssetNodeKeyFragment | null; }) => { - const content = useMemo(() => { - if (!dependency) { - return {` ${reason}`}; - } - - const dependencyName = displayNameForAssetKey(dependency); - const dependencyPythonName = dependencyName.replace(/ /g, ''); - if (reason.endsWith(`${dependencyPythonName}`)) { - const reasonUpToDep = reason.slice(0, -dependencyPythonName.length); - return ( - <> - {reasonUpToDep} - - {dependencyName} - - - ); - } + if (!dependency) { + return {` ${reason}`}; + } + const dependencyName = displayNameForAssetKey(dependency); + const dependencyPythonName = dependencyName.replace(/ /g, ''); + if (reason.endsWith(`${dependencyPythonName}`)) { + const reasonUpToDep = reason.slice(0, -dependencyPythonName.length); return ( <> + {reasonUpToDep} {dependencyName} - {` ${reason} `} ); - }, [dependency, reason]); + } return ( - - {content} - + <> + + {dependencyName} + + {` ${reason} `} + ); }; export const MinimalNodeStaleDot = ({ liveData, assetKey, + include = 'all', }: { liveData?: StaleDataForNode; assetKey: AssetKeyInput; + include?: 'all' | 'upstream' | 'self'; }) => { return ( - + ); From ce01ed2eb898490690f8fd8926751b0df6d7c903 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Wed, 6 Mar 2024 13:19:50 -0500 Subject: [PATCH 12/16] upstream --- .../dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx index e5eb84acc6a74..d99508f585495 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx @@ -35,7 +35,7 @@ export const AssetNode = React.memo(({definition, selected}: Props) => { return ( - + From 775d7663d6dfbf5d8d59e83d2c7d8ed9aa3c3525 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Wed, 6 Mar 2024 13:25:56 -0500 Subject: [PATCH 13/16] spacing --- .../packages/ui-core/src/asset-graph/AssetNode.tsx | 10 ++++++++-- .../ui-core/src/assets/AssetPartitionDetail.tsx | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx index d99508f585495..984716e2f6cfb 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/AssetNode.tsx @@ -15,7 +15,7 @@ import {AssetNodeFragment} from './types/AssetNode.types'; import {withMiddleTruncation} from '../app/Util'; import {useAssetLiveData} from '../asset-data/AssetLiveDataProvider'; import {PartitionCountTags} from '../assets/AssetNodePartitionCounts'; -import {MinimalNodeChangedDot} from '../assets/ChangedReasons'; +import {ChangedReasonsTag, MinimalNodeChangedDot} from '../assets/ChangedReasons'; import {MinimalNodeStaleDot, StaleReasonsTag, isAssetStale} from '../assets/Stale'; import {AssetChecksStatusSummary} from '../assets/asset-checks/AssetChecksStatusSummary'; import {assetDetailsPathForKey} from '../assets/assetDetailsPathForKey'; @@ -35,7 +35,13 @@ export const AssetNode = React.memo(({definition, selected}: Props) => { return ( - + + + + diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx index 2ac275e37102e..af8de7ff2d44e 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetPartitionDetail.tsx @@ -251,10 +251,10 @@ export const AssetPartitionDetail = ({ {hasStaleLoadingState ? ( ) : ( - <> + - + )}
) : ( From 0ab225b86906d9d5d5d122f88627667badd362ca Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Wed, 6 Mar 2024 13:38:42 -0500 Subject: [PATCH 14/16] sofar --- .../ui-core/src/assets/ChangedReasons.tsx | 1 + .../packages/ui-core/src/assets/Stale.tsx | 26 ++++++++----------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx index 99532a9419f74..009b742b1df4e 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx @@ -24,6 +24,7 @@ export const ChangedReasonsTag = ({ if (!changedReasons) { return null; } + console.log({changedReasons}); return ( - + ))} @@ -239,16 +234,17 @@ const StaleCausesPopoverSummary = ({ ); }; -const StaleReason = ({ - reason, - dependency, -}: { - assetKey: AssetKeyInput; - reason: string; - dependency: AssetNodeKeyFragment | null; -}) => { +const StaleReason = ({cause}: {cause: NonNullable[0]}) => { + const {dependency, reason, key} = cause; if (!dependency) { - return {` ${reason}`}; + return ( + <> + + {displayNameForAssetKey(key)} + + {` ${reason}`} + + ); } const dependencyName = displayNameForAssetKey(dependency); From 30e37410ec59c4572f7f534bbfd2991a0e1b4380 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Wed, 6 Mar 2024 13:39:20 -0500 Subject: [PATCH 15/16] check .length --- .../dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx index 009b742b1df4e..b42a897075aed 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx @@ -21,10 +21,9 @@ export const ChangedReasonsTag = ({ changedReasons?: ChangeReason[]; assetKey: AssetKeyInput; }) => { - if (!changedReasons) { + if (!changedReasons?.length) { return null; } - console.log({changedReasons}); return ( Date: Wed, 6 Mar 2024 15:24:25 -0500 Subject: [PATCH 16/16] add feature gate --- .../dagster-ui/packages/ui-core/src/app/Flags.tsx | 1 + .../packages/ui-core/src/assets/ChangedReasons.tsx | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/app/Flags.tsx b/js_modules/dagster-ui/packages/ui-core/src/app/Flags.tsx index c0002a922d86a..2fc2910941675 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/app/Flags.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/app/Flags.tsx @@ -13,6 +13,7 @@ export const FeatureFlag = { flagDisableAutoLoadDefaults: 'flagDisableAutoLoadDefaults' as const, flagUseNewAutomationPage: 'flagUseNewAutomationPage' as const, flagUseNewOverviewPage: 'flagUseNewOverviewPage' as const, + flagExperimentalBranchDiff: 'flagExperimentalBranchDiff' as const, }; export type FeatureFlagType = keyof typeof FeatureFlag; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx index b42a897075aed..35f1584a66b94 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/ChangedReasons.tsx @@ -10,6 +10,7 @@ import { } from '@dagster-io/ui-components'; import styled from 'styled-components'; +import {FeatureFlag, featureEnabled} from '../app/Flags'; import {displayNameForAssetKey} from '../asset-graph/Utils'; import {AssetKeyInput, ChangeReason} from '../graphql/types'; import {numberFormatter} from '../ui/formatters'; @@ -21,7 +22,8 @@ export const ChangedReasonsTag = ({ changedReasons?: ChangeReason[]; assetKey: AssetKeyInput; }) => { - if (!changedReasons?.length) { + const flagExperimentalBranchDiff = featureEnabled(FeatureFlag.flagExperimentalBranchDiff); + if (!changedReasons?.length || !flagExperimentalBranchDiff) { return null; } return ( @@ -45,6 +47,10 @@ export const ChangedReasonsPopover = ({ assetKey: AssetKeyInput; children: React.ReactNode; }) => { + const flagExperimentalBranchDiff = featureEnabled(FeatureFlag.flagExperimentalBranchDiff); + if (!flagExperimentalBranchDiff) { + return null; + } const modifiedChanges = changedReasons.filter((reason) => reason !== ChangeReason.NEW); function getDescription(change: ChangeReason) { switch (change) { @@ -100,6 +106,10 @@ export const MinimalNodeChangedDot = ({ changedReasons: ChangeReason[]; assetKey: AssetKeyInput; }) => { + const flagExperimentalBranchDiff = featureEnabled(FeatureFlag.flagExperimentalBranchDiff); + if (!flagExperimentalBranchDiff) { + return null; + } return (