From af65c24e048459329a246a6773636e5007b97fc3 Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Tue, 2 Dec 2025 16:44:11 +0100 Subject: [PATCH 01/15] Copy utils from v1 to v2 Signed-off-by: Adhitya Mamallan --- .../config/workflow-history-event-group-details.config.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/views/workflow-history-v2/config/workflow-history-event-group-details.config.ts b/src/views/workflow-history-v2/config/workflow-history-event-group-details.config.ts index 71d7761b9..6a002c670 100644 --- a/src/views/workflow-history-v2/config/workflow-history-event-group-details.config.ts +++ b/src/views/workflow-history-v2/config/workflow-history-event-group-details.config.ts @@ -55,7 +55,10 @@ const workflowHistoryEventGroupDetailsConfig = [ pathRegex: '(input|result|details|failureDetails|Error|lastCompletionResult|heartbeatDetails|lastFailureDetails)$', showInPanels: true, +<<<<<<< HEAD valueComponent: WorkflowHistoryGroupDetailsJson, +======= +>>>>>>> e99f9e96 (Copy utils from v1 to v2) }, { name: 'Duration & interval seconds', From 14ba0334b10d71b55d6ec0a17e8155f46d56c599 Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Wed, 3 Dec 2025 10:47:29 +0100 Subject: [PATCH 02/15] Add JSON component and allow custom components for panels Signed-off-by: Adhitya Mamallan --- .../config/workflow-history-event-group-details.config.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/views/workflow-history-v2/config/workflow-history-event-group-details.config.ts b/src/views/workflow-history-v2/config/workflow-history-event-group-details.config.ts index 6a002c670..71d7761b9 100644 --- a/src/views/workflow-history-v2/config/workflow-history-event-group-details.config.ts +++ b/src/views/workflow-history-v2/config/workflow-history-event-group-details.config.ts @@ -55,10 +55,7 @@ const workflowHistoryEventGroupDetailsConfig = [ pathRegex: '(input|result|details|failureDetails|Error|lastCompletionResult|heartbeatDetails|lastFailureDetails)$', showInPanels: true, -<<<<<<< HEAD valueComponent: WorkflowHistoryGroupDetailsJson, -======= ->>>>>>> e99f9e96 (Copy utils from v1 to v2) }, { name: 'Duration & interval seconds', From 58244e3d103b91a3ea5325ec1f382f477941e8ab Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Tue, 2 Dec 2025 17:29:17 +0100 Subject: [PATCH 03/15] add changes Signed-off-by: Adhitya Mamallan --- .../__tests__/workflow-history-event-group.test.tsx | 1 + .../workflow-history-grouped-table.tsx | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/views/workflow-history-v2/workflow-history-event-group/__tests__/workflow-history-event-group.test.tsx b/src/views/workflow-history-v2/workflow-history-event-group/__tests__/workflow-history-event-group.test.tsx index fa732b165..d1f6cd592 100644 --- a/src/views/workflow-history-v2/workflow-history-event-group/__tests__/workflow-history-event-group.test.tsx +++ b/src/views/workflow-history-v2/workflow-history-event-group/__tests__/workflow-history-event-group.test.tsx @@ -582,6 +582,7 @@ function setup({ render( ( + itemContent={(_, [groupId, group]) => ( Date: Wed, 3 Dec 2025 12:37:29 +0100 Subject: [PATCH 04/15] More changes Signed-off-by: Adhitya Mamallan --- .../workflow-history-event-details.config.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/views/workflow-history/config/workflow-history-event-details.config.ts b/src/views/workflow-history/config/workflow-history-event-details.config.ts index 1eb57d8fa..c73c14dbc 100644 --- a/src/views/workflow-history/config/workflow-history-event-details.config.ts +++ b/src/views/workflow-history/config/workflow-history-event-details.config.ts @@ -9,17 +9,32 @@ import { type WorkflowHistoryEventDetailsConfig } from '../workflow-history-even import WorkflowHistoryEventDetailsJson from '../workflow-history-event-details-json/workflow-history-event-details-json'; import WorkflowHistoryEventDetailsPlaceholderText from '../workflow-history-event-details-placeholder-text/workflow-history-event-details-placeholder-text'; +/** + * Configuration array for customizing how workflow history event details are rendered. + * Each config entry defines matching criteria and rendering behavior for specific event fields. + * Configs are evaluated in order, and the first matching config is applied to each field. + */ const workflowHistoryEventDetailsConfig = [ + /** + * Hides fields with null or undefined values from the event details display. + */ { name: 'Filter empty value', customMatcher: ({ value }) => value === null || value === undefined, hide: () => true, }, + /** + * Hides internal fields (taskId, eventType) that are not useful for display. + */ { name: 'Filter unneeded values', pathRegex: '(taskId|eventType)$', hide: () => true, }, + /** + * Displays a placeholder text for timeout/retry fields that are set to 0 (not configured). + * Also removes the "Seconds" suffix from labels since formatted durations may be in minutes/hours. + */ { name: 'Not set placeholder', customMatcher: ({ value, path }) => { @@ -34,11 +49,17 @@ const workflowHistoryEventDetailsConfig = [ valueComponent: () => createElement(WorkflowHistoryEventDetailsPlaceholderText), }, + /** + * Formats Date objects as human-readable time strings. + */ { name: 'Date object as time string', customMatcher: ({ value }) => value instanceof Date, valueComponent: ({ entryValue }) => formatDate(entryValue), }, + /** + * Renders task list names as clickable links that navigate to the task list view. + */ { name: 'Tasklists as links', key: 'taskList', @@ -50,6 +71,10 @@ const workflowHistoryEventDetailsConfig = [ }); }, }, + /** + * Renders JSON fields (input, result, details, etc.) as formatted PrettyJson components. + * Uses forceWrap to ensure proper wrapping of long JSON content. + */ { name: 'Json as PrettyJson', pathRegex: @@ -57,6 +82,10 @@ const workflowHistoryEventDetailsConfig = [ valueComponent: WorkflowHistoryEventDetailsJson, forceWrap: true, }, + /** + * Formats duration fields (ending in TimeoutSeconds, BackoffSeconds, or InSeconds) as human-readable durations. + * Removes the "Seconds" suffix from labels since formatted durations may be in minutes/hours. + */ { name: 'Duration & interval seconds', pathRegex: '(TimeoutSeconds|BackoffSeconds|InSeconds)$', @@ -64,6 +93,10 @@ const workflowHistoryEventDetailsConfig = [ valueComponent: ({ entryValue }) => formatDuration({ seconds: entryValue > 0 ? entryValue : 0, nanos: 0 }), }, + /** + * Renders workflow execution objects as clickable links that navigate to the workflow view. + * Applies to parentWorkflowExecution, externalWorkflowExecution, and workflowExecution fields. + */ { name: 'WorkflowExecution as link', pathRegex: @@ -77,6 +110,10 @@ const workflowHistoryEventDetailsConfig = [ }); }, }, + /** + * Renders run ID fields as clickable links that navigate to the corresponding workflow run. + * Applies to firstExecutionRunId, originalExecutionRunId, newExecutionRunId, and continuedExecutionRunId. + */ { name: 'RunIds as link', pathRegex: @@ -90,6 +127,9 @@ const workflowHistoryEventDetailsConfig = [ }); }, }, + /** + * Renames the "attempt" field label to "retryAttempt" for better clarity. + */ { name: 'Retry config attempt as retryAttempt', key: 'attempt', From 21bb81874de7fcca937b69100839d53a46e09e4f Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Wed, 3 Dec 2025 14:58:18 +0100 Subject: [PATCH 05/15] Add unit tests and isolate prop types Signed-off-by: Adhitya Mamallan --- .../workflow-history-event-details.config.ts | 40 ------------------- 1 file changed, 40 deletions(-) diff --git a/src/views/workflow-history/config/workflow-history-event-details.config.ts b/src/views/workflow-history/config/workflow-history-event-details.config.ts index c73c14dbc..1eb57d8fa 100644 --- a/src/views/workflow-history/config/workflow-history-event-details.config.ts +++ b/src/views/workflow-history/config/workflow-history-event-details.config.ts @@ -9,32 +9,17 @@ import { type WorkflowHistoryEventDetailsConfig } from '../workflow-history-even import WorkflowHistoryEventDetailsJson from '../workflow-history-event-details-json/workflow-history-event-details-json'; import WorkflowHistoryEventDetailsPlaceholderText from '../workflow-history-event-details-placeholder-text/workflow-history-event-details-placeholder-text'; -/** - * Configuration array for customizing how workflow history event details are rendered. - * Each config entry defines matching criteria and rendering behavior for specific event fields. - * Configs are evaluated in order, and the first matching config is applied to each field. - */ const workflowHistoryEventDetailsConfig = [ - /** - * Hides fields with null or undefined values from the event details display. - */ { name: 'Filter empty value', customMatcher: ({ value }) => value === null || value === undefined, hide: () => true, }, - /** - * Hides internal fields (taskId, eventType) that are not useful for display. - */ { name: 'Filter unneeded values', pathRegex: '(taskId|eventType)$', hide: () => true, }, - /** - * Displays a placeholder text for timeout/retry fields that are set to 0 (not configured). - * Also removes the "Seconds" suffix from labels since formatted durations may be in minutes/hours. - */ { name: 'Not set placeholder', customMatcher: ({ value, path }) => { @@ -49,17 +34,11 @@ const workflowHistoryEventDetailsConfig = [ valueComponent: () => createElement(WorkflowHistoryEventDetailsPlaceholderText), }, - /** - * Formats Date objects as human-readable time strings. - */ { name: 'Date object as time string', customMatcher: ({ value }) => value instanceof Date, valueComponent: ({ entryValue }) => formatDate(entryValue), }, - /** - * Renders task list names as clickable links that navigate to the task list view. - */ { name: 'Tasklists as links', key: 'taskList', @@ -71,10 +50,6 @@ const workflowHistoryEventDetailsConfig = [ }); }, }, - /** - * Renders JSON fields (input, result, details, etc.) as formatted PrettyJson components. - * Uses forceWrap to ensure proper wrapping of long JSON content. - */ { name: 'Json as PrettyJson', pathRegex: @@ -82,10 +57,6 @@ const workflowHistoryEventDetailsConfig = [ valueComponent: WorkflowHistoryEventDetailsJson, forceWrap: true, }, - /** - * Formats duration fields (ending in TimeoutSeconds, BackoffSeconds, or InSeconds) as human-readable durations. - * Removes the "Seconds" suffix from labels since formatted durations may be in minutes/hours. - */ { name: 'Duration & interval seconds', pathRegex: '(TimeoutSeconds|BackoffSeconds|InSeconds)$', @@ -93,10 +64,6 @@ const workflowHistoryEventDetailsConfig = [ valueComponent: ({ entryValue }) => formatDuration({ seconds: entryValue > 0 ? entryValue : 0, nanos: 0 }), }, - /** - * Renders workflow execution objects as clickable links that navigate to the workflow view. - * Applies to parentWorkflowExecution, externalWorkflowExecution, and workflowExecution fields. - */ { name: 'WorkflowExecution as link', pathRegex: @@ -110,10 +77,6 @@ const workflowHistoryEventDetailsConfig = [ }); }, }, - /** - * Renders run ID fields as clickable links that navigate to the corresponding workflow run. - * Applies to firstExecutionRunId, originalExecutionRunId, newExecutionRunId, and continuedExecutionRunId. - */ { name: 'RunIds as link', pathRegex: @@ -127,9 +90,6 @@ const workflowHistoryEventDetailsConfig = [ }); }, }, - /** - * Renames the "attempt" field label to "retryAttempt" for better clarity. - */ { name: 'Retry config attempt as retryAttempt', key: 'attempt', From db034dee84e2ae701da696d3e26018eecb3034fe Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Fri, 5 Dec 2025 12:06:30 +0100 Subject: [PATCH 06/15] address comments Signed-off-by: Adhitya Mamallan --- .../__tests__/workflow-history-event-group.test.tsx | 1 - .../workflow-history-grouped-table.tsx | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/views/workflow-history-v2/workflow-history-event-group/__tests__/workflow-history-event-group.test.tsx b/src/views/workflow-history-v2/workflow-history-event-group/__tests__/workflow-history-event-group.test.tsx index d1f6cd592..fa732b165 100644 --- a/src/views/workflow-history-v2/workflow-history-event-group/__tests__/workflow-history-event-group.test.tsx +++ b/src/views/workflow-history-v2/workflow-history-event-group/__tests__/workflow-history-event-group.test.tsx @@ -582,7 +582,6 @@ function setup({ render( ( + itemContent={(_, [__, group]) => ( Date: Wed, 3 Dec 2025 17:27:59 +0100 Subject: [PATCH 07/15] Add single-line summary for history events Signed-off-by: Adhitya Mamallan --- .../workflow-history-event-group.styles.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/views/workflow-history-v2/workflow-history-event-group/workflow-history-event-group.styles.ts b/src/views/workflow-history-v2/workflow-history-event-group/workflow-history-event-group.styles.ts index b2d9ce5d6..1534eab32 100644 --- a/src/views/workflow-history-v2/workflow-history-event-group/workflow-history-event-group.styles.ts +++ b/src/views/workflow-history-v2/workflow-history-event-group/workflow-history-event-group.styles.ts @@ -35,9 +35,15 @@ export const styled = { gap: $theme.sizing.scale300, alignItems: 'center', })), - SummarizedDetailsContainer: createStyled('div', { - overflow: 'hidden', - }), + SummarizedDetailsContainer: createStyled( + 'div', + ({ $theme }: { $theme: Theme }) => ({ + overflow: 'hidden', + [$theme.mediaQuery.medium]: { + margin: `-${$theme.sizing.scale200} 0`, + }, + }) + ), ActionsContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ display: 'flex', gap: $theme.sizing.scale300, From 2090a2246c1f824d24a5d2ec2b5d13d16eaed7b5 Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Thu, 4 Dec 2025 16:35:02 +0100 Subject: [PATCH 08/15] Add basic ungrouped table Signed-off-by: Adhitya Mamallan --- .../workflow-history-ungrouped-table.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/views/workflow-history-v2/workflow-history-ungrouped-table/workflow-history-ungrouped-table.tsx b/src/views/workflow-history-v2/workflow-history-ungrouped-table/workflow-history-ungrouped-table.tsx index 1305d1298..15e1af579 100644 --- a/src/views/workflow-history-v2/workflow-history-ungrouped-table/workflow-history-ungrouped-table.tsx +++ b/src/views/workflow-history-v2/workflow-history-ungrouped-table/workflow-history-ungrouped-table.tsx @@ -2,11 +2,18 @@ import { useMemo } from 'react'; import { Virtuoso } from 'react-virtuoso'; +<<<<<<< HEAD +======= +import compareUngroupedEvents from '@/views/workflow-history/helpers/compare-ungrouped-events'; +>>>>>>> d60602c5 (Add basic ungrouped table) import WorkflowHistoryTimelineLoadMore from '@/views/workflow-history/workflow-history-timeline-load-more/workflow-history-timeline-load-more'; import WorkflowHistoryUngroupedEvent from '../workflow-history-ungrouped-event/workflow-history-ungrouped-event'; +<<<<<<< HEAD import compareUngroupedEvents from './helpers/compare-ungrouped-events'; +======= +>>>>>>> d60602c5 (Add basic ungrouped table) import { styled } from './workflow-history-ungrouped-table.styles'; import { type UngroupedEventInfo, From 7e11bfeb12a2e55191f9be3a4dfe04e6bf5e0e35 Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Thu, 4 Dec 2025 19:25:23 +0100 Subject: [PATCH 09/15] Change types and add helper Signed-off-by: Adhitya Mamallan --- .../workflow-history-ungrouped-table.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/views/workflow-history-v2/workflow-history-ungrouped-table/workflow-history-ungrouped-table.tsx b/src/views/workflow-history-v2/workflow-history-ungrouped-table/workflow-history-ungrouped-table.tsx index 15e1af579..1305d1298 100644 --- a/src/views/workflow-history-v2/workflow-history-ungrouped-table/workflow-history-ungrouped-table.tsx +++ b/src/views/workflow-history-v2/workflow-history-ungrouped-table/workflow-history-ungrouped-table.tsx @@ -2,18 +2,11 @@ import { useMemo } from 'react'; import { Virtuoso } from 'react-virtuoso'; -<<<<<<< HEAD -======= -import compareUngroupedEvents from '@/views/workflow-history/helpers/compare-ungrouped-events'; ->>>>>>> d60602c5 (Add basic ungrouped table) import WorkflowHistoryTimelineLoadMore from '@/views/workflow-history/workflow-history-timeline-load-more/workflow-history-timeline-load-more'; import WorkflowHistoryUngroupedEvent from '../workflow-history-ungrouped-event/workflow-history-ungrouped-event'; -<<<<<<< HEAD import compareUngroupedEvents from './helpers/compare-ungrouped-events'; -======= ->>>>>>> d60602c5 (Add basic ungrouped table) import { styled } from './workflow-history-ungrouped-table.styles'; import { type UngroupedEventInfo, From 7369e168430eadb3e5fe4dc20941a4b063bf3763 Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Thu, 4 Dec 2025 20:59:19 +0100 Subject: [PATCH 10/15] more changes to ungrouped event Signed-off-by: Adhitya Mamallan --- ...workflow-history-ungrouped-event.styles.ts | 165 +++++++++++++++++- .../workflow-history-ungrouped-event.tsx | 141 ++++++++++++++- 2 files changed, 299 insertions(+), 7 deletions(-) diff --git a/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.styles.ts b/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.styles.ts index 8a65a8bd9..11c4f79f0 100644 --- a/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.styles.ts +++ b/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.styles.ts @@ -1,9 +1,166 @@ import { styled as createStyled, type Theme } from 'baseui'; +import { type PanelOverrides } from 'baseui/accordion'; +import { type BadgeOverrides } from 'baseui/badge'; +import { type StyleObject } from 'styletron-react'; + +import { type WorkflowHistoryEventFilteringType } from '@/views/workflow-history/workflow-history-filters-type/workflow-history-filters-type.types'; + +import workflowHistoryEventFilteringTypeColorsConfig from '../config/workflow-history-event-filtering-type-colors.config'; +import { WORKFLOW_HISTORY_UNGROUPED_GRID_TEMPLATE_COLUMNS } from '../workflow-history-ungrouped-table/workflow-history-ungrouped-table.constants'; export const styled = { - TempContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ - ...$theme.typography.MonoParagraphXSmall, - padding: $theme.sizing.scale300, - ...$theme.borders.border100, + HeaderContent: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ + ...$theme.typography.ParagraphSmall, + display: 'flex', + flexDirection: 'column', + gap: $theme.sizing.scale200, + paddingBottom: $theme.sizing.scale300, + [$theme.mediaQuery.medium]: { + display: 'grid', + gridTemplateColumns: WORKFLOW_HISTORY_UNGROUPED_GRID_TEMPLATE_COLUMNS, + width: '100%', + alignItems: 'center', + gap: $theme.sizing.scale600, + paddingBottom: 0, + }, + })), + HeaderLabel: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ + ...$theme.typography.LabelSmall, + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + overflow: 'hidden', })), + StatusContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ + display: 'flex', + gap: $theme.sizing.scale300, + alignItems: 'center', + })), + SummarizedDetailsContainer: createStyled( + 'div', + ({ $theme }: { $theme: Theme }) => ({ + overflow: 'hidden', + [$theme.mediaQuery.medium]: { + margin: `-${$theme.sizing.scale200} 0`, + }, + }) + ), + ActionsContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ + display: 'flex', + gap: $theme.sizing.scale300, + alignItems: 'center', + [$theme.mediaQuery.medium]: { + margin: `-${$theme.sizing.scale200} 0`, + }, + })), + GroupDetailsGridContainer: createStyled('div', { + display: 'grid', + gridTemplateColumns: WORKFLOW_HISTORY_UNGROUPED_GRID_TEMPLATE_COLUMNS, + }), + GroupDetailsNameSpacer: createStyled( + 'div', + ({ $theme }: { $theme: Theme }) => ({ + display: 'none', + [$theme.mediaQuery.medium]: { + gridColumn: '1 / span 3', + }, + }) + ), + GroupDetailsContainer: createStyled( + 'div', + ({ $theme }: { $theme: Theme }) => ({ + gridColumn: '1 / -1', + [$theme.mediaQuery.medium]: { + gridColumn: '4 / -1', + }, + border: `2px solid ${$theme.colors.borderOpaque}`, + borderRadius: $theme.borders.radius400, + padding: $theme.sizing.scale500, + backgroundColor: $theme.colors.backgroundPrimary, + }) + ), }; + +export const overrides = ( + eventFilteringType: WorkflowHistoryEventFilteringType, + animateOnEnter?: boolean +) => ({ + panel: { + PanelContainer: { + style: ({ $theme }: { $theme: Theme }): StyleObject => ({ + borderColor: $theme.borders.border100.borderColor, + borderStyle: $theme.borders.border100.borderStyle, + borderRadius: 0, + borderTopWidth: $theme.borders.border100.borderWidth, + borderBottomWidth: 0, + borderLeftWidth: 0, + borderRightWidth: 0, + marginTop: 0, + marginBottom: 0, + overflow: 'hidden', + }), + }, + Header: { + style: ({ $theme }: { $theme: Theme }): StyleObject => ({ + // https://github.com/uber/baseweb/blob/main/src/accordion/styled-components.ts#L50 + // Since the original Panel uses longhand properties, we need to use longhand in overrides + paddingTop: $theme.sizing.scale300, + paddingBottom: $theme.sizing.scale300, + paddingLeft: $theme.sizing.scale300, + paddingRight: $theme.sizing.scale300, + backgroundColor: 'inherit', + display: 'flex', + alignItems: 'center', + ':hover': { + backgroundColor: + workflowHistoryEventFilteringTypeColorsConfig[eventFilteringType] + .backgroundHighlighted, + }, + ...(animateOnEnter && { + animationDuration: '2s', + animationName: { + from: { + backgroundColor: + workflowHistoryEventFilteringTypeColorsConfig[ + eventFilteringType + ].backgroundHighlighted, + }, + to: { + backgroundColor: 'inherit', + }, + }, + }), + }), + }, + Content: { + style: ({ $theme }: { $theme: Theme }): StyleObject => ({ + // https://github.com/uber/baseweb/blob/main/src/accordion/styled-components.ts#L102 + // Since the original Panel uses longhand properties, we need to use longhand in overrides + paddingTop: 0, + paddingBottom: $theme.sizing.scale600, + paddingLeft: 0, + paddingRight: 0, + [$theme.mediaQuery.medium]: { + paddingLeft: $theme.sizing.scale700, + paddingRight: $theme.sizing.scale700, + }, + backgroundColor: 'inherit', + }), + }, + ToggleIcon: { + style: { + display: 'none', + }, + }, + } satisfies PanelOverrides, + badge: { + Badge: { + style: ({ $theme }: { $theme: Theme }): StyleObject => ({ + backgroundColor: $theme.colors.backgroundSecondary, + color: $theme.colors.contentSecondary, + ...$theme.typography.LabelXSmall, + whiteSpace: 'nowrap', + marginLeft: $theme.sizing.scale100, + }), + }, + } satisfies BadgeOverrides, +}); diff --git a/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.tsx b/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.tsx index 47d543dc9..9a5193c02 100644 --- a/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.tsx +++ b/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.tsx @@ -1,8 +1,143 @@ -import { styled } from './workflow-history-ungrouped-event.styles'; +import { useCallback, useMemo } from 'react'; + +import { Panel } from 'baseui/accordion'; +import { MdOutlineCircle } from 'react-icons/md'; + +import formatDate from '@/utils/data-formatters/format-date'; +import parseGrpcTimestamp from '@/utils/datetime/parse-grpc-timestamp'; +import WorkflowHistoryEventStatusBadge from '@/views/workflow-history/workflow-history-event-status-badge/workflow-history-event-status-badge'; +import WorkflowHistoryGroupLabel from '@/views/workflow-history/workflow-history-group-label/workflow-history-group-label'; +import WorkflowHistoryTimelineResetButton from '@/views/workflow-history/workflow-history-timeline-reset-button/workflow-history-timeline-reset-button'; + +import workflowHistoryEventFilteringTypeColorsConfig from '../config/workflow-history-event-filtering-type-colors.config'; +import generateHistoryGroupDetails from '../helpers/generate-history-group-details'; +import WorkflowHistoryDetailsRow from '../workflow-history-details-row/workflow-history-details-row'; +import getEventGroupFilteringType from '../workflow-history-event-group/helpers/get-event-group-filtering-type'; +import getFormattedEventsDuration from '../workflow-history-event-group-duration/helpers/get-formatted-events-duration'; +import WorkflowHistoryGroupDetails from '../workflow-history-group-details/workflow-history-group-details'; + +import { + styled, + overrides as getOverrides, +} from './workflow-history-ungrouped-event.styles'; import { type Props } from './workflow-history-ungrouped-event.types'; -export default function WorkflowHistoryUngroupedEvent({ eventInfo }: Props) { +export default function WorkflowHistoryUngroupedEvent({ + eventInfo, + animateOnEnter, + workflowStartTimeMs, + onReset, + decodedPageUrlParams, + isExpanded, + toggleIsExpanded, +}: Props) { + const eventFilteringType = getEventGroupFilteringType(eventInfo.eventGroup); + + const overrides = getOverrides(eventFilteringType, animateOnEnter); + + const handleReset = useCallback(() => { + if (onReset) { + onReset(); + } + }, [onReset]); + + const { groupDetailsEntries, summaryDetailsEntries } = useMemo( + () => generateHistoryGroupDetails(eventInfo.eventGroup), + [eventInfo.eventGroup] + ); + + const eventSummaryDetails = summaryDetailsEntries.find( + ([eventId]) => eventId === eventInfo.id + )?.[1].eventDetails; + return ( - {JSON.stringify(eventInfo)} + + + {eventInfo.id} + + + + + + {eventInfo.eventMetadata.label} + +
+ {eventInfo.event.eventTime + ? formatDate(parseGrpcTimestamp(eventInfo.event.eventTime)) + : null} +
+
+ {eventInfo.event.eventTime && workflowStartTimeMs + ? getFormattedEventsDuration( + workflowStartTimeMs, + parseGrpcTimestamp(eventInfo.event.eventTime) + ) + : null} +
+ + {eventSummaryDetails && eventSummaryDetails.length > 0 ? ( + + ) : ( +
+ )} + + + {eventInfo.canReset && ( + + )} + + + } + expanded={isExpanded} + onChange={toggleIsExpanded} + overrides={overrides.panel} + > + + + + + eventSummaryDetails.eventDetails + ), + eventLabel: 'Summary', + }, + ], + ...groupDetailsEntries, + ]} + initialEventId={eventInfo.id} + workflowPageParams={decodedPageUrlParams} + onClose={() => toggleIsExpanded()} + /> + + + ); } From 6e84df9a849b00ca889934702507de50b23c9b60 Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Mon, 8 Dec 2025 16:28:13 +0100 Subject: [PATCH 11/15] add tests Signed-off-by: Adhitya Mamallan --- .../workflow-history-ungrouped-event.test.tsx | 457 ++++++++++++++++++ 1 file changed, 457 insertions(+) create mode 100644 src/views/workflow-history-v2/workflow-history-ungrouped-event/__tests__/workflow-history-ungrouped-event.test.tsx diff --git a/src/views/workflow-history-v2/workflow-history-ungrouped-event/__tests__/workflow-history-ungrouped-event.test.tsx b/src/views/workflow-history-v2/workflow-history-ungrouped-event/__tests__/workflow-history-ungrouped-event.test.tsx new file mode 100644 index 000000000..cef0b1f2b --- /dev/null +++ b/src/views/workflow-history-v2/workflow-history-ungrouped-event/__tests__/workflow-history-ungrouped-event.test.tsx @@ -0,0 +1,457 @@ +import { render, screen, userEvent } from '@/test-utils/rtl'; + +import { scheduleActivityTaskEvent } from '@/views/workflow-history/__fixtures__/workflow-history-activity-events'; +import { mockActivityEventGroup } from '@/views/workflow-history/__fixtures__/workflow-history-event-groups'; +import type WorkflowHistoryEventStatusBadge from '@/views/workflow-history/workflow-history-event-status-badge/workflow-history-event-status-badge'; +import type WorkflowHistoryGroupLabel from '@/views/workflow-history/workflow-history-group-label/workflow-history-group-label'; +import type WorkflowHistoryTimelineResetButton from '@/views/workflow-history/workflow-history-timeline-reset-button/workflow-history-timeline-reset-button'; +import { + type ExtendedHistoryEvent, + type ActivityHistoryGroup, +} from '@/views/workflow-history/workflow-history.types'; + +import * as generateHistoryGroupDetailsModule from '../../helpers/generate-history-group-details'; +import type { EventDetailsEntries } from '../../workflow-history-event-details/workflow-history-event-details.types'; +import type WorkflowHistoryGroupDetails from '../../workflow-history-group-details/workflow-history-group-details'; +import type { GroupDetailsEntries } from '../../workflow-history-group-details/workflow-history-group-details.types'; +import type { UngroupedEventInfo } from '../../workflow-history-ungrouped-table/workflow-history-ungrouped-table.types'; +import WorkflowHistoryUngroupedEvent from '../workflow-history-ungrouped-event'; +import type { Props } from '../workflow-history-ungrouped-event.types'; + +jest.mock('@/utils/data-formatters/format-date', () => + jest.fn((timeMs: number) => `Formatted: ${timeMs}`) +); + +jest.mock('@/utils/datetime/parse-grpc-timestamp', () => + jest.fn((timestamp) => { + if (timestamp?.seconds) { + return ( + parseInt(timestamp.seconds) * 1000 + (timestamp.nanos || 0) / 1000000 + ); + } + return null; + }) +); + +jest.mock('../../helpers/generate-history-group-details', () => jest.fn()); + +jest.mock( + '../../workflow-history-group-details/workflow-history-group-details', + () => + jest.fn(({ groupDetailsEntries, initialEventId, onClose }) => ( +
+
+ {groupDetailsEntries.length} events +
+ {groupDetailsEntries.map(([eventId, { eventLabel }]) => ( +
+ {eventLabel} +
+ ))} + {initialEventId && ( +
{initialEventId}
+ )} + {onClose && ( + + )} +
+ )) +); + +jest.mock( + '@/views/workflow-history/workflow-history-event-status-badge/workflow-history-event-status-badge', + () => + jest.fn((props) => ( +
+ {props.statusReady ? props.status : 'Loading'} +
+ )) +); + +jest.mock( + '@/views/workflow-history/workflow-history-group-label/workflow-history-group-label', + () => jest.fn((props) => <>{props.label}) +); + +jest.mock( + '@/views/workflow-history/workflow-history-timeline-reset-button/workflow-history-timeline-reset-button', + () => + jest.fn((props) => ( + + )) +); + +jest.mock( + '../../workflow-history-event-group-duration/helpers/get-formatted-events-duration', + () => jest.fn(() => '1m 30s') +); + +jest.mock( + '../../workflow-history-event-group/helpers/get-event-group-filtering-type', + () => jest.fn(() => 'ACTIVITY') +); + +const mockActivityEventGroupWithMetadata: ActivityHistoryGroup = { + ...mockActivityEventGroup, + eventsMetadata: [ + { + label: 'Scheduled', + status: 'COMPLETED', + timeMs: 1725747370599, + timeLabel: 'Scheduled at 07 Sep, 22:16:10 UTC', + }, + { + label: 'Started', + status: 'COMPLETED', + timeMs: 1725747370612, + timeLabel: 'Started at 07 Sep, 22:16:10 UTC', + }, + { + label: 'Completed', + status: 'COMPLETED', + timeMs: 1725747370632, + timeLabel: 'Completed at 07 Sep, 22:16:10 UTC', + }, + ], +}; + +const createMockEventInfo = ( + event: ExtendedHistoryEvent = scheduleActivityTaskEvent, + eventMetadataIndex = 0 +): UngroupedEventInfo => ({ + id: event.eventId ?? 'unknown', + event: event, + eventMetadata: + mockActivityEventGroupWithMetadata.eventsMetadata[eventMetadataIndex], + eventGroup: mockActivityEventGroupWithMetadata, + label: mockActivityEventGroupWithMetadata.label, + shortLabel: mockActivityEventGroupWithMetadata.shortLabel, + canReset: false, +}); + +describe(WorkflowHistoryUngroupedEvent.name, () => { + beforeEach(() => { + jest.restoreAllMocks(); + }); + + it('renders event correctly', () => { + const eventInfo = createMockEventInfo(); + setup({ eventInfo }); + + expect(screen.getByText(eventInfo.id)).toBeInTheDocument(); + expect( + screen.getByText(mockActivityEventGroupWithMetadata.label) + ).toBeInTheDocument(); + expect(screen.getByText('1m 30s')).toBeInTheDocument(); + expect(screen.getByTestId('status-badge')).toBeInTheDocument(); + expect(screen.getByText('COMPLETED')).toBeInTheDocument(); + expect(screen.getByText('Scheduled')).toBeInTheDocument(); + }); + + it('renders formatted date when eventTime is provided', () => { + const eventInfo = createMockEventInfo(); + setup({ eventInfo }); + + expect(screen.getByText(/Formatted:/)).toBeInTheDocument(); + }); + + it('does not render date when eventTime is missing', () => { + const eventInfo = createMockEventInfo({ + ...scheduleActivityTaskEvent, + eventTime: null, + }); + setup({ eventInfo }); + + expect(screen.queryByText(/Formatted:/)).not.toBeInTheDocument(); + }); + + it('renders duration when eventTime and workflowStartTimeMs are provided', () => { + const eventInfo = createMockEventInfo(); + setup({ eventInfo, workflowStartTimeMs: 1725747370000 }); + + expect(screen.getByText('1m 30s')).toBeInTheDocument(); + }); + + it('does not render duration when workflowStartTimeMs is missing', () => { + const eventInfo = createMockEventInfo(); + setup({ eventInfo, workflowStartTimeMs: null }); + + expect(screen.queryByText('1m 30s')).not.toBeInTheDocument(); + }); + + it('renders reset button when canReset is true', () => { + const eventInfo = createMockEventInfo(); + const eventInfoWithReset = { + ...eventInfo, + canReset: true, + }; + setup({ eventInfo: eventInfoWithReset }); + + expect(screen.getByTestId('reset-button')).toBeInTheDocument(); + }); + + it('calls onReset when reset button is clicked', async () => { + const eventInfo = createMockEventInfo(); + const eventInfoWithReset = { + ...eventInfo, + canReset: true, + }; + const { mockOnReset, user } = setup({ eventInfo: eventInfoWithReset }); + + const resetButton = screen.getByTestId('reset-button'); + await user.click(resetButton); + + expect(mockOnReset).toHaveBeenCalledTimes(1); + }); + + it('expands panel when isExpanded is true', () => { + const eventInfo = createMockEventInfo(); + setup({ eventInfo, isExpanded: true }); + + expect( + screen.getByTestId('workflow-history-group-details') + ).toBeInTheDocument(); + }); + + it('does not expand panel when isExpanded is false', () => { + const eventInfo = createMockEventInfo(); + setup({ eventInfo, isExpanded: false }); + + expect( + screen.queryByTestId('workflow-history-group-details') + ).not.toBeInTheDocument(); + }); + + it('calls toggleIsExpanded when panel is toggled', async () => { + const eventInfo = createMockEventInfo(); + const { mockToggleIsExpanded, user } = setup({ eventInfo }); + + const headerLabel = screen.getByText(eventInfo.id); + await user.click(headerLabel); + + expect(mockToggleIsExpanded).toHaveBeenCalledTimes(1); + }); + + it('calls toggleIsExpanded when WorkflowHistoryGroupDetails onClose is called', async () => { + const eventInfo = createMockEventInfo(); + const { mockToggleIsExpanded, user } = setup({ + eventInfo, + isExpanded: true, + }); + + const closeButton = screen.getByTestId('group-details-close'); + await user.click(closeButton); + + expect(mockToggleIsExpanded).toHaveBeenCalledTimes(1); + }); + + it('renders event summary details when available', () => { + const mockEventDetails: EventDetailsEntries = [ + { + key: 'input', + path: 'input', + value: 'test input value', + isGroup: false, + renderConfig: null, + }, + ]; + + const mockSummaryDetails: EventDetailsEntries = [ + { + key: 'activityType', + path: 'activityType', + value: 'TestActivity', + isGroup: false, + renderConfig: null, + }, + ]; + + const eventInfo = createMockEventInfo(); + setup({ + eventInfo, + mockGroupDetails: { + groupDetailsEntries: [ + [ + eventInfo.id, + { + eventLabel: 'Scheduled', + eventDetails: mockEventDetails, + }, + ], + ], + summaryDetailsEntries: [ + [ + eventInfo.id, + { + eventLabel: 'Scheduled', + eventDetails: mockSummaryDetails, + }, + ], + ], + }, + }); + + // Summary details should be rendered in the header + expect(screen.getByText('TestActivity')).toBeInTheDocument(); + }); + + it('renders empty div when event summary details are not available', () => { + const eventInfo = createMockEventInfo(); + setup({ eventInfo }); + + // Should render an empty div in the summarized details container + const container = screen.getByTestId('status-badge').parentElement; + expect(container).toBeInTheDocument(); + }); + + it('includes summary tab in groupDetailsEntries when expanded', () => { + const mockEventDetails: EventDetailsEntries = [ + { + key: 'input', + path: 'input', + value: 'test input value', + isGroup: false, + renderConfig: null, + }, + ]; + + const mockSummaryDetails: EventDetailsEntries = [ + { + key: 'activityType', + path: 'activityType', + value: 'TestActivity', + isGroup: false, + renderConfig: null, + }, + ]; + + const eventInfo = createMockEventInfo(); + setup({ + eventInfo, + isExpanded: true, + mockGroupDetails: { + groupDetailsEntries: [ + [ + eventInfo.id, + { + eventLabel: 'Scheduled', + eventDetails: mockEventDetails, + }, + ], + ], + summaryDetailsEntries: [ + [ + eventInfo.id, + { + eventLabel: 'Scheduled', + eventDetails: mockSummaryDetails, + }, + ], + ], + }, + }); + + // Summary tab should appear in groupDetailsEntries + expect(screen.getByText('Summary')).toBeInTheDocument(); + }); + + it('renders status badge with correct status', () => { + const eventInfo = createMockEventInfo(); + setup({ eventInfo }); + + expect(screen.getByTestId('status-badge')).toBeInTheDocument(); + expect(screen.getByText('COMPLETED')).toBeInTheDocument(); + }); + + it('renders event metadata label', () => { + const eventInfo = createMockEventInfo(); + setup({ eventInfo }); + + expect(screen.getByText('Scheduled')).toBeInTheDocument(); + }); +}); + +function setup({ + eventInfo, + workflowStartTimeMs = 1725747370000, + decodedPageUrlParams = { + domain: 'test-domain', + cluster: 'test-cluster', + workflowId: 'test-workflow-id', + runId: 'test-run-id', + workflowTab: 'history', + }, + isExpanded = false, + toggleIsExpanded = jest.fn(), + animateOnEnter = false, + onReset = jest.fn(), + mockGroupDetails, +}: Partial & { + mockGroupDetails?: { + groupDetailsEntries: GroupDetailsEntries; + summaryDetailsEntries: GroupDetailsEntries; + }; +} = {}) { + const mockGenerateHistoryGroupDetails = jest.spyOn( + generateHistoryGroupDetailsModule, + 'default' + ); + + if (mockGroupDetails) { + mockGenerateHistoryGroupDetails.mockReturnValue(mockGroupDetails); + } else { + const defaultMockEventDetails: EventDetailsEntries = [ + { + key: 'testKey', + path: 'testPath', + value: 'testValue', + isGroup: false, + renderConfig: null, + }, + ]; + + const defaultEventInfo = eventInfo ?? createMockEventInfo(); + mockGenerateHistoryGroupDetails.mockReturnValue({ + groupDetailsEntries: defaultEventInfo.eventGroup.events + .filter((event) => event.eventId) + .map((event, index) => [ + event.eventId!, + { + eventLabel: + defaultEventInfo.eventGroup.eventsMetadata[index]?.label ?? + 'Unknown', + eventDetails: defaultMockEventDetails, + }, + ]), + summaryDetailsEntries: [], + }); + } + + const mockToggleIsExpanded = toggleIsExpanded || jest.fn(); + const mockOnReset = onReset || jest.fn(); + const user = userEvent.setup(); + + const defaultEventInfo = eventInfo ?? createMockEventInfo(); + + render( + + ); + + return { + mockToggleIsExpanded, + mockOnReset, + user, + }; +} From 7dc9377d84abdf662b3d87b5e7a91ca1437afa35 Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Wed, 10 Dec 2025 15:19:40 +0100 Subject: [PATCH 12/15] Undo changes to style in event group Signed-off-by: Adhitya Mamallan --- .../workflow-history-event-group.styles.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/views/workflow-history-v2/workflow-history-event-group/workflow-history-event-group.styles.ts b/src/views/workflow-history-v2/workflow-history-event-group/workflow-history-event-group.styles.ts index 1534eab32..b2d9ce5d6 100644 --- a/src/views/workflow-history-v2/workflow-history-event-group/workflow-history-event-group.styles.ts +++ b/src/views/workflow-history-v2/workflow-history-event-group/workflow-history-event-group.styles.ts @@ -35,15 +35,9 @@ export const styled = { gap: $theme.sizing.scale300, alignItems: 'center', })), - SummarizedDetailsContainer: createStyled( - 'div', - ({ $theme }: { $theme: Theme }) => ({ - overflow: 'hidden', - [$theme.mediaQuery.medium]: { - margin: `-${$theme.sizing.scale200} 0`, - }, - }) - ), + SummarizedDetailsContainer: createStyled('div', { + overflow: 'hidden', + }), ActionsContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ display: 'flex', gap: $theme.sizing.scale300, From 23f73b72fae63e4ecb42abe375c3d986e22c6eae Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Wed, 10 Dec 2025 15:28:22 +0100 Subject: [PATCH 13/15] Remove negative margin from styles Signed-off-by: Adhitya Mamallan --- .../workflow-history-ungrouped-event.styles.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.styles.ts b/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.styles.ts index 11c4f79f0..499737df4 100644 --- a/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.styles.ts +++ b/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.styles.ts @@ -35,15 +35,9 @@ export const styled = { gap: $theme.sizing.scale300, alignItems: 'center', })), - SummarizedDetailsContainer: createStyled( - 'div', - ({ $theme }: { $theme: Theme }) => ({ - overflow: 'hidden', - [$theme.mediaQuery.medium]: { - margin: `-${$theme.sizing.scale200} 0`, - }, - }) - ), + SummarizedDetailsContainer: createStyled('div', { + overflow: 'hidden', + }), ActionsContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ display: 'flex', gap: $theme.sizing.scale300, From 32203078028c2e6fb5dc5f5f2d5900d0984099f9 Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Wed, 10 Dec 2025 15:40:00 +0100 Subject: [PATCH 14/15] Update groupDetailsEntries logic in ungrouped view as well Signed-off-by: Adhitya Mamallan --- .../workflow-history-ungrouped-event.tsx | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.tsx b/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.tsx index 9a5193c02..afdd79f66 100644 --- a/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.tsx +++ b/src/views/workflow-history-v2/workflow-history-ungrouped-event/workflow-history-ungrouped-event.tsx @@ -13,6 +13,7 @@ import workflowHistoryEventFilteringTypeColorsConfig from '../config/workflow-hi import generateHistoryGroupDetails from '../helpers/generate-history-group-details'; import WorkflowHistoryDetailsRow from '../workflow-history-details-row/workflow-history-details-row'; import getEventGroupFilteringType from '../workflow-history-event-group/helpers/get-event-group-filtering-type'; +import getSummaryTabContentEntry from '../workflow-history-event-group/helpers/get-summary-tab-content-entry'; import getFormattedEventsDuration from '../workflow-history-event-group-duration/helpers/get-formatted-events-duration'; import WorkflowHistoryGroupDetails from '../workflow-history-group-details/workflow-history-group-details'; @@ -50,6 +51,33 @@ export default function WorkflowHistoryUngroupedEvent({ ([eventId]) => eventId === eventInfo.id )?.[1].eventDetails; + const groupSummaryDetails = useMemo( + () => + summaryDetailsEntries.flatMap( + ([_eventId, { eventDetails }]) => eventDetails + ), + [summaryDetailsEntries] + ); + + const groupDetailsEntriesWithSummary = useMemo( + () => [ + ...(groupSummaryDetails.length > 0 && groupDetailsEntries.length > 1 + ? [ + getSummaryTabContentEntry({ + groupId: eventInfo.eventGroup.firstEventId ?? 'unknown', + summaryDetails: groupSummaryDetails, + }), + ] + : []), + ...groupDetailsEntries, + ], + [ + eventInfo.eventGroup.firstEventId, + groupDetailsEntries, + groupSummaryDetails, + ] + ); + return ( - eventSummaryDetails.eventDetails - ), - eventLabel: 'Summary', - }, - ], - ...groupDetailsEntries, - ]} + groupDetailsEntries={groupDetailsEntriesWithSummary} initialEventId={eventInfo.id} workflowPageParams={decodedPageUrlParams} onClose={() => toggleIsExpanded()} From f1e9a3d9e2c8d5191c8e53eba53d075afda3b9bf Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Fri, 12 Dec 2025 10:15:36 +0100 Subject: [PATCH 15/15] fix tests Signed-off-by: Adhitya Mamallan --- .../workflow-history-ungrouped-event.test.tsx | 71 ++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/src/views/workflow-history-v2/workflow-history-ungrouped-event/__tests__/workflow-history-ungrouped-event.test.tsx b/src/views/workflow-history-v2/workflow-history-ungrouped-event/__tests__/workflow-history-ungrouped-event.test.tsx index cef0b1f2b..4c021f5f9 100644 --- a/src/views/workflow-history-v2/workflow-history-ungrouped-event/__tests__/workflow-history-ungrouped-event.test.tsx +++ b/src/views/workflow-history-v2/workflow-history-ungrouped-event/__tests__/workflow-history-ungrouped-event.test.tsx @@ -1,6 +1,9 @@ import { render, screen, userEvent } from '@/test-utils/rtl'; -import { scheduleActivityTaskEvent } from '@/views/workflow-history/__fixtures__/workflow-history-activity-events'; +import { + scheduleActivityTaskEvent, + startActivityTaskEvent, +} from '@/views/workflow-history/__fixtures__/workflow-history-activity-events'; import { mockActivityEventGroup } from '@/views/workflow-history/__fixtures__/workflow-history-event-groups'; import type WorkflowHistoryEventStatusBadge from '@/views/workflow-history/workflow-history-event-status-badge/workflow-history-event-status-badge'; import type WorkflowHistoryGroupLabel from '@/views/workflow-history/workflow-history-group-label/workflow-history-group-label'; @@ -330,6 +333,7 @@ describe(WorkflowHistoryUngroupedEvent.name, () => { ]; const eventInfo = createMockEventInfo(); + const secondEventInfo = createMockEventInfo(startActivityTaskEvent, 1); setup({ eventInfo, isExpanded: true, @@ -342,6 +346,13 @@ describe(WorkflowHistoryUngroupedEvent.name, () => { eventDetails: mockEventDetails, }, ], + [ + secondEventInfo.id, + { + eventLabel: 'Started', + eventDetails: mockEventDetails, + }, + ], ], summaryDetailsEntries: [ [ @@ -351,14 +362,70 @@ describe(WorkflowHistoryUngroupedEvent.name, () => { eventDetails: mockSummaryDetails, }, ], + [ + secondEventInfo.id, + { + eventLabel: 'Started', + eventDetails: mockSummaryDetails, + }, + ], ], }, }); - // Summary tab should appear in groupDetailsEntries expect(screen.getByText('Summary')).toBeInTheDocument(); }); + it('does not include summary tab in groupDetailsEntries when there is only one entry', () => { + const mockEventDetails: EventDetailsEntries = [ + { + key: 'input', + path: 'input', + value: 'test input value', + isGroup: false, + renderConfig: null, + }, + ]; + + const mockSummaryDetails: EventDetailsEntries = [ + { + key: 'activityType', + path: 'activityType', + value: 'TestActivity', + isGroup: false, + renderConfig: null, + }, + ]; + + const eventInfo = createMockEventInfo(); + setup({ + eventInfo, + isExpanded: true, + mockGroupDetails: { + groupDetailsEntries: [ + [ + eventInfo.id, + { + eventLabel: 'Scheduled', + eventDetails: mockEventDetails, + }, + ], + ], + summaryDetailsEntries: [ + [ + eventInfo.id, + { + eventLabel: 'Scheduled', + eventDetails: mockSummaryDetails, + }, + ], + ], + }, + }); + + expect(screen.queryByText('Summary')).not.toBeInTheDocument(); + }); + it('renders status badge with correct status', () => { const eventInfo = createMockEventInfo(); setup({ eventInfo });