From e933f210d44920c2800f832216739d55e952fa3f Mon Sep 17 00:00:00 2001 From: Eugene Jahn Date: Tue, 28 Jun 2022 09:39:39 -0700 Subject: [PATCH] fix: cache icon fro map task (#519) * fix: cache icon fro map task * fix: icon and text center Signed-off-by: eugenejahn --- .../ui-atoms/src/Icons/MapCacheIcon/index.tsx | 24 ++++++ .../composites/ui-atoms/src/Icons/index.tsx | 1 + .../NodeExecutionDetailsPanelContent.tsx | 2 +- .../Timeline/TimelineChart/chartData.ts | 10 ++- .../Timeline/TimelineChart/utils.ts | 19 ++++- .../test/TimelineChart.test.tsx | 15 +++- .../test/__mocks__/NodeExecution.mock.ts | 40 ++++++++- .../Executions/NodeExecutionCacheStatus.tsx | 84 +++++++++++++++++-- .../Tables/nodeExecutionColumns.tsx | 15 ++-- .../Tables/test/NodeExecutionsTable.test.tsx | 15 +--- .../src/components/Executions/constants.ts | 78 ++++++++--------- .../src/components/Executions/strings.ts | 33 ++++++++ .../MapTaskExecutionsList/TaskNameList.tsx | 34 +++++--- .../ReactFlow/customNodeComponents.tsx | 18 ++-- .../ReactFlow/transformDAGToReactFlowV2.tsx | 10 ++- .../console/src/models/Execution/enums.ts | 7 +- 16 files changed, 296 insertions(+), 109 deletions(-) create mode 100644 packages/composites/ui-atoms/src/Icons/MapCacheIcon/index.tsx create mode 100644 packages/zapp/console/src/components/Executions/strings.ts diff --git a/packages/composites/ui-atoms/src/Icons/MapCacheIcon/index.tsx b/packages/composites/ui-atoms/src/Icons/MapCacheIcon/index.tsx new file mode 100644 index 000000000..a99e85533 --- /dev/null +++ b/packages/composites/ui-atoms/src/Icons/MapCacheIcon/index.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; + +export const MapCacheIcon = React.forwardRef((props, ref) => { + return ( + + + + + + + + + + + + ); +}); diff --git a/packages/composites/ui-atoms/src/Icons/index.tsx b/packages/composites/ui-atoms/src/Icons/index.tsx index 2f6fb0418..1f591b50b 100644 --- a/packages/composites/ui-atoms/src/Icons/index.tsx +++ b/packages/composites/ui-atoms/src/Icons/index.tsx @@ -1,4 +1,5 @@ export { FlyteLogo } from './FlyteLogo'; export { InfoIcon } from './InfoIcon'; export { RerunIcon } from './RerunIcon'; +export { MapCacheIcon } from './MapCacheIcon'; export { MuiLaunchPlanIcon } from './MuiLaunchPlanIcon'; diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/NodeExecutionDetailsPanelContent.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/NodeExecutionDetailsPanelContent.tsx index 728a9fe58..dbe5db314 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/NodeExecutionDetailsPanelContent.tsx +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/NodeExecutionDetailsPanelContent.tsx @@ -364,7 +364,7 @@ export const NodeExecutionDetailsPanelContent: React.FC - + ); diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/TimelineChart/chartData.ts b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/TimelineChart/chartData.ts index adbf5e8bf..76c0e6766 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/TimelineChart/chartData.ts +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/TimelineChart/chartData.ts @@ -1,6 +1,7 @@ import { timestampToDate } from 'common/utils'; import { CatalogCacheStatus, NodeExecutionPhase } from 'models/Execution/enums'; import { dNode } from 'models/Graph/types'; +import { isMapTaskType } from 'models/Task/utils'; import { BarItemData } from './utils'; const WEEK_DURATION_SEC = 7 * 24 * 3600; @@ -10,6 +11,7 @@ const EMPTY_BAR_ITEM: BarItemData = { startOffsetSec: 0, durationSec: 0, isFromCache: false, + isMapTaskCache: false, }; export const getChartDurationData = ( @@ -20,7 +22,8 @@ export const getChartDurationData = ( let totalDurationSec = 0; const initialStartTime = startedAt.getTime(); - const result: BarItemData[] = nodes.map(({ execution }) => { + + const result: BarItemData[] = nodes.map(({ execution, value }) => { if (!execution) { return EMPTY_BAR_ITEM; } @@ -29,6 +32,9 @@ export const getChartDurationData = ( const isFromCache = execution.closure.taskNodeMetadata?.cacheStatus === CatalogCacheStatus.CACHE_HIT; + const isMapTaskCache = + isMapTaskType(value?.template?.type) && value?.template?.metadata?.cacheSerializable; + // Offset values let startOffset = 0; const startedAt = execution.closure.startedAt; @@ -67,7 +73,7 @@ export const getChartDurationData = ( const startOffsetSec = Math.trunc(startOffset / 1000); totalDurationSec = Math.max(totalDurationSec, startOffsetSec + durationSec); - return { phase, startOffsetSec, durationSec, isFromCache }; + return { phase, startOffsetSec, durationSec, isFromCache, isMapTaskCache }; }); // Do we want to get initialStartTime from different place, to avoid recalculating it. diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/TimelineChart/utils.ts b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/TimelineChart/utils.ts index fab27b6ec..b5b16d380 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/TimelineChart/utils.ts +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/TimelineChart/utils.ts @@ -1,6 +1,7 @@ import { getNodeExecutionPhaseConstants } from 'components/Executions/utils'; import { primaryTextColor } from 'components/Theme/constants'; import { NodeExecutionPhase } from 'models/Execution/enums'; +import t from 'components/Executions/strings'; export const CASHED_GREEN = 'rgba(74,227,174,0.25)'; // statusColors.SUCCESS (Mint20) with 25% opacity export const TRANSPARENT = 'rgba(0, 0, 0, 0)'; @@ -10,6 +11,7 @@ export interface BarItemData { startOffsetSec: number; durationSec: number; isFromCache: boolean; + isMapTaskCache: boolean; } interface ChartDataInput { @@ -60,11 +62,24 @@ export const generateChartData = (data: BarItemData[]): ChartDataInput => { // don't show Label if there is now duration yet. const labelString = element.durationSec > 0 ? durationString : ''; + const generateTooltipLabelText = (element: BarItemData): string[] => { + if (element.isMapTaskCache) return [tooltipString, t('mapCacheMessage')]; + if (element.isFromCache) return [tooltipString, t('readFromCache')]; + + return [tooltipString]; + }; + + const generateBarLabelText = (element: BarItemData): string => { + if (element.isMapTaskCache) return '\u229A ' + t('mapCacheMessage'); + if (element.isFromCache) return '\u229A ' + t('fromCache'); + return labelString; + }; + durations.push(element.durationSec); startOffset.push(element.startOffsetSec); offsetColor.push(element.isFromCache ? CASHED_GREEN : TRANSPARENT); - tooltipLabel.push(element.isFromCache ? [tooltipString, 'Read from cache'] : [tooltipString]); - barLabel.push(element.isFromCache ? '\u229A From cache' : labelString); + tooltipLabel.push(generateTooltipLabelText(element)); + barLabel.push(generateBarLabelText(element)); barColor.push(phaseConstant.badgeColor); }); diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/test/TimelineChart.test.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/test/TimelineChart.test.tsx index 763855ac3..8d0f31d32 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/test/TimelineChart.test.tsx +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/test/TimelineChart.test.tsx @@ -28,12 +28,21 @@ describe('ExecutionDetails > Timeline > BarChart', () => { it('generateChartData properly generates map of data for ChartBars', () => { const chartData = generateChartData(mockbarItems); - expect(chartData.durations).toEqual([15, 11, 23, 0]); - expect(chartData.startOffset).toEqual([0, 5, 17, 39]); - expect(chartData.offsetColor).toEqual([TRANSPARENT, CASHED_GREEN, TRANSPARENT, TRANSPARENT]); + expect(chartData.durations).toEqual([15, 11, 23, 0, 11]); + expect(chartData.startOffset).toEqual([0, 5, 17, 39, 5]); + expect(chartData.offsetColor).toEqual([ + TRANSPARENT, + CASHED_GREEN, + TRANSPARENT, + TRANSPARENT, + TRANSPARENT, + ]); // labels looks as expected expect(chartData.barLabel[0]).toEqual(formatSecondsToHmsFormat(mockbarItems[0].durationSec)); expect(chartData.barLabel[1]).toEqual('\u229A From cache'); expect(chartData.barLabel[3]).toEqual(''); + expect(chartData.barLabel[4]).toEqual( + "\u229A Check the detail panel for each task's cache status.", + ); }); }); diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/test/__mocks__/NodeExecution.mock.ts b/packages/zapp/console/src/components/Executions/ExecutionDetails/test/__mocks__/NodeExecution.mock.ts index d5a0a33f5..3dcf5d057 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/test/__mocks__/NodeExecution.mock.ts +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/test/__mocks__/NodeExecution.mock.ts @@ -60,10 +60,41 @@ const getMockNodeExecution = ( }; export const mockbarItems = [ - { phase: NodeExecutionPhase.FAILED, startOffsetSec: 0, durationSec: 15, isFromCache: false }, - { phase: NodeExecutionPhase.SUCCEEDED, startOffsetSec: 5, durationSec: 11, isFromCache: true }, - { phase: NodeExecutionPhase.RUNNING, startOffsetSec: 17, durationSec: 23, isFromCache: false }, - { phase: NodeExecutionPhase.QUEUED, startOffsetSec: 39, durationSec: 0, isFromCache: false }, + { + phase: NodeExecutionPhase.FAILED, + startOffsetSec: 0, + durationSec: 15, + isFromCache: false, + isMapTaskCache: false, + }, + { + phase: NodeExecutionPhase.SUCCEEDED, + startOffsetSec: 5, + durationSec: 11, + isFromCache: true, + isMapTaskCache: false, + }, + { + phase: NodeExecutionPhase.RUNNING, + startOffsetSec: 17, + durationSec: 23, + isFromCache: false, + isMapTaskCache: false, + }, + { + phase: NodeExecutionPhase.QUEUED, + startOffsetSec: 39, + durationSec: 0, + isFromCache: false, + isMapTaskCache: false, + }, + { + phase: NodeExecutionPhase.SUCCEEDED, + startOffsetSec: 5, + durationSec: 11, + isFromCache: false, + isMapTaskCache: true, + }, ]; export const getMockExecutionsForBarChart = (startTimeSec: number) => { @@ -73,5 +104,6 @@ export const getMockExecutionsForBarChart = (startTimeSec: number) => { getMockNodeExecution(start, NodeExecutionPhase.SUCCEEDED, 5, 11, CatalogCacheStatus.CACHE_HIT), getMockNodeExecution(start, NodeExecutionPhase.RUNNING, 17, 23, CatalogCacheStatus.CACHE_MISS), getMockNodeExecution(start, NodeExecutionPhase.QUEUED, 39, 0), + getMockNodeExecution(start, NodeExecutionPhase.SUCCEEDED, 5, 11, CatalogCacheStatus.MAP_CACHE), ]; }; diff --git a/packages/zapp/console/src/components/Executions/NodeExecutionCacheStatus.tsx b/packages/zapp/console/src/components/Executions/NodeExecutionCacheStatus.tsx index 72b1fbf14..a16960dec 100644 --- a/packages/zapp/console/src/components/Executions/NodeExecutionCacheStatus.tsx +++ b/packages/zapp/console/src/components/Executions/NodeExecutionCacheStatus.tsx @@ -7,9 +7,13 @@ import classnames from 'classnames'; import { assertNever } from 'common/utils'; import { PublishedWithChangesOutlined } from 'components/common/PublishedWithChanges'; import { useCommonStyles } from 'components/common/styles'; +import { NodeExecutionDetails } from 'components/Executions/types'; +import { useNodeExecutionContext } from 'components/Executions/contextProvider/NodeExecutionDetails'; import { CatalogCacheStatus } from 'models/Execution/enums'; -import { TaskNodeMetadata } from 'models/Execution/types'; +import { NodeExecution, TaskExecutionIdentifier } from 'models/Execution/types'; +import { MapCacheIcon } from '@flyteconsole/ui-atoms'; import * as React from 'react'; +import { isMapTaskType } from 'models/Task/utils'; import { Link as RouterLink } from 'react-router-dom'; import { Routes } from 'routes/routes'; import { @@ -50,6 +54,9 @@ export const NodeExecutionCacheStatusIcon: React.FC< case CatalogCacheStatus.CACHE_PUT_FAILURE: { return ; } + case CatalogCacheStatus.MAP_CACHE: { + return ; + } default: { assertNever(status); return null; @@ -58,7 +65,7 @@ export const NodeExecutionCacheStatusIcon: React.FC< }); export interface NodeExecutionCacheStatusProps { - taskNodeMetadata?: TaskNodeMetadata; + execution: NodeExecution; /** `normal` will render an icon with description message beside it * `iconOnly` will render just the icon with the description as a tooltip */ @@ -68,20 +75,78 @@ export interface NodeExecutionCacheStatusProps { * the cache status with a descriptive message. For `Core.CacheCatalogStatus.CACHE_HIT`, * it will also attempt to render a link to the source `WorkflowExecution` (normal * variant only). + * + * For Map Tasks, we will check the NodeExecutionDetail for the cache status instead. Since map tasks + * cotains multiple tasks, the logic of the cache status is different. */ export const NodeExecutionCacheStatus: React.FC = ({ - taskNodeMetadata, + execution, + variant = 'normal', +}) => { + const taskNodeMetadata = execution.closure?.taskNodeMetadata; + const detailsContext = useNodeExecutionContext(); + const [nodeDetails, setNodeDetails] = React.useState(); + + React.useEffect(() => { + let isCurrent = true; + detailsContext.getNodeExecutionDetails(execution).then((res) => { + if (isCurrent) { + setNodeDetails(res); + } + }); + return () => { + isCurrent = false; + }; + }); + + if (isMapTaskType(nodeDetails?.taskTemplate?.type)) { + if (nodeDetails?.taskTemplate?.metadata?.cacheSerializable) { + return ; + } + } + + // cachestatus can be 0 + if (taskNodeMetadata?.cacheStatus == null) { + return null; + } + + const sourceTaskExecution = taskNodeMetadata.catalogKey?.sourceTaskExecution; + + return ( + + ); +}; + +export interface CacheStatusProps { + cacheStatus: CatalogCacheStatus | null | undefined; + /** `normal` will render an icon with description message beside it + * `iconOnly` will render just the icon with the description as a tooltip + */ + variant?: 'normal' | 'iconOnly'; + sourceTaskExecution?: TaskExecutionIdentifier; + iconStyles?: React.CSSProperties; +} + +export const CacheStatus: React.FC = ({ + cacheStatus, + sourceTaskExecution, variant = 'normal', + iconStyles, }) => { const commonStyles = useCommonStyles(); const styles = useStyles(); - if (taskNodeMetadata == null || taskNodeMetadata.cacheStatus == null) { + + if (cacheStatus == null) { return null; } - const message = cacheStatusMessages[taskNodeMetadata.cacheStatus] || unknownCacheStatusString; + const message = cacheStatusMessages[cacheStatus] || unknownCacheStatusString; - const sourceExecutionId = taskNodeMetadata.catalogKey?.sourceTaskExecution; + const sourceExecutionId = sourceTaskExecution; const sourceExecutionLink = sourceExecutionId ? ( = ) : (
{message} diff --git a/packages/zapp/console/src/components/Executions/Tables/nodeExecutionColumns.tsx b/packages/zapp/console/src/components/Executions/Tables/nodeExecutionColumns.tsx index 5a9925b62..b2338437f 100644 --- a/packages/zapp/console/src/components/Executions/Tables/nodeExecutionColumns.tsx +++ b/packages/zapp/console/src/components/Executions/Tables/nodeExecutionColumns.tsx @@ -139,16 +139,13 @@ export function generateColumns( label: 'type', }, { - cellRenderer: ({ - execution: { - closure: { phase = NodeExecutionPhase.UNDEFINED, taskNodeMetadata }, - }, - }) => ( + cellRenderer: ({ execution }) => ( <> - - {hasCacheStatus(taskNodeMetadata) ? ( - - ) : null} + + ), className: styles.columnStatus, diff --git a/packages/zapp/console/src/components/Executions/Tables/test/NodeExecutionsTable.test.tsx b/packages/zapp/console/src/components/Executions/Tables/test/NodeExecutionsTable.test.tsx index c6e679f37..424dbccb4 100644 --- a/packages/zapp/console/src/components/Executions/Tables/test/NodeExecutionsTable.test.tsx +++ b/packages/zapp/console/src/components/Executions/Tables/test/NodeExecutionsTable.test.tsx @@ -243,6 +243,8 @@ describe('NodeExecutionsTable', () => { CatalogCacheStatus.CACHE_LOOKUP_FAILURE, CatalogCacheStatus.CACHE_POPULATED, CatalogCacheStatus.CACHE_PUT_FAILURE, + CatalogCacheStatus.CACHE_MISS, + CatalogCacheStatus.CACHE_DISABLED, ].forEach((cacheStatusValue) => it(`renders correct icon for ${CatalogCacheStatus[cacheStatusValue]}`, async () => { taskNodeMetadata.cacheStatus = cacheStatusValue; @@ -254,19 +256,6 @@ describe('NodeExecutionsTable', () => { ); }), ); - - [CatalogCacheStatus.CACHE_DISABLED, CatalogCacheStatus.CACHE_MISS].forEach( - (cacheStatusValue) => - it(`renders no icon for ${CatalogCacheStatus[cacheStatusValue]}`, async () => { - taskNodeMetadata.cacheStatus = cacheStatusValue; - updateNodeExecutions([cachedNodeExecution]); - const { getByText, queryByTitle } = renderTable(); - await waitFor(() => { - getByText(cachedNodeExecution.id.nodeId); - }); - expect(queryByTitle(cacheStatusMessages[cacheStatusValue])).toBeNull(); - }), - ); }); }); diff --git a/packages/zapp/console/src/components/Executions/constants.ts b/packages/zapp/console/src/components/Executions/constants.ts index ca70252f1..2b2a88f35 100644 --- a/packages/zapp/console/src/components/Executions/constants.ts +++ b/packages/zapp/console/src/components/Executions/constants.ts @@ -11,10 +11,11 @@ import { WorkflowExecutionPhase, } from 'models/Execution/enums'; import { TaskType } from 'models/Task/constants'; +import t from './strings'; import { ExecutionPhaseConstants, NodeExecutionDisplayType } from './types'; export const executionRefreshIntervalMs = 10000; -export const noLogsFoundString = 'No logs found'; +export const noLogsFoundString = t('noLogsFoundString'); /** Shared values for color/text/etc for each execution phase */ export const workflowExecutionPhaseConstants: { @@ -22,52 +23,52 @@ export const workflowExecutionPhaseConstants: { } = { [WorkflowExecutionPhase.ABORTED]: { badgeColor: statusColors.SKIPPED, - text: 'Aborted', + text: t('aborted'), textColor: negativeTextColor, }, [WorkflowExecutionPhase.ABORTING]: { badgeColor: statusColors.SKIPPED, - text: 'Aborting', + text: t('aborting'), textColor: negativeTextColor, }, [WorkflowExecutionPhase.FAILING]: { badgeColor: statusColors.FAILURE, - text: 'Failing', + text: t('failing'), textColor: negativeTextColor, }, [WorkflowExecutionPhase.FAILED]: { badgeColor: statusColors.FAILURE, - text: 'Failed', + text: t('failed'), textColor: negativeTextColor, }, [WorkflowExecutionPhase.QUEUED]: { badgeColor: statusColors.QUEUED, - text: 'Queued', + text: t('queued'), textColor: secondaryTextColor, }, [WorkflowExecutionPhase.RUNNING]: { badgeColor: statusColors.RUNNING, - text: 'Running', + text: t('running'), textColor: secondaryTextColor, }, [WorkflowExecutionPhase.SUCCEEDED]: { badgeColor: statusColors.SUCCESS, - text: 'Succeeded', + text: t('succeeded'), textColor: positiveTextColor, }, [WorkflowExecutionPhase.SUCCEEDING]: { badgeColor: statusColors.SUCCESS, - text: 'Succeeding', + text: t('succeeding'), textColor: positiveTextColor, }, [WorkflowExecutionPhase.TIMED_OUT]: { badgeColor: statusColors.FAILURE, - text: 'Timed Out', + text: t('timedOut'), textColor: negativeTextColor, }, [WorkflowExecutionPhase.UNDEFINED]: { badgeColor: statusColors.UNKNOWN, - text: 'Unknown', + text: t('unknown'), textColor: secondaryTextColor, }, }; @@ -78,57 +79,57 @@ export const nodeExecutionPhaseConstants: { } = { [NodeExecutionPhase.ABORTED]: { badgeColor: statusColors.FAILURE, - text: 'Aborted', + text: t('aborted'), textColor: negativeTextColor, }, [NodeExecutionPhase.FAILING]: { badgeColor: statusColors.FAILURE, - text: 'Failing', + text: t('failing'), textColor: negativeTextColor, }, [NodeExecutionPhase.FAILED]: { badgeColor: statusColors.FAILURE, - text: 'Failed', + text: t('failed'), textColor: negativeTextColor, }, [NodeExecutionPhase.QUEUED]: { badgeColor: statusColors.RUNNING, - text: 'Queued', + text: t('queued'), textColor: secondaryTextColor, }, [NodeExecutionPhase.RUNNING]: { badgeColor: statusColors.RUNNING, - text: 'Running', + text: t('running'), textColor: secondaryTextColor, }, [NodeExecutionPhase.DYNAMIC_RUNNING]: { badgeColor: statusColors.RUNNING, - text: 'Running', + text: t('running'), textColor: secondaryTextColor, }, [NodeExecutionPhase.SUCCEEDED]: { badgeColor: statusColors.SUCCESS, - text: 'Succeeded', + text: t('succeeded'), textColor: positiveTextColor, }, [NodeExecutionPhase.TIMED_OUT]: { badgeColor: statusColors.FAILURE, - text: 'Timed Out', + text: t('timedOut'), textColor: negativeTextColor, }, [NodeExecutionPhase.SKIPPED]: { badgeColor: statusColors.UNKNOWN, - text: 'Skipped', + text: t('skipped'), textColor: secondaryTextColor, }, [NodeExecutionPhase.RECOVERED]: { badgeColor: statusColors.SUCCESS, - text: 'Recovered', + text: t('recovered'), textColor: positiveTextColor, }, [NodeExecutionPhase.UNDEFINED]: { badgeColor: statusColors.UNKNOWN, - text: 'Unknown', + text: t('unknown'), textColor: secondaryTextColor, }, }; @@ -139,42 +140,42 @@ export const taskExecutionPhaseConstants: { } = { [TaskExecutionPhase.ABORTED]: { badgeColor: statusColors.FAILURE, - text: 'Aborted', + text: t('aborted'), textColor: negativeTextColor, }, [TaskExecutionPhase.FAILED]: { badgeColor: statusColors.FAILURE, - text: 'Failed', + text: t('failed'), textColor: negativeTextColor, }, [TaskExecutionPhase.WAITING_FOR_RESOURCES]: { badgeColor: statusColors.RUNNING, - text: 'Waiting', + text: t('waiting'), textColor: secondaryTextColor, }, [TaskExecutionPhase.QUEUED]: { badgeColor: statusColors.RUNNING, - text: 'Queued', + text: t('queued'), textColor: secondaryTextColor, }, [TaskExecutionPhase.INITIALIZING]: { badgeColor: statusColors.RUNNING, - text: 'Initializing', + text: t('initializing'), textColor: secondaryTextColor, }, [TaskExecutionPhase.RUNNING]: { badgeColor: statusColors.RUNNING, - text: 'Running', + text: t('running'), textColor: secondaryTextColor, }, [TaskExecutionPhase.SUCCEEDED]: { badgeColor: statusColors.SUCCESS, - text: 'Succeeded', + text: t('succeeded'), textColor: positiveTextColor, }, [TaskExecutionPhase.UNDEFINED]: { badgeColor: statusColors.UNKNOWN, - text: 'Unknown', + text: t('unknown'), textColor: secondaryTextColor, }, }; @@ -197,12 +198,13 @@ export const taskTypeToNodeExecutionDisplayType: { }; export const cacheStatusMessages: { [k in CatalogCacheStatus]: string } = { - [CatalogCacheStatus.CACHE_DISABLED]: 'Caching was disabled for this execution.', - [CatalogCacheStatus.CACHE_HIT]: 'Output for this execution was read from cache.', - [CatalogCacheStatus.CACHE_LOOKUP_FAILURE]: 'Failed to lookup cache information.', - [CatalogCacheStatus.CACHE_MISS]: 'No cached output was found for this execution.', - [CatalogCacheStatus.CACHE_POPULATED]: 'The result of this execution was written to cache.', - [CatalogCacheStatus.CACHE_PUT_FAILURE]: 'Failed to write output for this execution to cache.', + [CatalogCacheStatus.CACHE_DISABLED]: t('cacheDisabledMessage'), + [CatalogCacheStatus.CACHE_HIT]: t('cacheHitMessage'), + [CatalogCacheStatus.CACHE_LOOKUP_FAILURE]: t('cacheLookupFailureMessage'), + [CatalogCacheStatus.CACHE_MISS]: t('cacheMissMessage'), + [CatalogCacheStatus.CACHE_POPULATED]: t('cachePopulatedMessage'), + [CatalogCacheStatus.CACHE_PUT_FAILURE]: t('cachePutFailure'), + [CatalogCacheStatus.MAP_CACHE]: t('mapCacheMessage'), }; -export const unknownCacheStatusString = 'Cache status is unknown'; -export const viewSourceExecutionString = 'View source execution'; +export const unknownCacheStatusString = t('unknownCacheStatusString'); +export const viewSourceExecutionString = t('viewSourceExecutionString'); diff --git a/packages/zapp/console/src/components/Executions/strings.ts b/packages/zapp/console/src/components/Executions/strings.ts new file mode 100644 index 000000000..8856bb3ec --- /dev/null +++ b/packages/zapp/console/src/components/Executions/strings.ts @@ -0,0 +1,33 @@ +import { createLocalizedString } from '@flyteconsole/locale'; + +const str = { + noLogsFoundString: 'No logs found', + aborted: 'Aborted', + aborting: 'Aborting', + failed: 'Failed', + failing: 'Failing', + waiting: 'Waiting', + queued: 'Queued', + skipped: 'Skipped', + recovered: 'Recovered', + initializing: 'Initializing', + running: 'Running', + succeeded: 'Succeeded', + succeeding: 'Succeeding', + timedOut: 'Timed Out', + unknown: 'Unknown', + cacheDisabledMessage: 'Caching was disabled for this execution.', + cacheHitMessage: 'Output for this execution was read from cache.', + cacheLookupFailureMessage: 'Failed to lookup cache information.', + cacheMissMessage: 'No cached output was found for this execution.', + cachePopulatedMessage: 'The result of this execution was written to cache.', + cachePutFailure: 'Failed to write output for this execution to cache.', + mapCacheMessage: "Check the detail panel for each task's cache status.", + unknownCacheStatusString: 'Cache status is unknown', + viewSourceExecutionString: 'View source execution', + fromCache: 'From cache', + readFromCache: 'Read from cache', +}; + +export { patternKey } from '@flyteconsole/locale'; +export default createLocalizedString(str); diff --git a/packages/zapp/console/src/components/common/MapTaskExecutionsList/TaskNameList.tsx b/packages/zapp/console/src/components/common/MapTaskExecutionsList/TaskNameList.tsx index 41d7d1c79..20a091894 100644 --- a/packages/zapp/console/src/components/common/MapTaskExecutionsList/TaskNameList.tsx +++ b/packages/zapp/console/src/components/common/MapTaskExecutionsList/TaskNameList.tsx @@ -5,6 +5,7 @@ import { Core } from 'flyteidl'; import { getTaskIndex, getTaskLogName } from 'components/Executions/TaskExecutionsList/utils'; import { MapTaskExecution, TaskExecution } from 'models/Execution/types'; import { noLogsFoundString } from 'components/Executions/constants'; +import { CacheStatus } from 'components/Executions/NodeExecutionCacheStatus'; import { useCommonStyles } from '../styles'; interface StyleProps { @@ -35,26 +36,37 @@ export const TaskNameList = ({ taskExecution, logs, onTaskSelected }: TaskNameLi return ( <> - {logs.map((log) => { + {logs.map((log, taskIndex) => { const styles = useStyles({ isLink: !!log.uri }); const taskLogName = getTaskLogName(taskExecution.id.taskId.name, log.name ?? ''); - const taskIndex = getTaskIndex(taskExecution, log); + const cacheStatus = + taskIndex != null + ? taskExecution.closure?.metadata?.externalResources?.[taskIndex]?.cacheStatus + : null; const handleClick = () => { onTaskSelected({ ...taskExecution, taskIndex }); }; return ( - - {taskLogName} - + + {taskLogName} + + +
); })} diff --git a/packages/zapp/console/src/components/flytegraph/ReactFlow/customNodeComponents.tsx b/packages/zapp/console/src/components/flytegraph/ReactFlow/customNodeComponents.tsx index 27383b4ee..8a74f925f 100644 --- a/packages/zapp/console/src/components/flytegraph/ReactFlow/customNodeComponents.tsx +++ b/packages/zapp/console/src/components/flytegraph/ReactFlow/customNodeComponents.tsx @@ -7,6 +7,7 @@ import { CatalogCacheStatus, TaskExecutionPhase } from 'models/Execution/enums'; import { PublishedWithChangesOutlined } from 'components/common/PublishedWithChanges'; import { RENDER_ORDER } from 'components/Executions/TaskExecutionsList/constants'; import { whiteColor } from 'components/Theme/constants'; +import { CacheStatus } from 'components/Executions/NodeExecutionCacheStatus'; import { COLOR_TASK_TYPE, COLOR_GRAPH_BACKGROUND, @@ -333,17 +334,6 @@ export const ReactFlowCustomTaskNode = ({ data }: any) => { ); }; - const renderCacheIcon = (cacheStatus) => { - switch (cacheStatus) { - case CatalogCacheStatus.CACHE_HIT: - return ; - case CatalogCacheStatus.CACHE_POPULATED: - return ; - default: - return null; - } - }; - const renderTaskPhases = (logsByPhase) => { return (
@@ -375,7 +365,11 @@ export const ReactFlowCustomTaskNode = ({ data }: any) => { {data.nodeLogsByPhase ? renderTaskName() : data.taskType ? renderTaskType() : null}
{data.nodeLogsByPhase ? renderTaskPhases(data.nodeLogsByPhase) : data.text} - {renderCacheIcon(data.cacheStatus)} +
{renderDefaultHandles( data.scopedId, diff --git a/packages/zapp/console/src/components/flytegraph/ReactFlow/transformDAGToReactFlowV2.tsx b/packages/zapp/console/src/components/flytegraph/ReactFlow/transformDAGToReactFlowV2.tsx index 7eb07dec0..9c499d793 100644 --- a/packages/zapp/console/src/components/flytegraph/ReactFlow/transformDAGToReactFlowV2.tsx +++ b/packages/zapp/console/src/components/flytegraph/ReactFlow/transformDAGToReactFlowV2.tsx @@ -3,6 +3,7 @@ import { Edge, Node, Position } from 'react-flow-renderer'; import { CatalogCacheStatus, NodeExecutionPhase, TaskExecutionPhase } from 'models/Execution/enums'; import { createDebugLogger } from 'common/log'; import { LogsByPhase } from 'models/Execution/types'; +import { isMapTaskType } from 'models/Task/utils'; import { ReactFlowGraphConfig } from './utils'; import { ConvertDagProps } from './types'; @@ -84,9 +85,12 @@ const buildReactFlowDataProps = (props: BuildDataProps) => { const nodeLogsByPhase: LogsByPhase = nodeExecutionsById?.[node.scopedId]?.logsByPhase; - const cacheStatus: CatalogCacheStatus = - nodeExecutionsById?.[scopedId]?.closure.taskNodeMetadata?.cacheStatus ?? - CatalogCacheStatus.CACHE_DISABLED; + // get the cache status for mapped task + const isMapCache = isMapTaskType(taskType) && nodeValue?.template?.metadata?.cacheSerializable; + + const cacheStatus: CatalogCacheStatus = isMapCache + ? CatalogCacheStatus.MAP_CACHE + : nodeExecutionsById?.[scopedId]?.closure.taskNodeMetadata?.cacheStatus; const dataProps = { nodeExecutionStatus, diff --git a/packages/zapp/console/src/models/Execution/enums.ts b/packages/zapp/console/src/models/Execution/enums.ts index 3209223ca..da80201b4 100644 --- a/packages/zapp/console/src/models/Execution/enums.ts +++ b/packages/zapp/console/src/models/Execution/enums.ts @@ -17,6 +17,9 @@ export type NodeExecutionPhase = Core.NodeExecution.Phase; export const NodeExecutionPhase = Core.NodeExecution.Phase; export type TaskExecutionPhase = Core.TaskExecution.Phase; export const TaskExecutionPhase = Core.TaskExecution.Phase; -export type CatalogCacheStatus = Core.CatalogCacheStatus; -export const CatalogCacheStatus = Core.CatalogCacheStatus; +enum MapCacheStatus { + MAP_CACHE = 10, +} +export const CatalogCacheStatus = { ...Core.CatalogCacheStatus, ...MapCacheStatus }; +export type CatalogCacheStatus = Core.CatalogCacheStatus | MapCacheStatus; /* eslint-enable @typescript-eslint/no-redeclare */