From 5740d40a9bc6ad4c4f5fe34f50dbc750131a5f7b Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Fri, 25 Apr 2025 15:13:57 -0400 Subject: [PATCH 1/2] add some memoization --- .../src/partitions/AssetJobPartitionsView.tsx | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/partitions/AssetJobPartitionsView.tsx b/js_modules/dagster-ui/packages/ui-core/src/partitions/AssetJobPartitionsView.tsx index f19cbaea5a75d..4ee6b734e368f 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/partitions/AssetJobPartitionsView.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/partitions/AssetJobPartitionsView.tsx @@ -90,18 +90,24 @@ export const AssetJobPartitionsView = ({ } }, [viewport.width, setPageSize]); - let dimensionIdx = merged.dimensions.findIndex(isTimeseriesDimension); - if (dimensionIdx === -1) { - dimensionIdx = 0; // may as well show something - } - - const dimension = merged.dimensions[dimensionIdx] ? merged.dimensions[dimensionIdx] : null; - const dimensionKeys = dimension?.partitionKeys || []; + const {selectedDimensionKeys, dimensionIdx, dimension, dimensionKeys} = useMemo(() => { + let dimensionIdx = merged.dimensions.findIndex(isTimeseriesDimension); + if (dimensionIdx === -1) { + dimensionIdx = 0; // may as well show something + } + const dimension = merged.dimensions[dimensionIdx] ? merged.dimensions[dimensionIdx] : null; + const dimensionKeys = dimension?.partitionKeys || []; + return { + selectedDimensionKeys: dimensionKeys.slice( + Math.max(0, dimensionKeys.length - 1 - offset - pageSize), + dimensionKeys.length - offset, + ), + dimensionIdx, + dimension, + dimensionKeys, + }; + }, [merged.dimensions, offset, pageSize]); - const selectedDimensionKeys = dimensionKeys.slice( - Math.max(0, dimensionKeys.length - 1 - offset - pageSize), - dimensionKeys.length - offset, - ); return (
Date: Fri, 25 Apr 2025 15:15:25 -0400 Subject: [PATCH 2/2] add some memoization --- .../src/partitions/AssetJobPartitionsView.tsx | 444 +++++++++--------- 1 file changed, 224 insertions(+), 220 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/partitions/AssetJobPartitionsView.tsx b/js_modules/dagster-ui/packages/ui-core/src/partitions/AssetJobPartitionsView.tsx index 4ee6b734e368f..a5b9b4dc99e37 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/partitions/AssetJobPartitionsView.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/partitions/AssetJobPartitionsView.tsx @@ -1,5 +1,5 @@ import {Box, Button, Subheading, useViewport} from '@dagster-io/ui-components'; -import {useEffect, useMemo, useState} from 'react'; +import React, {useEffect, useMemo, useState} from 'react'; import {JobBackfillsTable} from './JobBackfillsTable'; import {CountBox, usePartitionDurations} from './OpJobPartitionsView'; @@ -24,243 +24,247 @@ import {DagsterTag} from '../runs/RunTag'; import {repoAddressToSelector} from '../workspace/repoAddressToSelector'; import {RepoAddress} from '../workspace/types'; -export const AssetJobPartitionsView = ({ - partitionSetName, - repoAddress, - pipelineName, -}: { - pipelineName: string; - partitionSetName: string; - repoAddress: RepoAddress; -}) => { - const {viewport, containerProps} = useViewport(); - const repositorySelector = repoAddressToSelector(repoAddress); - - const assetGraph = useAssetGraphData('*', { - pipelineSelector: { - pipelineName, - repositoryName: repoAddress.name, - repositoryLocationName: repoAddress.location, - }, - }); +export const AssetJobPartitionsView = React.memo( + ({ + partitionSetName, + repoAddress, + pipelineName, + }: { + pipelineName: string; + partitionSetName: string; + repoAddress: RepoAddress; + }) => { + const {viewport, containerProps} = useViewport(); + const repositorySelector = repoAddressToSelector(repoAddress); - const assetKeysWithPartitions = useMemo(() => { - return assetGraph.graphAssetKeys.filter((key) => { - return assetGraph.assetGraphData?.nodes[toGraphId(key)]?.definition.isPartitioned; + const assetGraph = useAssetGraphData('*', { + pipelineSelector: { + pipelineName, + repositoryName: repoAddress.name, + repositoryLocationName: repoAddress.location, + }, }); - }, [assetGraph]); - const assetHealth = usePartitionHealthData( - assetKeysWithPartitions.length - ? assetKeysWithPartitions - : assetGraph.graphAssetKeys[0] - ? [assetGraph.graphAssetKeys[0]] - : [], - ); + const assetKeysWithPartitions = useMemo(() => { + return assetGraph.graphAssetKeys.filter((key) => { + return assetGraph.assetGraphData?.nodes[toGraphId(key)]?.definition.isPartitioned; + }); + }, [assetGraph]); - const {total, missing, merged} = useMemo(() => { - const merged = mergedAssetHealth(assetHealth.filter((h) => h.dimensions.length > 0)); - const selection = merged.dimensions.map((d) => ({ - selectedKeys: d.partitionKeys, - selectedRanges: [allPartitionsRange(d)], - dimension: d, - })); - const missing = explodePartitionKeysInSelectionMatching(selection, (dIdxs) => - merged.stateForKeyIdx(dIdxs).includes(AssetPartitionStatus.MISSING), + const assetHealth = usePartitionHealthData( + assetKeysWithPartitions.length + ? assetKeysWithPartitions + : assetGraph.graphAssetKeys[0] + ? [assetGraph.graphAssetKeys[0]] + : [], ); - return { - merged, - total: keyCountInSelections(selection), - missing: missing.length, - }; - }, [assetHealth]); + const {total, missing, merged} = useMemo(() => { + const merged = mergedAssetHealth(assetHealth.filter((h) => h.dimensions.length > 0)); + const selection = merged.dimensions.map((d) => ({ + selectedKeys: d.partitionKeys, + selectedRanges: [allPartitionsRange(d)], + dimension: d, + })); + const missing = explodePartitionKeysInSelectionMatching(selection, (dIdxs) => + merged.stateForKeyIdx(dIdxs).includes(AssetPartitionStatus.MISSING), + ); - const [pageSize, setPageSize] = useState(60); - const [offset, setOffset] = useState(0); - const [showAssets, setShowAssets] = useState(false); + return { + merged, + total: keyCountInSelections(selection), + missing: missing.length, + }; + }, [assetHealth]); - useEffect(() => { - if (viewport.width) { - // magical numbers to approximate the size of the window, which is calculated in the step - // status component. This approximation is to make sure that the window does not jump as - // the pageSize gets recalculated - const approxPageSize = getVisibleItemCount(viewport.width - GRID_FLOATING_CONTAINER_WIDTH); - setPageSize(approxPageSize); - } - }, [viewport.width, setPageSize]); + const [pageSize, setPageSize] = useState(60); + const [offset, setOffset] = useState(0); + const [showAssets, setShowAssets] = useState(false); - const {selectedDimensionKeys, dimensionIdx, dimension, dimensionKeys} = useMemo(() => { - let dimensionIdx = merged.dimensions.findIndex(isTimeseriesDimension); - if (dimensionIdx === -1) { - dimensionIdx = 0; // may as well show something - } - const dimension = merged.dimensions[dimensionIdx] ? merged.dimensions[dimensionIdx] : null; - const dimensionKeys = dimension?.partitionKeys || []; - return { - selectedDimensionKeys: dimensionKeys.slice( - Math.max(0, dimensionKeys.length - 1 - offset - pageSize), - dimensionKeys.length - offset, - ), - dimensionIdx, - dimension, - dimensionKeys, - }; - }, [merged.dimensions, offset, pageSize]); + useEffect(() => { + if (viewport.width) { + // magical numbers to approximate the size of the window, which is calculated in the step + // status component. This approximation is to make sure that the window does not jump as + // the pageSize gets recalculated + const approxPageSize = getVisibleItemCount(viewport.width - GRID_FLOATING_CONTAINER_WIDTH); + setPageSize(approxPageSize); + } + }, [viewport.width, setPageSize]); - return ( -
- - Status - - - g.node), skipAllTerm: true}} - preferredJobName={pipelineName} - /> + const {selectedDimensionKeys, dimensionIdx, dimension, dimensionKeys} = useMemo(() => { + let dimensionIdx = merged.dimensions.findIndex(isTimeseriesDimension); + if (dimensionIdx === -1) { + dimensionIdx = 0; // may as well show something + } + const dimension = merged.dimensions[dimensionIdx] ? merged.dimensions[dimensionIdx] : null; + const dimensionKeys = dimension?.partitionKeys || []; + return { + selectedDimensionKeys: dimensionKeys.slice( + Math.max(0, dimensionKeys.length - 1 - offset - pageSize), + dimensionKeys.length - offset, + ), + dimensionIdx, + dimension, + dimensionKeys, + }; + }, [merged.dimensions, offset, pageSize]); + + return ( +
+ + Status + + + g.node), skipAllTerm: true}} + preferredJobName={pipelineName} + /> + - - - - - - -
- + + + + +
+ { + const maxIdx = dimensionKeys.length - 1; + const selectedIdx = dimensionKeys.indexOf(partitionName); + const nextOffset = Math.min( + maxIdx, + Math.max(0, maxIdx - selectedIdx - 0.5 * pageSize), + ); + setOffset(nextOffset); + }} + /> +
+ {showAssets && dimension && ( + + + + )} +
+ {showAssets && ( + 1} + dimensionName={dimension ? dimension.name : null} + dimensionKeys={dimensionKeys} selected={selectedDimensionKeys} - selectionWindowSize={pageSize} - tooltipMessage="Click to view per-asset status" - onClick={(partitionName) => { - const maxIdx = dimensionKeys.length - 1; - const selectedIdx = dimensionKeys.indexOf(partitionName); - const nextOffset = Math.min( - maxIdx, - Math.max(0, maxIdx - selectedIdx - 0.5 * pageSize), - ); - setOffset(nextOffset); - }} + offset={offset} + pageSize={pageSize} /> -
- {showAssets && dimension && ( - - - )} -
- {showAssets && ( - 1} - dimensionName={dimension ? dimension.name : null} - dimensionKeys={dimensionKeys} - selected={selectedDimensionKeys} - offset={offset} - pageSize={pageSize} - /> - )} - - Backfill history - - - - -
- ); -}; + + Backfill history + + + + +
+ ); + }, +); -const AssetJobPartitionGraphs = ({ - repositorySelector, - dimensionKeys, - dimensionName, - selected, - pageSize, - partitionSetName, - multidimensional, - pipelineName, - offset, -}: { - repositorySelector: RepositorySelector; - pipelineName: string; - partitionSetName: string; - multidimensional: boolean; - dimensionName: string | null; - dimensionKeys: string[]; - selected: string[]; - pageSize: number; - offset: number; -}) => { - const partitions = usePartitionStepQuery({ - partitionSetName, - partitionTagName: multidimensional - ? `${DagsterTag.Partition}/${dimensionName}` - : DagsterTag.Partition, - partitionNames: dimensionKeys, +const AssetJobPartitionGraphs = React.memo( + ({ repositorySelector, + dimensionKeys, + dimensionName, + selected, pageSize, - runsFilter: [], - jobName: pipelineName, + partitionSetName, + multidimensional, + pipelineName, offset, - skipQuery: !dimensionName, - }); + }: { + repositorySelector: RepositorySelector; + pipelineName: string; + partitionSetName: string; + multidimensional: boolean; + dimensionName: string | null; + dimensionKeys: string[]; + selected: string[]; + pageSize: number; + offset: number; + }) => { + const partitions = usePartitionStepQuery({ + partitionSetName, + partitionTagName: multidimensional + ? `${DagsterTag.Partition}/${dimensionName}` + : DagsterTag.Partition, + partitionNames: dimensionKeys, + repositorySelector, + pageSize, + runsFilter: [], + jobName: pipelineName, + offset, + skipQuery: !dimensionName, + }); - const {stepDurationData, runDurationData} = usePartitionDurations(partitions); + const {stepDurationData, runDurationData} = usePartitionDurations(partitions); - return ( - <> - - Run duration - + return ( + <> + + Run duration + - - - - - Step durations - - - - - - ); -}; + + + + + Step durations + + + + + + ); + }, +);