From ab4f68fcb52fe1ab259e9a5c4686cf442aca41c5 Mon Sep 17 00:00:00 2001 From: Isaac Hellendag Date: Wed, 13 Nov 2024 10:21:42 -0600 Subject: [PATCH] [ui] New Evaluations list table --- .../EvaluationList.tsx | 35 ++++ .../EvaluationListRow.tsx | 158 ++++++++++++++++++ .../EvaluationStatusTag.tsx | 79 +++++++++ .../__fixtures__/EvaluationList.fixtures.ts | 54 ++++++ .../__stories__/EvaluationList.stories.tsx | 29 ++++ 5 files changed, 355 insertions(+) create mode 100644 js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/EvaluationList.tsx create mode 100644 js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/EvaluationListRow.tsx create mode 100644 js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/EvaluationStatusTag.tsx create mode 100644 js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/__fixtures__/EvaluationList.fixtures.ts create mode 100644 js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/__stories__/EvaluationList.stories.tsx diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/EvaluationList.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/EvaluationList.tsx new file mode 100644 index 0000000000000..abb3e2e87f9a4 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/EvaluationList.tsx @@ -0,0 +1,35 @@ +import {Table} from '@dagster-io/ui-components'; + +import {EvaluationListRow} from './EvaluationListRow'; +import {AssetViewDefinitionNodeFragment} from '../types/AssetView.types'; +import {AssetConditionEvaluationRecordFragment} from './types/GetEvaluationsQuery.types'; + +interface Props { + definition: AssetViewDefinitionNodeFragment; + evaluations: AssetConditionEvaluationRecordFragment[]; +} + +export const EvaluationList = ({definition, evaluations}: Props) => { + return ( + + + + + + + + + + {evaluations.map((evaluation) => { + return ( + + ); + })} + +
TimestampEvaluation resultRun(s)
+ ); +}; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/EvaluationListRow.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/EvaluationListRow.tsx new file mode 100644 index 0000000000000..ecc8bf3524d16 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/EvaluationListRow.tsx @@ -0,0 +1,158 @@ +import { + Box, + Button, + ButtonLink, + Colors, + Dialog, + DialogFooter, + DialogHeader, + Mono, +} from '@dagster-io/ui-components'; +import {useState} from 'react'; + +import {EvaluationStatusTag} from './EvaluationStatusTag'; +import {PolicyEvaluationTable} from './PolicyEvaluationTable'; +import {AssetConditionEvaluationRecordFragment} from './types/GetEvaluationsQuery.types'; +import {DEFAULT_TIME_FORMAT} from '../../app/time/TimestampFormat'; +import {RunsFeedTableWithFilters} from '../../runs/RunsFeedTable'; +import {TimestampDisplay} from '../../schedules/TimestampDisplay'; +import {AssetViewDefinitionNodeFragment} from '../types/AssetView.types'; + +interface Props { + definition: AssetViewDefinitionNodeFragment; + evaluation: AssetConditionEvaluationRecordFragment; +} + +export const EvaluationListRow = ({evaluation, definition}: Props) => { + const [isOpen, setIsOpen] = useState(false); + // const [selectedPartition, setSelectedPartition] = useState(null); + + return ( + <> + + + setIsOpen(true)}> + + + + + {}} + /> + + + + + + setIsOpen(false)} + style={{ + width: '80vw', + maxWidth: '1400px', + minWidth: '800px', + height: '80vh', + minHeight: '400px', + maxHeight: '1400px', + }} + > + + + Evaluation details:{' '} + + + } + /> +
+ {}} + /> +
+
+ + + +
+
+
+ + ); +}; + +const EvaluationRunInfo = ({evaluation}: {evaluation: AssetConditionEvaluationRecordFragment}) => { + const {runIds} = evaluation; + const [isOpen, setIsOpen] = useState(false); + + if (runIds.length === 0) { + return None; + } + + if (runIds.length === 1) { + return ( + + {runIds[0]} + + ); + } + + return ( + <> + setIsOpen(true)}>{runIds.length} runs + setIsOpen(false)} + style={{ + width: '80vw', + maxWidth: '1400px', + minWidth: '800px', + height: '80vh', + minHeight: '400px', + maxHeight: '1400px', + }} + > + + + Runs at{' '} + + + } + /> +
+ +
+ + + +
+
+ + ); +}; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/EvaluationStatusTag.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/EvaluationStatusTag.tsx new file mode 100644 index 0000000000000..4e89fbb089f9e --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/EvaluationStatusTag.tsx @@ -0,0 +1,79 @@ +import {Box, Colors, Icon, Popover, Tag} from '@dagster-io/ui-components'; +import {useMemo} from 'react'; + +import {PartitionSubsetList} from './PartitionSubsetList'; +import {AssetConditionEvaluationRecordFragment} from './types/GetEvaluationsQuery.types'; +import {AssetViewDefinitionNodeFragment} from '../types/AssetView.types'; + +interface Props { + definition: AssetViewDefinitionNodeFragment; + selectedEvaluation: AssetConditionEvaluationRecordFragment; + selectPartition: (partitionKey: string | null) => void; +} + +export const EvaluationStatusTag = ({definition, selectedEvaluation, selectPartition}: Props) => { + const evaluation = selectedEvaluation?.evaluation; + const rootEvaluationNode = useMemo( + () => evaluation?.evaluationNodes.find((node) => node.uniqueId === evaluation.rootUniqueId), + [evaluation], + ); + const rootUniqueId = evaluation?.rootUniqueId; + + const partitionDefinition = definition?.partitionDefinition; + const assetKeyPath = definition?.assetKey.path || []; + const numRequested = selectedEvaluation?.numRequested; + + const numTrue = + rootEvaluationNode?.__typename === 'PartitionedAssetConditionEvaluationNode' + ? rootEvaluationNode.numTrue + : null; + + if (numRequested) { + if (partitionDefinition && rootUniqueId && numTrue) { + return ( + + + } + > + + + + {numRequested} requested + + + + + ); + } + + return ( + + + + Requested + + + ); + } + + return ( + + + + Not requested + + + ); +}; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/__fixtures__/EvaluationList.fixtures.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/__fixtures__/EvaluationList.fixtures.ts new file mode 100644 index 0000000000000..4c1720938dd11 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/__fixtures__/EvaluationList.fixtures.ts @@ -0,0 +1,54 @@ +import faker from 'faker'; + +import { + buildAssetConditionEvaluation, + buildAssetConditionEvaluationRecord, + buildAutomationConditionEvaluationNode, +} from '../../../graphql/types'; + +const ONE_MINUTE = 60 * 1000; + +export const buildEvaluationRecordsForList = (length: number) => { + const now = Date.now(); + const evaluationId = 100; + return new Array(length).fill(null).map((_, ii) => { + const evaluationNodes = new Array(30).fill(null).map((_, jj) => { + const id = faker.lorem.word(); + return buildAutomationConditionEvaluationNode({ + startTimestamp: 0 + jj, + endTimestamp: 10 + jj, + uniqueId: id, + userLabel: faker.lorem.word(), + isPartitioned: false, + numTrue: 0, + }); + }); + + return buildAssetConditionEvaluationRecord({ + id: `evaluation-${ii}`, + evaluationId: `${evaluationId + ii}`, + evaluation: buildAssetConditionEvaluation({ + rootUniqueId: 'my-root', + }), + timestamp: (now - ONE_MINUTE * ii) / 1000, + numRequested: Math.random() > 0.5 ? 1 : 0, + runIds: Array.from({length: Math.floor(Math.random() * 5)}).map(() => + faker.datatype.uuid().slice(0, 8), + ), + isLegacy: false, + rootUniqueId: 'my-root', + evaluationNodes: [ + buildAutomationConditionEvaluationNode({ + startTimestamp: 0, + endTimestamp: 1000, + uniqueId: 'my-root', + userLabel: faker.lorem.word(), + isPartitioned: false, + numTrue: 0, + childUniqueIds: evaluationNodes.map((node) => node.uniqueId), + }), + ...evaluationNodes, + ], + }); + }); +}; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/__stories__/EvaluationList.stories.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/__stories__/EvaluationList.stories.tsx new file mode 100644 index 0000000000000..3c3677fe8b6ee --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AutoMaterializePolicyPage/__stories__/EvaluationList.stories.tsx @@ -0,0 +1,29 @@ +import {MockedProvider} from '@apollo/client/testing'; + +import {buildAssetNode} from '../../../graphql/types'; +import {EvaluationList} from '../EvaluationList'; +import {buildEvaluationRecordsForList} from '../__fixtures__/EvaluationList.fixtures'; + +// eslint-disable-next-line import/no-default-export +export default { + title: 'Asset Details/Automaterialize/EvaluationList', + component: EvaluationList, +}; + +export const Default = () => { + const definition = buildAssetNode({ + id: '1', + groupName: '1', + isMaterializable: true, + partitionDefinition: null, + partitionKeysByDimension: [], + }); + + const evaluations = buildEvaluationRecordsForList(25); + + return ( + + + + ); +};