From 9213ec30a5a4d64483d45cc7d1d117e8504a0ccf Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Tue, 2 Dec 2025 17:37:39 +0100 Subject: [PATCH 1/4] Add new fields to event group getters Signed-off-by: Adhitya Mamallan --- .../get-activity-group-from-events.test.ts | 2 ++ .../get-decision-group-from-events.test.ts | 24 +++++++++++++++++++ ...get-single-event-group-from-events.test.ts | 1 + .../get-activity-group-from-events.ts | 2 ++ .../get-decision-group-from-events.ts | 6 ++++- .../get-single-event-group-from-events.ts | 1 + 6 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-activity-group-from-events.test.ts b/src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-activity-group-from-events.test.ts index 557975d2d..8f7464b4f 100644 --- a/src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-activity-group-from-events.test.ts +++ b/src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-activity-group-from-events.test.ts @@ -395,6 +395,7 @@ describe('getActivityGroupFromEvents', () => { expect(group.eventsMetadata[1].summaryFields).toEqual([ 'heartbeatDetails', 'lastHeartbeatTime', + 'attempt', ]); // The completed event should also have summaryFields @@ -522,6 +523,7 @@ describe('getActivityGroupFromEvents', () => { expect(pendingStartEventMetadata?.summaryFields).toEqual([ 'lastFailureReason', 'lastFailureDetails', + 'attempt', ]); // Other events should not have the same summaryFields diff --git a/src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-decision-group-from-events.test.ts b/src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-decision-group-from-events.test.ts index b359c0b1f..f0bfb21c1 100644 --- a/src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-decision-group-from-events.test.ts +++ b/src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-decision-group-from-events.test.ts @@ -370,6 +370,7 @@ describe('getDecisionGroupFromEvents', () => { ); expect(scheduledEventMetadata?.summaryFields).toEqual([ 'startToCloseTimeoutSeconds', + 'attempt', ]); // Other events should not have summaryFields @@ -380,4 +381,27 @@ describe('getDecisionGroupFromEvents', () => { expect(metadata.summaryFields).toBeUndefined(); }); }); + + it('should include summaryFields for pending decision start events', () => { + const events: ExtendedDecisionHistoryEvent[] = [ + scheduleDecisionTaskEvent, + pendingDecisionTaskStartEvent, + ]; + const group = getDecisionGroupFromEvents(events); + + // The pending start event should have summaryFields + const pendingStartEventMetadata = group.eventsMetadata.find( + (metadata) => metadata.label === 'Starting' + ); + expect(pendingStartEventMetadata?.summaryFields).toEqual(['attempt']); + + // Other events should not have the same summaryFields + const scheduledEventMetadata = group.eventsMetadata.find( + (metadata) => metadata.label === 'Scheduled' + ); + expect(scheduledEventMetadata?.summaryFields).toEqual([ + 'startToCloseTimeoutSeconds', + 'attempt', + ]); + }); }); diff --git a/src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-single-event-group-from-events.test.ts b/src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-single-event-group-from-events.test.ts index c4153ed0c..5ac7dddb3 100644 --- a/src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-single-event-group-from-events.test.ts +++ b/src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-single-event-group-from-events.test.ts @@ -186,6 +186,7 @@ describe('getSingleEventGroupFromEvents', () => { expect(eventMetadata.summaryFields).toEqual([ 'input', 'executionStartToCloseTimeoutSeconds', + 'attempt', ]); }); diff --git a/src/views/workflow-history/helpers/get-history-group-from-events/get-activity-group-from-events.ts b/src/views/workflow-history/helpers/get-history-group-from-events/get-activity-group-from-events.ts index 7956c47b5..04ebc09a7 100644 --- a/src/views/workflow-history/helpers/get-history-group-from-events/get-activity-group-from-events.ts +++ b/src/views/workflow-history/helpers/get-history-group-from-events/get-activity-group-from-events.ts @@ -165,10 +165,12 @@ export default function getActivityGroupFromEvents( pendingActivityTaskStartEventAttributes: [ 'lastFailureReason', 'lastFailureDetails', + 'attempt', ], activityTaskStartedEventAttributes: [ 'heartbeatDetails', 'lastHeartbeatTime', + 'attempt', ], activityTaskCompletedEventAttributes: ['result'], activityTaskFailedEventAttributes: ['details', 'reason'], diff --git a/src/views/workflow-history/helpers/get-history-group-from-events/get-decision-group-from-events.ts b/src/views/workflow-history/helpers/get-history-group-from-events/get-decision-group-from-events.ts index 1827e4aa2..fb47a66e0 100644 --- a/src/views/workflow-history/helpers/get-history-group-from-events/get-decision-group-from-events.ts +++ b/src/views/workflow-history/helpers/get-history-group-from-events/get-decision-group-from-events.ts @@ -122,7 +122,11 @@ export default function getDecisionGroupFromEvents( const eventToSummaryFields: HistoryGroupEventToSummaryFieldsMap = { - decisionTaskScheduledEventAttributes: ['startToCloseTimeoutSeconds'], + decisionTaskScheduledEventAttributes: [ + 'startToCloseTimeoutSeconds', + 'attempt', + ], + pendingDecisionTaskStartEventAttributes: ['attempt'], }; return { diff --git a/src/views/workflow-history/helpers/get-history-group-from-events/get-single-event-group-from-events.ts b/src/views/workflow-history/helpers/get-history-group-from-events/get-single-event-group-from-events.ts index 971b20b56..3f64bd2da 100644 --- a/src/views/workflow-history/helpers/get-history-group-from-events/get-single-event-group-from-events.ts +++ b/src/views/workflow-history/helpers/get-history-group-from-events/get-single-event-group-from-events.ts @@ -99,6 +99,7 @@ export default function getSingleEventGroupFromEvents( workflowExecutionStartedEventAttributes: [ 'input', 'executionStartToCloseTimeoutSeconds', + 'attempt', ], workflowExecutionCompletedEventAttributes: ['result'], workflowExecutionFailedEventAttributes: ['details', 'reason'], From ad922a4482e7f4cafc734b9abaf25ce1867e07f3 Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Wed, 3 Dec 2025 10:39:11 +0100 Subject: [PATCH 2/4] Add retries to summary fields Signed-off-by: Adhitya Mamallan --- ...tory-event-summary-field-parsers.config.ts | 15 +++- .../get-history-event-summary-items.test.ts | 86 +++++++++++++++++++ .../get-history-event-summary-items.ts | 12 ++- .../workflow-history-event-summary.types.ts | 2 + 4 files changed, 111 insertions(+), 4 deletions(-) diff --git a/src/views/workflow-history/config/workflow-history-event-summary-field-parsers.config.ts b/src/views/workflow-history/config/workflow-history-event-summary-field-parsers.config.ts index 69bdf4fb6..8253c2928 100644 --- a/src/views/workflow-history/config/workflow-history-event-summary-field-parsers.config.ts +++ b/src/views/workflow-history/config/workflow-history-event-summary-field-parsers.config.ts @@ -1,4 +1,8 @@ -import { MdOutlineMonitorHeart, MdOutlineTimer } from 'react-icons/md'; +import { + MdHourglassBottom, + MdOutlineMonitorHeart, + MdReplay, +} from 'react-icons/md'; import { type WorkflowHistoryEventSummaryFieldParser } from '../workflow-history-event-summary/workflow-history-event-summary.types'; import WorkflowHistoryEventSummaryJson from '../workflow-history-event-summary-json/workflow-history-event-summary-json'; @@ -25,7 +29,14 @@ const workflowHistoryEventSummaryFieldParsersConfig: Array new RegExp('(TimeoutSeconds|BackoffSeconds|InSeconds)$').test(name), - icon: MdOutlineTimer, + icon: MdHourglassBottom, + }, + { + name: 'Retries with retry icon', + matcher: (name) => name === 'attempt', + shouldHide: (_, value) => typeof value === 'number' && value <= 0, + icon: MdReplay, + tooltipLabel: 'retries', }, ]; diff --git a/src/views/workflow-history/workflow-history-event-summary/helpers/__tests__/get-history-event-summary-items.test.ts b/src/views/workflow-history/workflow-history-event-summary/helpers/__tests__/get-history-event-summary-items.test.ts index 5003e69be..31dcaeebe 100644 --- a/src/views/workflow-history/workflow-history-event-summary/helpers/__tests__/get-history-event-summary-items.test.ts +++ b/src/views/workflow-history/workflow-history-event-summary/helpers/__tests__/get-history-event-summary-items.test.ts @@ -81,6 +81,38 @@ jest.mock( isGroup: true, groupEntries: [], }, + { + key: 'hiddenField', + path: 'hiddenField', + value: 'hide-me', + renderConfig: { + name: 'Test Config', + key: 'test', + getLabel: ({ path }) => `Label: ${path}`, + }, + isGroup: false, + }, + { + key: 'tooltipField', + path: 'tooltipField', + value: 'test-value', + renderConfig: { + name: 'Test Config', + key: 'test', + getLabel: ({ path }) => `Label: ${path}`, + }, + isGroup: false, + }, + { + key: 'defaultPathField', + path: 'defaultPathField', + value: 'test-value', + renderConfig: { + name: 'Test Config', + key: 'test', + }, + isGroup: false, + }, ] satisfies WorkflowHistoryEventDetailsEntries ) ); @@ -112,6 +144,18 @@ jest.mock( matcher: (path) => path === 'firstExecutionRunId', icon: jest.fn(), }, + { + name: 'Hidden Field Parser', + matcher: (path) => path === 'hiddenField', + icon: jest.fn(), + shouldHide: jest.fn((_, value) => value === 'hide-me'), + }, + { + name: 'Tooltip Label Parser', + matcher: (path) => path === 'tooltipField', + icon: jest.fn(), + tooltipLabel: 'Custom Tooltip Label', + }, ] satisfies Array ); @@ -279,4 +323,46 @@ describe(getHistoryEventSummaryItems.name, () => { expect(result[0].path).toBe('workflowExecution'); expect(result[0].renderValue).toBeDefined(); }); + + it('should exclude fields when shouldHide returns true', () => { + const details = { hiddenField: 'hide-me' }; + const summaryFields = ['hiddenField']; + + const result = getHistoryEventSummaryItems({ details, summaryFields }); + + expect(result).toHaveLength(0); + }); + + it('should use tooltipLabel from parser config when set', () => { + const details = { tooltipField: 'test-value' }; + const summaryFields = ['tooltipField']; + + const result = getHistoryEventSummaryItems({ details, summaryFields }); + + expect(result).toHaveLength(1); + expect(result[0].path).toBe('tooltipField'); + expect(result[0].label).toBe('Custom Tooltip Label'); + }); + + it('should use getLabel from renderConfig when tooltipLabel is not set in parser config', () => { + const details = { input: { data: 'test' } }; + const summaryFields = ['input']; + + const result = getHistoryEventSummaryItems({ details, summaryFields }); + + expect(result).toHaveLength(1); + expect(result[0].path).toBe('input'); + expect(result[0].label).toBe('Label: input'); + }); + + it('should default to path when neither tooltipLabel nor getLabel is available', () => { + const details = { defaultPathField: 'test-value' }; + const summaryFields = ['defaultPathField']; + + const result = getHistoryEventSummaryItems({ details, summaryFields }); + + expect(result).toHaveLength(1); + expect(result[0].path).toBe('defaultPathField'); + expect(result[0].label).toBe('defaultPathField'); + }); }); diff --git a/src/views/workflow-history/workflow-history-event-summary/helpers/get-history-event-summary-items.ts b/src/views/workflow-history/workflow-history-event-summary/helpers/get-history-event-summary-items.ts index effc8b1e9..0d16e8451 100644 --- a/src/views/workflow-history/workflow-history-event-summary/helpers/get-history-event-summary-items.ts +++ b/src/views/workflow-history/workflow-history-event-summary/helpers/get-history-event-summary-items.ts @@ -33,7 +33,9 @@ export default function getHistoryEventSummaryItems({ ); let renderValue: ComponentType; - if (summaryFieldParserConfig?.customRenderValue) { + if (summaryFieldParserConfig?.shouldHide?.(path, value)) { + return acc; + } else if (summaryFieldParserConfig?.customRenderValue) { renderValue = summaryFieldParserConfig.customRenderValue; } else if (renderConfig?.valueComponent) { const detailsRenderValue = renderConfig?.valueComponent; @@ -49,9 +51,15 @@ export default function getHistoryEventSummaryItems({ renderValue = ({ value }) => String(value); } + let tooltipLabel = path; + if (summaryFieldParserConfig?.tooltipLabel) { + tooltipLabel = summaryFieldParserConfig.tooltipLabel; + } else if (renderConfig?.getLabel) + tooltipLabel = renderConfig.getLabel({ key, path, value }); + acc.push({ path, - label: renderConfig?.getLabel?.({ key, path, value }) ?? path, + label: tooltipLabel, value, icon: summaryFieldParserConfig?.icon ?? null, renderValue, diff --git a/src/views/workflow-history/workflow-history-event-summary/workflow-history-event-summary.types.ts b/src/views/workflow-history/workflow-history-event-summary/workflow-history-event-summary.types.ts index e9f87196f..0c8425e99 100644 --- a/src/views/workflow-history/workflow-history-event-summary/workflow-history-event-summary.types.ts +++ b/src/views/workflow-history/workflow-history-event-summary/workflow-history-event-summary.types.ts @@ -22,6 +22,8 @@ export type WorkflowHistoryEventSummaryFieldParser = { size?: IconProps['size']; color?: IconProps['color']; }> | null; + shouldHide?: (path: string, value: unknown) => boolean; + tooltipLabel?: string; customRenderValue?: ComponentType; hideDefaultTooltip?: boolean; }; From 34f79d98f3dadab9ceb75ea3d1507a891b875ba4 Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Wed, 3 Dec 2025 11:19:11 +0100 Subject: [PATCH 3/4] Hide retries from summary in v1 Signed-off-by: Adhitya Mamallan --- .../workflow-history-event-summary-field-parsers.config.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/views/workflow-history/config/workflow-history-event-summary-field-parsers.config.ts b/src/views/workflow-history/config/workflow-history-event-summary-field-parsers.config.ts index 8253c2928..6b844d46e 100644 --- a/src/views/workflow-history/config/workflow-history-event-summary-field-parsers.config.ts +++ b/src/views/workflow-history/config/workflow-history-event-summary-field-parsers.config.ts @@ -32,11 +32,10 @@ const workflowHistoryEventSummaryFieldParsersConfig: Array name === 'attempt', - shouldHide: (_, value) => typeof value === 'number' && value <= 0, - icon: MdReplay, - tooltipLabel: 'retries', + shouldHide: () => true, + icon: null, }, ]; From 49ba0318f1418f90bd5f9da1d770bfbf4a16c482 Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Wed, 3 Dec 2025 11:22:39 +0100 Subject: [PATCH 4/4] fix imports Signed-off-by: Adhitya Mamallan --- .../workflow-history-event-summary-field-parsers.config.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/views/workflow-history/config/workflow-history-event-summary-field-parsers.config.ts b/src/views/workflow-history/config/workflow-history-event-summary-field-parsers.config.ts index 6b844d46e..537f48f82 100644 --- a/src/views/workflow-history/config/workflow-history-event-summary-field-parsers.config.ts +++ b/src/views/workflow-history/config/workflow-history-event-summary-field-parsers.config.ts @@ -1,8 +1,4 @@ -import { - MdHourglassBottom, - MdOutlineMonitorHeart, - MdReplay, -} from 'react-icons/md'; +import { MdHourglassBottom, MdOutlineMonitorHeart } from 'react-icons/md'; import { type WorkflowHistoryEventSummaryFieldParser } from '../workflow-history-event-summary/workflow-history-event-summary.types'; import WorkflowHistoryEventSummaryJson from '../workflow-history-event-summary-json/workflow-history-event-summary-json';