Skip to content

Commit 88c4181

Browse files
authored
Add sorting for subscription details workflows tab (#1425)
* Add sorting for subscription details workflows tab * Added changeset * Moved type to WfoRadioDropdown
1 parent 94ed80b commit 88c4181

File tree

8 files changed

+191
-25
lines changed

8 files changed

+191
-25
lines changed

.changeset/slow-files-yawn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@orchestrator-ui/orchestrator-ui-components': patch
3+
---
4+
5+
1378 Add sorting for subscription details workflows tab
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import React, { useState } from 'react';
2+
3+
import {
4+
EuiButtonEmpty,
5+
EuiFlexGroup,
6+
EuiPopover,
7+
EuiRadioGroup,
8+
} from '@elastic/eui';
9+
import { EuiRadioGroupOption } from '@elastic/eui/src/components/form/radio/radio_group';
10+
11+
export interface WfoRadioDropdownProps<T> {
12+
options: WfoRadioDropdownOption<T>[];
13+
selectedOption: WfoRadioDropdownOption<T>;
14+
onUpdateOption: (value: WfoRadioDropdownOption<T>) => void;
15+
}
16+
17+
export type WfoRadioDropdownOption<T> = {
18+
label: string;
19+
id: string;
20+
value: T;
21+
};
22+
23+
export const WfoRadioDropdown = <T,>({
24+
options,
25+
onUpdateOption,
26+
selectedOption,
27+
}: WfoRadioDropdownProps<T>) => {
28+
const [isOpen, setIsOpen] = useState(false);
29+
30+
const handleClose = () => {
31+
if (isOpen) {
32+
setIsOpen(false);
33+
}
34+
};
35+
const handleSelectRadio = (id: string) => {
36+
const updatedOption = options.find((option) => option.id === id);
37+
setTimeout(handleClose, 100);
38+
if (updatedOption) {
39+
onUpdateOption(updatedOption);
40+
}
41+
};
42+
43+
const buttonLabel = options.find(
44+
(option) => option.id === selectedOption.id,
45+
)?.label;
46+
const radioGroupOptions: EuiRadioGroupOption[] = options.map((option) => ({
47+
id: option.id,
48+
label: option.label,
49+
}));
50+
51+
return (
52+
<EuiFlexGroup
53+
gutterSize="s"
54+
alignItems="center"
55+
justifyContent="flexEnd"
56+
>
57+
<EuiPopover
58+
button={
59+
<EuiButtonEmpty
60+
size="s"
61+
iconType="arrowDown"
62+
iconSide="right"
63+
onClick={() => {
64+
setIsOpen((isOpen) => !isOpen);
65+
}}
66+
css={{
67+
'&:focus': {
68+
backgroundColor: 'transparent',
69+
textDecoration: 'none',
70+
},
71+
}}
72+
>
73+
{buttonLabel}
74+
</EuiButtonEmpty>
75+
}
76+
isOpen={isOpen}
77+
closePopover={handleClose}
78+
anchorPosition="downLeft"
79+
>
80+
<EuiRadioGroup
81+
options={radioGroupOptions}
82+
idSelected={selectedOption.id}
83+
onChange={handleSelectRadio}
84+
/>
85+
</EuiPopover>
86+
</EuiFlexGroup>
87+
);
88+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './WfoRadioDropdown';

packages/orchestrator-ui-components/src/components/WfoSubscription/WfoProcessesTimeline.tsx

Lines changed: 71 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,26 @@ import React from 'react';
22

33
import { useTranslations } from 'next-intl';
44

5-
import { EuiComment, EuiCommentList, EuiSpacer, EuiText } from '@elastic/eui';
5+
import {
6+
EuiComment,
7+
EuiCommentList,
8+
EuiFlexGroup,
9+
EuiSpacer,
10+
EuiText,
11+
} from '@elastic/eui';
12+
13+
import { WfoLoading, WfoRadioDropdownOption } from '@/components';
14+
import { PATH_TASKS, PATH_WORKFLOWS } from '@/components';
15+
import { WfoRadioDropdown, sortProcessesByDate } from '@/components';
16+
import { useWithOrchestratorTheme } from '@/hooks';
17+
import { SortOrder, SubscriptionDetailProcess } from '@/types';
18+
import {
19+
parseDate,
20+
parseDateToLocaleDateTimeString,
21+
upperCaseFirstChar,
22+
} from '@/utils';
623

7-
import { useWithOrchestratorTheme } from '../../hooks';
8-
import { SubscriptionDetailProcess } from '../../types';
9-
import { parseDate, parseDateToLocaleDateTimeString } from '../../utils';
10-
import { upperCaseFirstChar } from '../../utils';
1124
import { WfoProcessStatusBadge } from '../WfoBadges';
12-
import { WfoLoading } from '../WfoLoading';
13-
import { PATH_TASKS, PATH_WORKFLOWS } from '../WfoPageTemplate';
1425
import { WfoTargetTypeIcon } from './WfoTargetTypeIcon';
1526
import { getSubscriptionDetailStyles } from './styles';
1627

@@ -104,14 +115,19 @@ const WfoRenderSubscriptionProcess = ({
104115
/>
105116
}
106117
>
107-
<div css={timeLineStyle}>
118+
<EuiFlexGroup
119+
alignItems="center"
120+
gutterSize="s"
121+
css={timeLineStyle}
122+
>
108123
<EuiText css={workflowTargetStyle}>
109124
{upperCaseFirstChar(
110125
subscriptionDetailProcess.workflowTarget,
111126
)}
112127
</EuiText>
128+
<EuiText>-</EuiText>
113129
<EuiText>{subscriptionDetailProcess.workflowName}</EuiText>
114-
</div>
130+
</EuiFlexGroup>
115131

116132
<WfoProcessCard
117133
subscriptionDetailProcess={subscriptionDetailProcess}
@@ -127,26 +143,56 @@ interface WfoProcessesTimelineProps {
127143
export const WfoProcessesTimeline = ({
128144
subscriptionDetailProcesses,
129145
}: WfoProcessesTimelineProps) => {
146+
const t = useTranslations('subscriptions.detail.workflowsTab');
147+
const options: WfoRadioDropdownOption<SortOrder>[] = [
148+
{
149+
label: t('startWithOldestLabel'),
150+
id: 'radioButtonOldest',
151+
value: SortOrder.ASC,
152+
},
153+
{
154+
label: t('startWithNewestLabel'),
155+
id: 'radioButtonNewest',
156+
value: SortOrder.DESC,
157+
},
158+
];
159+
160+
const [selectedOption, setSelectedOption] = React.useState(options[0]);
161+
162+
const handleOnSelectOption = (
163+
option: WfoRadioDropdownOption<SortOrder>,
164+
) => {
165+
setSelectedOption(option);
166+
};
167+
168+
const sortedProcesses = sortProcessesByDate(
169+
subscriptionDetailProcesses,
170+
selectedOption.value,
171+
);
172+
130173
return (
131174
<>
132175
<EuiSpacer size={'m'} />
133176
{!subscriptionDetailProcesses && <WfoLoading />}
134-
<EuiCommentList aria-label="Processes">
135-
{subscriptionDetailProcesses && (
136-
<EuiCommentList aria-label="Processes">
137-
{subscriptionDetailProcesses
138-
.filter((process) => !process.isTask)
139-
.map((subscriptionDetailProcess, index) => (
140-
<WfoRenderSubscriptionProcess
141-
key={index}
142-
subscriptionDetailProcess={
143-
subscriptionDetailProcess
144-
}
145-
/>
146-
))}
147-
</EuiCommentList>
148-
)}
149-
</EuiCommentList>
177+
<WfoRadioDropdown
178+
options={options}
179+
onUpdateOption={handleOnSelectOption}
180+
selectedOption={selectedOption}
181+
/>
182+
{sortedProcesses && (
183+
<EuiCommentList aria-label="Processes">
184+
{sortedProcesses
185+
.filter((process) => !process.isTask)
186+
.map((subscriptionDetailProcess, index) => (
187+
<WfoRenderSubscriptionProcess
188+
key={index}
189+
subscriptionDetailProcess={
190+
subscriptionDetailProcess
191+
}
192+
/>
193+
))}
194+
</EuiCommentList>
195+
)}
150196
</>
151197
);
152198
};

packages/orchestrator-ui-components/src/components/WfoSubscription/utils/utils.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { EuiThemeComputed } from '@elastic/eui';
55
import {
66
FieldValue,
77
ProcessStatus,
8+
SortOrder,
89
SubscriptionAction,
910
SubscriptionDetailProcess,
1011
WorkflowTarget,
@@ -126,3 +127,19 @@ export const getLatestTaskDate = (processes: SubscriptionDetailProcess[]) => {
126127

127128
return tasks.length > 0 ? tasks[0].startedAt : '';
128129
};
130+
131+
export const sortProcessesByDate = (
132+
processList: SubscriptionDetailProcess[],
133+
sortOrder: SortOrder,
134+
) => {
135+
return [...processList].sort((a, b) => {
136+
const dateA = new Date(a.startedAt).getTime();
137+
const dateB = new Date(b.startedAt).getTime();
138+
139+
if (sortOrder === SortOrder.ASC) {
140+
return dateA - dateB; // Ascending order (oldest first)
141+
} else {
142+
return dateB - dateA; // Descending order (newest first)
143+
}
144+
});
145+
};

packages/orchestrator-ui-components/src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ export * from './WfoStartButton';
2929
export * from './WfoSubscriptionsList';
3030
export * from './WfoSummary';
3131
export * from './WfoTitleWithWebsocketBadge';
32+
export * from './WfoRadioDropdown';

packages/orchestrator-ui-components/src/messages/en-GB.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,10 @@
357357
"setInSyncSuccess": {
358358
"title": "Subscription set in sync",
359359
"text": "The subscription was successfully set in sync."
360+
},
361+
"workflowsTab": {
362+
"startWithOldestLabel": "Start with oldest first",
363+
"startWithNewestLabel": "Start with newest first"
360364
}
361365
}
362366
},

packages/orchestrator-ui-components/src/messages/nl-NL.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,10 @@
356356
"setInSyncSuccess": {
357357
"title": "Subscription inSync",
358358
"text": "De subscription is in sync gezet."
359+
},
360+
"workflowsTab": {
361+
"startWithOldestLabel": "Start met oudste eerst",
362+
"startWithNewestLabel": "Start met nieuwste eerst"
359363
}
360364
}
361365
},

0 commit comments

Comments
 (0)