Skip to content

Commit 7d16a25

Browse files
Workflow History - scroll to event in timeline (#702)
* partial commit * Add more changes * Fix tests * Re-add load more logic * Resolve comments * Remove empty file
1 parent deea8db commit 7d16a25

File tree

5 files changed

+57
-17
lines changed

5 files changed

+57
-17
lines changed

src/views/workflow-history/__tests__/workflow-history.test.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ jest.mock(
2020
'../workflow-history-timeline-group/workflow-history-timeline-group',
2121
() => jest.fn(() => <div>Timeline group card</div>)
2222
);
23+
2324
jest.mock(
2425
'../workflow-history-timeline-load-more/workflow-history-timeline-load-more',
2526
() => jest.fn(() => <div>Load more</div>)
@@ -74,25 +75,25 @@ describe('WorkflowHistory', () => {
7475
);
7576
}
7677
});
78+
7779
it('should render the page initially with filters hidden', async () => {
7880
setup({});
7981
expect(screen.queryByText('Filter Fields')).not.toBeInTheDocument();
8082
});
8183

8284
it('should show filters on executing toggle button onClick', async () => {
83-
setup({});
85+
const { user } = setup({});
8486
const toggleButton = await screen.findByText('Filter Toggle');
8587

86-
await act(() => {
87-
userEvent.click(toggleButton);
88-
});
88+
await user.click(toggleButton);
8989

9090
expect(await screen.findByText('Filter Fields')).toBeInTheDocument();
9191
});
9292
});
9393

9494
function setup({ error }: { error?: boolean }) {
95-
render(
95+
const user = userEvent.setup();
96+
const renderResult = render(
9697
<Suspense>
9798
<WorkflowHistory
9899
params={{
@@ -141,4 +142,6 @@ function setup({ error }: { error?: boolean }) {
141142
),
142143
}
143144
);
145+
146+
return { user, ...renderResult };
144147
}

src/views/workflow-history/workflow-history-compact-event-card/__tests__/workflow-history-compact-event-card.test.tsx

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22

3-
import { render, screen } from '@/test-utils/rtl';
3+
import { render, screen, userEvent } from '@/test-utils/rtl';
44

55
import type WorkflowHistoryEventStatusBadge from '../../workflow-history-event-status-badge/workflow-history-event-status-badge';
66
import WorkflowHistoryCompactEventCard from '../workflow-history-compact-event-card';
@@ -45,15 +45,34 @@ describe('WorkflowHistoryCompactEventCard', () => {
4545
const badge = screen.getByText('ONGOING');
4646
expect(badge).toBeInTheDocument();
4747
});
48+
49+
it('calls onClick when clicked', async () => {
50+
const { user, mockOnClick } = setup({
51+
label: 'test label',
52+
});
53+
54+
const tile = screen.getByText('test label');
55+
56+
await user.click(tile);
57+
58+
expect(mockOnClick).toHaveBeenCalled();
59+
});
4860
});
4961

5062
function setup(props: Partial<Props>) {
51-
return render(
52-
<WorkflowHistoryCompactEventCard
53-
status="COMPLETED"
54-
label="test label"
55-
secondaryLabel="test secondaryLabel"
56-
{...props}
57-
/>
58-
);
63+
const user = userEvent.setup();
64+
const mockOnClick = jest.fn();
65+
return {
66+
...render(
67+
<WorkflowHistoryCompactEventCard
68+
status="COMPLETED"
69+
label="test label"
70+
secondaryLabel="test secondaryLabel"
71+
onClick={mockOnClick}
72+
{...props}
73+
/>
74+
),
75+
user,
76+
mockOnClick,
77+
};
5978
}

src/views/workflow-history/workflow-history-compact-event-card/workflow-history-compact-event-card.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export default function WorkflowHistoryCompactEventCard({
1919
label,
2020
secondaryLabel,
2121
showLabelPlaceholder,
22+
onClick,
2223
}: Props) {
2324
const { cls, theme } = useStyletronClasses(cssStyles);
2425

@@ -28,6 +29,7 @@ export default function WorkflowHistoryCompactEventCard({
2829
tileKind={TILE_KIND.selection}
2930
headerAlignment={ALIGNMENT.right}
3031
bodyAlignment={ALIGNMENT.left}
32+
onClick={onClick}
3133
>
3234
<WorkflowHistoryEventStatusBadge status={status} size="small" />
3335
<div className={cls.textContainer}>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
import { type TileProps } from 'baseui/tile';
2+
13
import { type WorkflowEventStatus } from '../workflow-history-event-status-badge/workflow-history-event-status-badge.types';
24

35
export type Props = {
46
status: WorkflowEventStatus;
57
label: string;
68
secondaryLabel: string;
79
showLabelPlaceholder?: boolean;
10+
onClick: TileProps['onClick'];
811
};

src/views/workflow-history/workflow-history.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
'use client';
2-
import React, { useMemo, useState } from 'react';
2+
import React, { useMemo, useRef, useState } from 'react';
33

44
import {
55
useSuspenseInfiniteQuery,
66
type InfiniteData,
77
} from '@tanstack/react-query';
88
import { HeadingXSmall } from 'baseui/typography';
99
import queryString from 'query-string';
10-
import { Virtuoso } from 'react-virtuoso';
10+
import { Virtuoso, type VirtuosoHandle } from 'react-virtuoso';
1111

1212
import usePageFilters from '@/components/page-filters/hooks/use-page-filters';
1313
import PageFiltersFields from '@/components/page-filters/page-filters-fields/page-filters-fields';
@@ -108,6 +108,8 @@ export default function WorkflowHistory({ params }: Props) {
108108

109109
const [areFiltersShown, setAreFiltersShown] = useState(false);
110110

111+
const timelineSectionListRef = useRef<VirtuosoHandle>(null);
112+
111113
return (
112114
<PageSection className={cls.pageContainer}>
113115
<div className={cls.pageHeader}>
@@ -133,23 +135,34 @@ export default function WorkflowHistory({ params }: Props) {
133135
<div role="list" className={cls.compactSection}>
134136
<Virtuoso
135137
data={filteredGroupedHistoryEventsEntries}
136-
itemContent={(_, [groupId, { label, status, timeLabel }]) => (
138+
itemContent={(index, [groupId, { label, status, timeLabel }]) => (
137139
<div role="listitem" className={cls.compactCardContainer}>
138140
<WorkflowHistoryCompactEventCard
139141
key={groupId}
140142
status={status}
141143
label={label}
142144
secondaryLabel={timeLabel}
143145
showLabelPlaceholder={!label}
146+
onClick={() => {
147+
timelineSectionListRef.current?.scrollToIndex({
148+
index,
149+
align: 'start',
150+
behavior: 'smooth',
151+
});
152+
}}
144153
/>
145154
</div>
146155
)}
156+
endReached={() => {
157+
if (!isFetchingNextPage && hasNextPage) fetchNextPage();
158+
}}
147159
/>
148160
</div>
149161
<section className={cls.timelineSection}>
150162
<Virtuoso
151163
useWindowScroll
152164
data={filteredGroupedHistoryEventsEntries}
165+
ref={timelineSectionListRef}
153166
itemContent={(index, [groupId, group]) => (
154167
<WorkflowHistoryTimelineGroup
155168
key={groupId}

0 commit comments

Comments
 (0)