Skip to content

Commit 786de10

Browse files
Add summaryFields to history group metadata (#995)
* Add new field summaryFields to event metadata, which mentions a list of top-level fields to highlight in an event summary * Rename HistoryGroupEventStatusToNegativeFieldsMap to HistoryGroupEventToNegativeFieldsMap, since it is a mapping from event and not event status
1 parent cb91b9b commit 786de10

15 files changed

+405
-38
lines changed

src/views/workflow-history/helpers/__tests__/get-common-history-group-fields.test.ts

Lines changed: 86 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,14 @@ describe('getCommonHistoryGroupFields', () => {
131131
}
132132
);
133133

134-
it('should include negativeFields when eventStatusToNegativeFieldsMap is provided', () => {
135-
const eventStatusToNegativeFieldsMap = {
134+
it('should include negativeFields when eventToNegativeFieldsMap is provided', () => {
135+
const eventToNegativeFieldsMap = {
136136
timerStartedEventAttributes: ['startReason', 'startDetails'],
137137
timerFiredEventAttributes: ['fireReason', 'fireDetails'],
138138
};
139139

140140
const group = setup({
141-
eventStatusToNegativeFieldsMap,
141+
eventToNegativeFieldsMap,
142142
});
143143

144144
expect(group.eventsMetadata[0].negativeFields).toEqual([
@@ -151,17 +151,17 @@ describe('getCommonHistoryGroupFields', () => {
151151
]);
152152
});
153153

154-
it('should not include negativeFields when eventStatusToNegativeFieldsMap is not provided', () => {
154+
it('should not include negativeFields when eventToNegativeFieldsMap is not provided', () => {
155155
const group = setup({});
156156

157157
group.eventsMetadata.forEach((metadata) => {
158158
expect(metadata.negativeFields).toBeUndefined();
159159
});
160160
});
161161

162-
it('should not include negativeFields when eventStatusToNegativeFieldsMap is empty', () => {
162+
it('should not include negativeFields when eventToNegativeFieldsMap is empty', () => {
163163
const group = setup({
164-
eventStatusToNegativeFieldsMap: {},
164+
eventToNegativeFieldsMap: {},
165165
});
166166

167167
group.eventsMetadata.forEach((metadata) => {
@@ -170,18 +170,89 @@ describe('getCommonHistoryGroupFields', () => {
170170
});
171171

172172
it('should only include negativeFields for events that have mappings', () => {
173-
const eventStatusToNegativeFieldsMap = {
173+
const eventToNegativeFieldsMap = {
174174
timerStartedEventAttributes: ['startReason'],
175175
};
176176

177177
const group = setup({
178-
eventStatusToNegativeFieldsMap,
178+
eventToNegativeFieldsMap,
179179
});
180180

181181
expect(group.eventsMetadata[0].negativeFields).toEqual(['startReason']);
182182
expect(group.eventsMetadata[1].negativeFields).toBeUndefined();
183183
});
184184

185+
it('should include summaryFields when eventToSummaryFieldsMap is provided', () => {
186+
const eventToSummaryFieldsMap = {
187+
timerStartedEventAttributes: ['startReason', 'startDetails'],
188+
timerFiredEventAttributes: ['fireReason', 'fireDetails'],
189+
};
190+
191+
const group = setup({
192+
eventToSummaryFieldsMap,
193+
});
194+
195+
expect(group.eventsMetadata[0].summaryFields).toEqual([
196+
'startReason',
197+
'startDetails',
198+
]);
199+
expect(group.eventsMetadata[1].summaryFields).toEqual([
200+
'fireReason',
201+
'fireDetails',
202+
]);
203+
});
204+
205+
it('should not include summaryFields when eventToSummaryFieldsMap is not provided', () => {
206+
const group = setup({});
207+
208+
group.eventsMetadata.forEach((metadata) => {
209+
expect(metadata.summaryFields).toBeUndefined();
210+
});
211+
});
212+
213+
it('should not include summaryFields when eventToSummaryFieldsMap is empty', () => {
214+
const group = setup({
215+
eventToSummaryFieldsMap: {},
216+
});
217+
218+
group.eventsMetadata.forEach((metadata) => {
219+
expect(metadata.summaryFields).toBeUndefined();
220+
});
221+
});
222+
223+
it('should only include summaryFields for events that have mappings', () => {
224+
const eventToSummaryFieldsMap = {
225+
timerStartedEventAttributes: ['startReason'],
226+
};
227+
228+
const group = setup({
229+
eventToSummaryFieldsMap,
230+
});
231+
232+
expect(group.eventsMetadata[0].summaryFields).toEqual(['startReason']);
233+
expect(group.eventsMetadata[1].summaryFields).toBeUndefined();
234+
});
235+
236+
it('should include both negativeFields and summaryFields when both maps are provided', () => {
237+
const eventToNegativeFieldsMap = {
238+
timerStartedEventAttributes: ['startReason'],
239+
};
240+
const eventToSummaryFieldsMap = {
241+
timerStartedEventAttributes: ['startDetails'],
242+
timerFiredEventAttributes: ['fireDetails'],
243+
};
244+
245+
const group = setup({
246+
eventToNegativeFieldsMap,
247+
eventToSummaryFieldsMap,
248+
});
249+
250+
expect(group.eventsMetadata[0].negativeFields).toEqual(['startReason']);
251+
expect(group.eventsMetadata[0].summaryFields).toEqual(['startDetails']);
252+
expect(group.eventsMetadata[1].summaryFields).toEqual(['fireDetails']);
253+
expect(group.eventsMetadata[1].negativeFields).toBeUndefined();
254+
});
255+
185256
it('should return group with firstEventId equal to first event id', () => {
186257
const group = setup({});
187258
expect(group.firstEventId).toEqual(group.events[0].eventId);
@@ -195,7 +266,8 @@ function setup({
195266
eventToLabel,
196267
eventToStatus,
197268
closeEvent,
198-
eventStatusToNegativeFieldsMap,
269+
eventToNegativeFieldsMap,
270+
eventToSummaryFieldsMap,
199271
}: {
200272
events?: TimerHistoryEvent[];
201273
eventToStatus?: HistoryGroupEventToStatusMap<TimerHistoryGroup>;
@@ -204,7 +276,8 @@ function setup({
204276
HistoryGroupEventToStringMap<TimerHistoryGroup>
205277
>;
206278
closeEvent?: TimerHistoryEvent;
207-
eventStatusToNegativeFieldsMap?: any;
279+
eventToNegativeFieldsMap?: any;
280+
eventToSummaryFieldsMap?: any;
208281
}) {
209282
const mockEvents: TimerHistoryEvent[] = events || [
210283
startTimerTaskEvent,
@@ -229,6 +302,8 @@ function setup({
229302
mockedEventToLabel,
230303
eventToTimeLabelPrefixMap,
231304
closeEvent,
232-
eventStatusToNegativeFieldsMap
305+
eventToNegativeFieldsMap,
306+
undefined,
307+
eventToSummaryFieldsMap
233308
);
234309
}

src/views/workflow-history/helpers/get-common-history-group-fields.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ import parseGrpcTimestamp from '@/utils/datetime/parse-grpc-timestamp';
33

44
import { type WorkflowEventStatus } from '../workflow-history-event-status-badge/workflow-history-event-status-badge.types';
55
import {
6-
type HistoryGroupEventStatusToNegativeFieldsMap,
6+
type HistoryGroupEventToNegativeFieldsMap,
77
type HistoryEventsGroup,
88
type HistoryGroupEventToStatusMap,
99
type HistoryGroupEventToStringMap,
1010
type HistoryGroupEventToAdditionalDetailsMap,
11+
type HistoryGroupEventToSummaryFieldsMap,
1112
} from '../workflow-history.types';
1213

1314
export default function getCommonHistoryGroupFields<
@@ -18,8 +19,9 @@ export default function getCommonHistoryGroupFields<
1819
eventToLabelMap: HistoryGroupEventToStringMap<GroupT>,
1920
eventToTimeLabelPrefixMap: Partial<HistoryGroupEventToStringMap<GroupT>>,
2021
closeEvent: GroupT['events'][number] | null | undefined,
21-
eventStatusToNegativeFieldsMap?: HistoryGroupEventStatusToNegativeFieldsMap<GroupT>,
22-
eventToAdditionalDetailsMap?: HistoryGroupEventToAdditionalDetailsMap<GroupT>
22+
eventToNegativeFieldsMap?: HistoryGroupEventToNegativeFieldsMap<GroupT>,
23+
eventToAdditionalDetailsMap?: HistoryGroupEventToAdditionalDetailsMap<GroupT>,
24+
eventToSummaryFieldsMap?: HistoryGroupEventToSummaryFieldsMap<GroupT>
2325
): Pick<
2426
GroupT,
2527
| 'eventsMetadata'
@@ -43,8 +45,9 @@ export default function getCommonHistoryGroupFields<
4345
? eventToTimeLabelPrefixMap[attrs]
4446
: `${eventToLabelMap[attrs]} at`;
4547

46-
const negativeFields = eventStatusToNegativeFieldsMap?.[attrs];
48+
const negativeFields = eventToNegativeFieldsMap?.[attrs];
4749
const additionalDetails = eventToAdditionalDetailsMap?.[attrs];
50+
const summaryFields = eventToSummaryFieldsMap?.[attrs];
4851

4952
return {
5053
label: eventToLabelMap[attrs],
@@ -53,6 +56,7 @@ export default function getCommonHistoryGroupFields<
5356
timeLabel: timeMs ? `${prefix} ${formatDate(timeMs)}` : '',
5457
...(negativeFields?.length ? { negativeFields } : {}),
5558
...(additionalDetails ? { additionalDetails } : {}),
59+
...(summaryFields?.length ? { summaryFields } : {}),
5660
};
5761
});
5862

src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-activity-group-from-events.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,50 @@ describe('getActivityGroupFromEvents', () => {
388388
});
389389
});
390390

391+
it('should include summaryFields for activity events', () => {
392+
const events: ExtendedActivityHistoryEvent[] = [
393+
scheduleActivityTaskEvent,
394+
startActivityTaskEvent,
395+
completeActivityTaskEvent,
396+
];
397+
const group = getActivityGroupFromEvents(events);
398+
399+
// The scheduled event should have summaryFields
400+
const scheduledEventMetadata = group.eventsMetadata.find(
401+
(metadata) => metadata.label === 'Scheduled'
402+
);
403+
expect(scheduledEventMetadata?.summaryFields).toEqual([
404+
'input',
405+
'scheduleToCloseTimeoutSeconds',
406+
]);
407+
408+
// The started event should also have summaryFields
409+
const startedEventMetadata = group.eventsMetadata.find(
410+
(metadata) => metadata.label === 'Started'
411+
);
412+
expect(startedEventMetadata?.summaryFields).toEqual([
413+
'lastHeartbeatTime',
414+
'heartbeatDetails',
415+
]);
416+
417+
// The completed event should also have summaryFields
418+
const completedEventMetadata = group.eventsMetadata.find(
419+
(metadata) => metadata.label === 'Completed'
420+
);
421+
expect(completedEventMetadata?.summaryFields).toEqual(['result']);
422+
});
423+
424+
it('should include summaryFields for failed activity events', () => {
425+
const events: ExtendedActivityHistoryEvent[] = [failedActivityTaskEvent];
426+
const group = getActivityGroupFromEvents(events);
427+
428+
// The failed event should have summaryFields
429+
const failedEventMetadata = group.eventsMetadata.find(
430+
(metadata) => metadata.status === 'FAILED'
431+
);
432+
expect(failedEventMetadata?.summaryFields).toEqual(['details', 'reason']);
433+
});
434+
391435
it('should include heartbeat details in additionalDetails when pending activity start event is present', () => {
392436
const events: ExtendedActivityHistoryEvent[] = [
393437
scheduleActivityTaskEvent,

src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-child-workflow-execution-group-from-events.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,4 +277,44 @@ describe('getChildWorkflowExecutionGroupFromEvents', () => {
277277
expect(metadata.negativeFields).toBeUndefined();
278278
});
279279
});
280+
281+
it('should include summaryFields for child workflow events', () => {
282+
const events: ChildWorkflowExecutionHistoryEvent[] = [
283+
initiateChildWorkflowEvent,
284+
startChildWorkflowEvent,
285+
completeChildWorkflowEvent,
286+
];
287+
const group = getChildWorkflowExecutionGroupFromEvents(events);
288+
289+
// The initiated event should have summaryFields
290+
const initiatedEventMetadata = group.eventsMetadata.find(
291+
(metadata) => metadata.label === 'Initiated'
292+
);
293+
expect(initiatedEventMetadata?.summaryFields).toEqual(['input']);
294+
295+
// The started event should also have summaryFields
296+
const startedEventMetadata = group.eventsMetadata.find(
297+
(metadata) => metadata.label === 'Started'
298+
);
299+
expect(startedEventMetadata?.summaryFields).toEqual(['workflowExecution']);
300+
301+
// The completed event should also have summaryFields
302+
const completedEventMetadata = group.eventsMetadata.find(
303+
(metadata) => metadata.label === 'Completed'
304+
);
305+
expect(completedEventMetadata?.summaryFields).toEqual(['result']);
306+
});
307+
308+
it('should include summaryFields for failed child workflow event', () => {
309+
const events: ChildWorkflowExecutionHistoryEvent[] = [
310+
failChildWorkflowEvent,
311+
];
312+
const group = getChildWorkflowExecutionGroupFromEvents(events);
313+
314+
// The failed event should have summaryFields
315+
const failedEventMetadata = group.eventsMetadata.find(
316+
(metadata) => metadata.status === 'FAILED'
317+
);
318+
expect(failedEventMetadata?.summaryFields).toEqual(['details', 'reason']);
319+
});
280320
});

src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-decision-group-from-events.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,4 +355,29 @@ describe('getDecisionGroupFromEvents', () => {
355355
expect(metadata.negativeFields).toBeUndefined();
356356
});
357357
});
358+
359+
it('should include summaryFields for scheduled decision events', () => {
360+
const events: ExtendedDecisionHistoryEvent[] = [
361+
scheduleDecisionTaskEvent,
362+
startDecisionTaskEvent,
363+
completeDecisionTaskEvent,
364+
];
365+
const group = getDecisionGroupFromEvents(events);
366+
367+
// The scheduled event should have summaryFields
368+
const scheduledEventMetadata = group.eventsMetadata.find(
369+
(metadata) => metadata.label === 'Scheduled'
370+
);
371+
expect(scheduledEventMetadata?.summaryFields).toEqual([
372+
'startToCloseTimeoutSeconds',
373+
]);
374+
375+
// Other events should not have summaryFields
376+
const otherEventsMetadata = group.eventsMetadata.filter(
377+
(metadata) => metadata.label !== 'Scheduled'
378+
);
379+
otherEventsMetadata.forEach((metadata) => {
380+
expect(metadata.summaryFields).toBeUndefined();
381+
});
382+
});
358383
});

src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-signal-external-workflow-execution-group-from-events.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,29 @@ describe('getSignalExternalWorkflowExecutionGroupFromEvents', () => {
137137
]);
138138
expect(groupWithMissingCloseEvent.closeTimeMs).toEqual(null);
139139
});
140+
141+
it('should include summaryFields for initiated signal external workflow events', () => {
142+
const events: SignalExternalWorkflowExecutionHistoryEvent[] = [
143+
initiateSignalExternalWorkflowEvent,
144+
signalExternalWorkflowEvent,
145+
];
146+
const group = getSignalExternalWorkflowExecutionGroupFromEvents(events);
147+
148+
// The initiated event should have summaryFields
149+
const initiatedEventMetadata = group.eventsMetadata.find(
150+
(metadata) => metadata.label === 'Initiated'
151+
);
152+
expect(initiatedEventMetadata?.summaryFields).toEqual([
153+
'input',
154+
'signalName',
155+
]);
156+
157+
// Other events should not have summaryFields
158+
const otherEventsMetadata = group.eventsMetadata.filter(
159+
(metadata) => metadata.label !== 'Initiated'
160+
);
161+
otherEventsMetadata.forEach((metadata) => {
162+
expect(metadata.summaryFields).toBeUndefined();
163+
});
164+
});
140165
});

0 commit comments

Comments
 (0)