Skip to content
Prev Previous commit
Next Next commit
address comments
Signed-off-by: Adhitya Mamallan <adhitya.mamallan@uber.com>
  • Loading branch information
adhityamamallan committed Dec 5, 2025
commit 0e28730cbad2d68cb60c6c631d9911cd50a0faa1

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import formatPendingWorkflowHistoryEvent from '@/utils/data-formatters/format-pending-workflow-history-event';
import formatWorkflowHistoryEvent from '@/utils/data-formatters/format-workflow-history-event';
import isPendingHistoryEvent from '@/views/workflow-history/workflow-history-event-details/helpers/is-pending-history-event';
import { type HistoryEventsGroup } from '@/views/workflow-history/workflow-history.types';

import generateHistoryEventDetails from '../helpers/generate-history-event-details';
import { type EventDetailsTabContent } from '../workflow-history-group-details/workflow-history-group-details.types';

export default function generateHistoryGroupDetails(
eventGroup: HistoryEventsGroup
) {
const groupDetailsEntries: Array<[string, EventDetailsTabContent]> = [],
summaryDetailsEntries: Array<[string, EventDetailsTabContent]> = [];

eventGroup.events.forEach((event, index) => {
const eventId = event.eventId ?? event.computedEventId;

const eventMetadata = eventGroup.eventsMetadata[index];
if (!eventMetadata) return;

const result = isPendingHistoryEvent(event)
? formatPendingWorkflowHistoryEvent(event)
: formatWorkflowHistoryEvent(event);

const eventDetails = result
? generateHistoryEventDetails({
details: {
...result,
...eventMetadata.additionalDetails,
},
negativeFields: eventMetadata.negativeFields,
})
: [];

groupDetailsEntries.push([
eventId,
{
eventLabel: eventMetadata.label,
eventDetails,
} satisfies EventDetailsTabContent,
]);

const eventSummaryDetails = eventDetails.filter((detail) =>
eventMetadata.summaryFields?.includes(detail.path)
);

if (eventSummaryDetails.length > 0) {
summaryDetailsEntries.push([
eventId,
{
eventLabel: eventMetadata.label,
eventDetails: eventSummaryDetails,
} satisfies EventDetailsTabContent,
]);
}
});

return {
groupDetailsEntries,
summaryDetailsEntries,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ describe(WorkflowHistoryEventDetails.name, () => {
).toBeInTheDocument();
});

it('passes correct props to WorkflowHistoryPanelDetailsEntry', () => {
it('correctly renders panel details entry', () => {
const eventDetails: EventDetailsEntries = [
{
key: 'key1',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,21 @@
import { useMemo } from 'react';

import partition from 'lodash/partition';

import WorkflowHistoryEventDetailsGroup from '@/views/workflow-history/workflow-history-event-details-group/workflow-history-event-details-group';

import WorkflowHistoryPanelDetailsEntry from '../workflow-history-panel-details-entry/workflow-history-panel-details-entry';

import { styled } from './workflow-history-event-details.styles';
import {
type Props,
type EventDetailsEntries,
} from './workflow-history-event-details.types';
import { type Props } from './workflow-history-event-details.types';

export default function WorkflowHistoryEventDetails({
eventDetails,
workflowPageParams,
}: Props) {
const [panelDetails, restDetails] = useMemo(
() =>
eventDetails.reduce<[EventDetailsEntries, EventDetailsEntries]>(
([panels, rest], entry) => {
if (entry.renderConfig?.showInPanels) {
panels.push(entry);
} else {
rest.push(entry);
}

return [panels, rest];
},
[[], []]
),
partition(eventDetails, (detail) => detail.renderConfig?.showInPanels),
[eventDetails]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,18 @@ import type WorkflowHistoryGroupLabel from '@/views/workflow-history/workflow-hi
import type WorkflowHistoryTimelineResetButton from '@/views/workflow-history/workflow-history-timeline-reset-button/workflow-history-timeline-reset-button';
import { type HistoryEventsGroup } 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 WorkflowHistoryEventGroup from '../workflow-history-event-group';
import type { Props } from '../workflow-history-event-group.types';

jest.mock('@/utils/data-formatters/format-date', () =>
jest.fn((timeMs: number) => `Formatted: ${timeMs}`)
);

jest.mock('@/utils/data-formatters/format-pending-workflow-history-event', () =>
jest.fn(() => ({ mockFormatted: true }))
);

jest.mock('@/utils/data-formatters/format-workflow-history-event', () =>
jest.fn(() => ({ mockFormatted: true }))
);

const mockGenerateHistoryEventDetails = jest.fn<EventDetailsEntries, any[]>();

jest.mock('../../helpers/generate-history-event-details', () =>
jest.fn(() => mockGenerateHistoryEventDetails())
);
jest.mock('../../helpers/generate-history-group-details', () => jest.fn());

jest.mock<typeof WorkflowHistoryGroupDetails>(
'../../workflow-history-group-details/workflow-history-group-details',
Expand Down Expand Up @@ -145,6 +135,10 @@ const mockDecisionEventGroupWithMetadata: HistoryEventsGroup = {
};

describe(WorkflowHistoryEventGroup.name, () => {
beforeEach(() => {
jest.restoreAllMocks();
});

it('renders group correctly', () => {
setup({ eventGroup: mockActivityEventGroupWithMetadata });

Expand Down Expand Up @@ -283,7 +277,7 @@ describe(WorkflowHistoryEventGroup.name, () => {
});
});

it('shows summary tab when summaryFields are available to show', () => {
it('shows summary tab when summaryDetailsEntries are available', () => {
const mockEventDetails: EventDetailsEntries = [
{
key: 'input',
Expand All @@ -299,10 +293,20 @@ describe(WorkflowHistoryEventGroup.name, () => {
isGroup: false,
renderConfig: null,
},
];

const mockSummaryDetails: EventDetailsEntries = [
{
key: 'input',
path: 'input',
value: 'test input value',
isGroup: false,
renderConfig: null,
},
{
key: 'result',
path: 'result',
value: 'test result',
key: 'activityType',
path: 'activityType',
value: 'TestActivity',
isGroup: false,
renderConfig: null,
},
Expand Down Expand Up @@ -340,13 +344,57 @@ describe(WorkflowHistoryEventGroup.name, () => {
(eventId: string) => eventId === completedActivityTaskEvents[0].eventId
);

setup({ eventGroup, getIsEventExpanded, mockEventDetails });
setup({
eventGroup,
getIsEventExpanded,
mockGroupDetails: {
groupDetailsEntries: [
[
completedActivityTaskEvents[0].eventId!,
{
eventLabel: 'Scheduled',
eventDetails: mockEventDetails,
},
],
[
completedActivityTaskEvents[1].eventId!,
{
eventLabel: 'Started',
eventDetails: mockEventDetails,
},
],
[
completedActivityTaskEvents[2].eventId!,
{
eventLabel: 'Completed',
eventDetails: mockEventDetails,
},
],
],
summaryDetailsEntries: [
[
completedActivityTaskEvents[0].eventId!,
{
eventLabel: 'Scheduled',
eventDetails: mockSummaryDetails,
},
],
[
completedActivityTaskEvents[1].eventId!,
{
eventLabel: 'Started',
eventDetails: mockSummaryDetails,
},
],
],
},
});

// Summary tab should appear in groupDetailsEntries when there are multiple events and summary details
// Summary tab should appear in groupDetailsEntries when there are summary details
expect(screen.getByText('Summary')).toBeInTheDocument();
});

it('does not show summary tab when there is only one event', () => {
it('does not show summary tab when summaryDetailsEntries is empty', () => {
const mockEventDetails: EventDetailsEntries = [
{
key: 'input',
Expand All @@ -371,14 +419,27 @@ describe(WorkflowHistoryEventGroup.name, () => {
],
};

setup({ eventGroup, mockEventDetails });
setup({
eventGroup,
mockGroupDetails: {
groupDetailsEntries: [
[
scheduleActivityTaskEvent.eventId!,
{
eventLabel: 'Scheduled',
eventDetails: mockEventDetails,
},
],
],
summaryDetailsEntries: [],
},
});

// Summary tab should not appear when there's only one event
expect(screen.queryByTestId('event-summary_7')).not.toBeInTheDocument();
// Summary tab should not appear when summaryDetailsEntries is empty
expect(screen.queryByText('Summary')).not.toBeInTheDocument();
});

it('does not show summary tab when summaryFields do not match any event details', () => {
it('does not show summary tab when summaryDetailsEntries is empty', () => {
const mockEventDetails: EventDetailsEntries = [
{
key: 'input',
Expand Down Expand Up @@ -416,9 +477,37 @@ describe(WorkflowHistoryEventGroup.name, () => {
],
};

setup({ eventGroup, mockEventDetails });
setup({
eventGroup,
mockGroupDetails: {
groupDetailsEntries: [
[
completedActivityTaskEvents[0].eventId!,
{
eventLabel: 'Scheduled',
eventDetails: mockEventDetails,
},
],
[
completedActivityTaskEvents[1].eventId!,
{
eventLabel: 'Started',
eventDetails: mockEventDetails,
},
],
[
completedActivityTaskEvents[2].eventId!,
{
eventLabel: 'Completed',
eventDetails: mockEventDetails,
},
],
],
summaryDetailsEntries: [],
},
});

// Summary tab should not appear when no summary details match
// Summary tab should not appear when summaryDetailsEntries is empty
expect(screen.queryByText('Summary')).not.toBeInTheDocument();
});
});
Expand All @@ -440,29 +529,51 @@ function setup({
onReset = jest.fn(),
getIsEventExpanded = jest.fn(() => false),
toggleIsEventExpanded = jest.fn(),
mockEventDetails,
mockGroupDetails,
}: Partial<Props> & {
mockEventDetails?: EventDetailsEntries;
mockGroupDetails?: {
groupDetailsEntries: GroupDetailsEntries;
summaryDetailsEntries: GroupDetailsEntries;
};
} = {}) {
mockGenerateHistoryEventDetails.mockReturnValue(
mockEventDetails ?? [
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,
},
]
);
];

mockGenerateHistoryGroupDetails.mockReturnValue({
groupDetailsEntries: eventGroup.events
.filter((event) => event.eventId)
.map((event, index) => [
event.eventId!,
{
eventLabel: eventGroup.eventsMetadata[index]?.label ?? 'Unknown',
eventDetails: defaultMockEventDetails,
},
]),
summaryDetailsEntries: [],
});
}

const mockOnReset = onReset || jest.fn();
const user = userEvent.setup();

render(
<WorkflowHistoryEventGroup
eventGroup={eventGroup}
groupId={eventGroup.firstEventId ?? ''}
selected={selected}
workflowCloseTimeMs={workflowCloseTimeMs}
workflowCloseStatus={workflowCloseStatus}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { type EventDetailsEntries } from '../../workflow-history-event-details/workflow-history-event-details.types';
import { type EventDetailsTabContent } from '../../workflow-history-group-details/workflow-history-group-details.types';

export default function getSummaryTabContentEntry({
groupId,
summaryDetails,
}: {
groupId: string;
summaryDetails: EventDetailsEntries;
}): [string, EventDetailsTabContent] {
return [
`summary_${groupId}`,
{
eventDetails: summaryDetails,
eventLabel: 'Summary',
},
];
}
Loading