Skip to content

Commit

Permalink
[ui] Make asset overview show metadata, schema of latest event, not “…
Browse files Browse the repository at this point in the history
…latest partition or null" (#28174)

## Summary & Motivation

Fixes
https://linear.app/dagster-labs/issue/FE-589/metadata-plots-only-work-in-asset-catalog-when-most-recent-partition,
#24600


![image](https://github.com/user-attachments/assets/fe35cfca-dd56-4123-8c9e-2db2a12d2a4a)

It was flagged by a user that the new Asset Overview page shows the
metadata and schema for the most recent PARTITION, or empty states if
that partition is not present. This is somewhat confusing because these
sections can render empty while the tag at the top still shows the
latest event. (Screenshot above)

I think at some point the tag at the top of the page was also restricted
to showing the latest partition, so this made sense. However, it seems
problematic because for any daily partitioned asset, it is missing for
some portion of the day and all the information disappears for that
period.

The fix in this PR is just to make the metadata + schema portions of the
page use the latest event, even if it's not for a recent / today's
partition. This could have slightly undesirable behavior during
backfills (eg: showing you metadata for an older partition), but means
that the materialization in the green pill and the materialization used
for these sections is always the same.

## How I Tested These Changes

Tested with a manual repro

## Changelog

[ui] The asset overview tab for a partitioned asset now shows metadata
and schema of the most recent materialization, not today's partition.

---------

Co-authored-by: bengotow <[email protected]>
  • Loading branch information
bengotow and bengotow authored Mar 4, 2025
1 parent 0a451cc commit 7d47ab7
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 46 deletions.
2 changes: 1 addition & 1 deletion js_modules/dagster-ui/packages/ui-core/client.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ type Props = {
loading: boolean;
};

export const RecentUpdatesTimelineForAssetKey = (props: {assetKey: AssetKey}) => {
const data = useRecentAssetEvents(props.assetKey, {}, {assetHasDefinedPartitions: false});
return <RecentUpdatesTimeline assetKey={props.assetKey} {...data} />;
};

export const RecentUpdatesTimeline = ({
assetKey,
observations,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// eslint-disable-next-line no-restricted-imports
import {Box, Caption, Colors, Tag} from '@dagster-io/ui-components';
import React from 'react';
import {Link} from 'react-router-dom';

import {MaterializationTag} from './MaterializationTag';
import {Timestamp} from '../app/time/Timestamp';
Expand All @@ -18,9 +19,11 @@ import {AssetViewDefinitionNodeFragment} from './types/AssetView.types';
export const SimpleStakeholderAssetStatus = ({
liveData,
assetNode,
partition,
}: {
liveData: LiveDataForNode | undefined;
assetNode: Pick<AssetViewDefinitionNodeFragment, 'assetKey' | 'isObservable'>;
partition: string | null;
}) => {
if (!liveData) {
return <span />;
Expand Down Expand Up @@ -53,20 +56,34 @@ export const SimpleStakeholderAssetStatus = ({
</Tag>
);
}
const partitionTag = partition ? (
<Tag intent="none">
<Link to={`?view=partitions&partition=${encodeURIComponent(partition)}`}>
<Caption color={Colors.textDefault()}>{partition}</Caption>
</Link>
</Tag>
) : undefined;

if (liveData.lastMaterialization) {
return (
<MaterializationTag
assetKey={assetNode.assetKey}
event={liveData.lastMaterialization}
stepKey={liveData.stepKey}
/>
<Box flex={{gap: 4}}>
<MaterializationTag
assetKey={assetNode.assetKey}
event={liveData.lastMaterialization}
stepKey={liveData.stepKey}
/>
{partitionTag}
</Box>
);
}
if (liveData.lastObservation && assetNode.isObservable) {
return (
<Tag intent="none">
<Timestamp timestamp={{ms: Number(liveData.lastObservation.timestamp)}} />
</Tag>
<Box flex={{gap: 4}}>
<Tag intent="none">
<Timestamp timestamp={{ms: Number(liveData.lastObservation.timestamp)}} />
</Tag>
{partitionTag}
</Box>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,15 @@ import {buildRepoAddress} from '../../workspace/buildRepoAddress';
import {LargeCollapsibleSection} from '../LargeCollapsibleSection';
import {MaterializationTag} from '../MaterializationTag';
import {OverdueTag} from '../OverdueTag';
import {RecentUpdatesTimeline} from '../RecentUpdatesTimeline';
import {RecentUpdatesTimelineForAssetKey} from '../RecentUpdatesTimeline';
import {SimpleStakeholderAssetStatus} from '../SimpleStakeholderAssetStatus';
import {AssetChecksStatusSummary} from '../asset-checks/AssetChecksStatusSummary';
import {buildConsolidatedColumnSchema} from '../buildConsolidatedColumnSchema';
import {globalAssetGraphPathForAssetsAndDescendants} from '../globalAssetGraphPathToString';
import {AssetKey} from '../types';
import {AssetTableDefinitionFragment} from '../types/AssetTableFragment.types';
import {AssetViewDefinitionNodeFragment} from '../types/AssetView.types';
import {useLatestPartitionEvents} from '../useLatestPartitionEvents';
import {useRecentAssetEvents} from '../useRecentAssetEvents';
import {useLatestEvents} from '../useLatestEvents';

export const AssetNodeOverview = ({
assetKey,
Expand Down Expand Up @@ -72,22 +71,12 @@ export const AssetNodeOverview = ({

const assetNodeLoadTimestamp = location ? location.updatedTimestamp * 1000 : undefined;

const {materialization, observation, loading} = useLatestPartitionEvents(
const {materialization, observation, loading} = useLatestEvents(
assetKey,
assetNodeLoadTimestamp,
liveData,
);

const {
materializations,
observations,
loading: materializationsLoading,
} = useRecentAssetEvents(
cachedOrLiveAssetNode?.partitionDefinition ? undefined : cachedOrLiveAssetNode?.assetKey,
{},
{assetHasDefinedPartitions: false},
);

// Start loading neighboring assets data immediately to avoid waterfall.
useAssetsLiveData(
useMemo(
Expand All @@ -113,6 +102,13 @@ export const AssetNodeOverview = ({
(entry) => isCanonicalRowCountMetadataEntry(entry),
) as IntMetadataEntry | undefined;

// The live data does not include a partition, but the timestamp on the live data triggers
// an update of `observation` and `materialization`, so they should be in sync. To make sure
// we never display incorrect data we verify that the timestamps match.
const liveDataPartition = assetNode?.isObservable
? partitionIfMatching(liveData?.lastObservation, observation)
: partitionIfMatching(liveData?.lastMaterialization, materialization);

const renderStatusSection = () => (
<Box flex={{direction: 'column', gap: 16}}>
<Box style={{display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))'}}>
Expand All @@ -124,6 +120,7 @@ export const AssetNodeOverview = ({
{liveData ? (
<SimpleStakeholderAssetStatus
liveData={liveData}
partition={liveDataPartition}
assetNode={assetNode ?? cachedAssetNode!}
/>
) : (
Expand Down Expand Up @@ -154,12 +151,7 @@ export const AssetNodeOverview = ({
) : undefined}
</Box>
{cachedOrLiveAssetNode.isPartitioned ? null : (
<RecentUpdatesTimeline
materializations={materializations}
observations={observations}
assetKey={cachedOrLiveAssetNode.assetKey}
loading={materializationsLoading}
/>
<RecentUpdatesTimelineForAssetKey assetKey={cachedOrLiveAssetNode.assetKey} />
)}
</Box>
);
Expand Down Expand Up @@ -305,12 +297,6 @@ export const AssetNodeOverviewNonSDA = ({
assetKey: AssetKey;
lastMaterialization: {timestamp: string; runId: string} | null | undefined;
}) => {
const {materializations, observations, loading} = useRecentAssetEvents(
assetKey,
{},
{assetHasDefinedPartitions: false},
);

return (
<AssetNodeOverviewContainer
left={
Expand All @@ -327,12 +313,7 @@ export const AssetNodeOverviewNonSDA = ({
<Caption color={Colors.textLighter()}>Never materialized</Caption>
)}
</div>
<RecentUpdatesTimeline
materializations={materializations}
observations={observations}
assetKey={assetKey}
loading={loading}
/>
<RecentUpdatesTimelineForAssetKey assetKey={assetKey} />
</Box>
</LargeCollapsibleSection>
}
Expand Down Expand Up @@ -388,3 +369,13 @@ export const AssetNodeOverviewLoading = () => (
}
/>
);

function partitionIfMatching(
liveDataEvent: {timestamp: string} | null | undefined,
event: {timestamp: string; partition: string | null} | undefined,
) {
if (!liveDataEvent || !event) {
return null;
}
return liveDataEvent.timestamp === event.timestamp ? event.partition : null;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import {gql, useQuery} from '../apollo-client';
import {
AssetOverviewMetadataEventsQuery,
AssetOverviewMetadataEventsQueryVariables,
} from './types/useLatestPartitionEvents.types';
} from './types/useLatestEvents.types';
import {LiveDataForNode} from '../asset-graph/Utils';
import {usePredicateChangeSignal} from '../hooks/usePredicateChangeSignal';
import {METADATA_ENTRY_FRAGMENT} from '../metadata/MetadataEntryFragment';

export function useLatestPartitionEvents(
export function useLatestEvents(
assetKey: AssetKey,
assetNodeLoadTimestamp: number | undefined,
liveData: LiveDataForNode | undefined,
Expand Down Expand Up @@ -66,16 +66,18 @@ export const ASSET_OVERVIEW_METADATA_EVENTS_QUERY = gql`
assetOrError(assetKey: $assetKey) {
... on Asset {
id
assetMaterializations(limit: 1, partitionInLast: 1) {
assetMaterializations(limit: 1) {
timestamp
runId
partition
metadataEntries {
...MetadataEntryFragment
}
}
assetObservations(limit: 1, partitionInLast: 1) {
assetObservations(limit: 1) {
timestamp
runId
partition
metadataEntries {
...MetadataEntryFragment
}
Expand Down

1 comment on commit 7d47ab7

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for dagit-core-storybook ready!

✅ Preview
https://dagit-core-storybook-po2ze7k3v-elementl.vercel.app

Built with commit 7d47ab7.
This pull request is being automatically deployed with vercel-action

Please sign in to comment.