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..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,4 +1,4 @@ -import { MdOutlineMonitorHeart, MdOutlineTimer } 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'; @@ -25,7 +25,13 @@ const workflowHistoryEventSummaryFieldParsersConfig: Array new RegExp('(TimeoutSeconds|BackoffSeconds|InSeconds)$').test(name), - icon: MdOutlineTimer, + icon: MdHourglassBottom, + }, + { + name: 'Hide retryAttempt from summary in History V1', + matcher: (name) => name === 'attempt', + shouldHide: () => true, + icon: null, }, ]; 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'], 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; };