Skip to content

Commit

Permalink
[UI] Dynamic partition creation and selection (#12615)
Browse files Browse the repository at this point in the history
### Summary & Motivation

Adds the ability to create dynamic partitions
<img width="794" alt="Screen Shot 2023-03-01 at 7 23 20 AM"
src="https://user-images.githubusercontent.com/2286579/222138339-716a15b4-b9e9-417a-a572-e63dd5cd6140.png">


<img width="814" alt="Screen Shot 2023-03-01 at 7 24 22 AM"
src="https://user-images.githubusercontent.com/2286579/222138548-806cb4cf-af71-417f-ac4f-c1e157122747.png">


<img width="896" alt="Screen Shot 2023-03-01 at 7 23 24 AM"
src="https://user-images.githubusercontent.com/2286579/222138432-d0e720d1-7479-4d19-8a5f-64708cef86bb.png">





### How I Tested These Changes

I tested this with `dagit dev` and also in `storybook`. I need to spend
some time digging through this some more to setup tests

---------

Co-authored-by: bengotow <bgotow@elementl.com>
  • Loading branch information
salazarm and bengotow committed Mar 1, 2023
1 parent dab3831 commit 122d46e
Show file tree
Hide file tree
Showing 7 changed files with 455 additions and 39 deletions.
Expand Up @@ -106,7 +106,7 @@ export const AssetPartitionList: React.FC<AssetPartitionListProps> = ({
);
};

const StateDot = ({state}: {state: PartitionState}) => (
export const StateDot = ({state}: {state: PartitionState}) => (
<div
key={state}
style={{
Expand Down
Expand Up @@ -24,7 +24,7 @@ import {usePermissionsForLocation} from '../app/Permissions';
import {PythonErrorInfo} from '../app/PythonErrorInfo';
import {displayNameForAssetKey, itemWithAssetKey} from '../asset-graph/Utils';
import {AssetKey} from '../assets/types';
import {LaunchBackfillParams} from '../graphql/types';
import {LaunchBackfillParams, PartitionDefinitionType} from '../graphql/types';
import {LAUNCH_PARTITION_BACKFILL_MUTATION} from '../instance/BackfillUtils';
import {
LaunchPartitionBackfillMutation,
Expand Down Expand Up @@ -83,14 +83,16 @@ interface Props {
partitionDefinition: PartitionDefinitionForLaunchAssetFragment | null;
}[];
upstreamAssetKeys: AssetKey[]; // single layer of upstream dependencies
refetch?: () => Promise<void>;
}

export const LaunchAssetChoosePartitionsDialog: React.FC<Props> = (props) => {
const title = `Launch runs to materialize ${
const displayName =
props.assets.length > 1
? `${props.assets.length} assets`
: displayNameForAssetKey(props.assets[0].assetKey)
}`;
: displayNameForAssetKey(props.assets[0].assetKey);

const title = `Launch runs to materialize ${displayName}`;

return (
<Dialog
Expand Down Expand Up @@ -119,6 +121,7 @@ const LaunchAssetChoosePartitionsDialogBody: React.FC<Props> = ({
repoAddress,
target,
upstreamAssetKeys,
refetch: _refetch,
}) => {
const partitionedAssets = assets.filter((a) => !!a.partitionDefinition);

Expand All @@ -130,7 +133,19 @@ const LaunchAssetChoosePartitionsDialogBody: React.FC<Props> = ({
const [previewCount, setPreviewCount] = React.useState(0);
const morePreviewsCount = partitionedAssets.length - previewCount;

const assetHealth = usePartitionHealthData(partitionedAssets.map((a) => a.assetKey));
const [lastRefresh, setLastRefresh] = React.useState(Date.now());

const refetch = async () => {
await _refetch?.();
setLastRefresh(Date.now());
};

const assetHealth = usePartitionHealthData(
partitionedAssets.map((a) => a.assetKey),
lastRefresh.toString(),
'immediate',
);

const assetHealthLoading = assetHealth.length === 0;

const displayedHealth = React.useMemo(() => {
Expand All @@ -147,6 +162,7 @@ const LaunchAssetChoosePartitionsDialogBody: React.FC<Props> = ({

const knownDimensions = partitionedAssets[0].partitionDefinition?.dimensionTypes || [];
const [missingOnly, setMissingOnly] = React.useState(true);

const [selections, setSelections] = usePartitionDimensionSelections({
knownDimensionNames: knownDimensions.map((d) => d.name),
modifyQueryString: false,
Expand Down Expand Up @@ -364,6 +380,7 @@ const LaunchAssetChoosePartitionsDialogBody: React.FC<Props> = ({
selections.length === 2 ? selections[1 - idx].selectedRanges : undefined,
),
}}
isDynamic={displayedPartitionDefinition?.type === PartitionDefinitionType.DYNAMIC}
selected={range.selectedKeys}
setSelected={(selectedKeys) =>
setSelections(
Expand All @@ -372,6 +389,9 @@ const LaunchAssetChoosePartitionsDialogBody: React.FC<Props> = ({
),
)
}
partitionDefinitionName={displayedPartitionDefinition?.name}
repoAddress={repoAddress}
refetch={refetch}
/>
))}

Expand Down
Expand Up @@ -317,6 +317,26 @@ export const useMaterializationAction = (preferredJobName?: string) => {
target={state.target}
open={true}
setOpen={() => setState({type: 'none'})}
refetch={async () => {
const result = await client.query<
LaunchAssetLoaderQuery,
LaunchAssetLoaderQueryVariables
>({
query: LAUNCH_ASSET_LOADER_QUERY,
variables: {assetKeys: state.assets.map(({assetKey}) => ({path: assetKey.path}))},
});
const assets = result.data.assetNodes;
const next = await stateForLaunchingAssets(client, assets, false, preferredJobName);
if (next.type === 'error') {
showCustomAlert({
title: 'Unable to Materialize',
body: next.error,
});
setState({type: 'none'});
return;
}
setState(next);
}}
/>
);
}
Expand Down
Expand Up @@ -436,17 +436,18 @@ function rangesCoverAll(ranges: Range[], keyCount: number) {
// a sign that we should invalidate and reload previously loaded health stats. We don't
// clear them immediately to avoid an empty state.
//
export function usePartitionHealthData(assetKeys: AssetKey[], assetLastMaterializedAt = '') {
export function usePartitionHealthData(
assetKeys: AssetKey[],
cacheKey = '',
cacheClearStrategy: 'immediate' | 'background' = 'background',
) {
const [result, setResult] = React.useState<(PartitionHealthData & {fetchedAt: string})[]>([]);
const client = useApolloClient();

const assetKeyJSONs = assetKeys.map((k) => JSON.stringify(k));
const assetKeyJSON = JSON.stringify(assetKeyJSONs);
const missingKeyJSON = assetKeyJSONs.find(
(k) =>
!result.some(
(r) => JSON.stringify(r.assetKey) === k && r.fetchedAt === assetLastMaterializedAt,
),
(k) => !result.some((r) => JSON.stringify(r.assetKey) === k && r.fetchedAt === cacheKey),
);

React.useMemo(() => {
Expand All @@ -465,16 +466,20 @@ export function usePartitionHealthData(assetKeys: AssetKey[], assetLastMateriali
const loaded = buildPartitionHealthData(data, loadKey);
setResult((result) => [
...result.filter((r) => !isEqual(r.assetKey, loadKey)),
{...loaded, fetchedAt: assetLastMaterializedAt},
{...loaded, fetchedAt: cacheKey},
]);
};
run();
}, [client, missingKeyJSON, assetLastMaterializedAt]);
}, [client, missingKeyJSON, cacheKey]);

return React.useMemo(() => {
const assetKeyJSONs = JSON.parse(assetKeyJSON);
return result.filter((r) => assetKeyJSONs.includes(JSON.stringify(r.assetKey)));
}, [assetKeyJSON, result]);
return result.filter(
(r) =>
assetKeyJSONs.includes(JSON.stringify(r.assetKey)) &&
(r.fetchedAt === cacheKey || cacheClearStrategy === 'background'),
);
}, [assetKeyJSON, result, cacheKey, cacheClearStrategy]);
}

export const PARTITION_HEALTH_QUERY = gql`
Expand Down

1 comment on commit 122d46e

@vercel
Copy link

@vercel vercel bot commented on 122d46e Mar 1, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

dagit-storybook – ./js_modules/dagit/packages/ui

dagit-storybook-git-master-elementl.vercel.app
dagit-storybook-elementl.vercel.app
dagit-storybook.vercel.app

Please sign in to comment.