diff --git a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.test.tsx b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.test.tsx
index 63a6045000..00c10eebfa 100644
--- a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.test.tsx
+++ b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.test.tsx
@@ -7,13 +7,13 @@ import {
} from './ChangeRequestTimeline.tsx';
import type { ChangeRequestState } from '../../changeRequest.types';
-test('cancelled timeline shows all states', () => {
+test('cancelled timeline shows expected states', () => {
render();
expect(screen.getByText('Draft')).toBeInTheDocument();
expect(screen.getByText('In review')).toBeInTheDocument();
expect(screen.getByText('Approved')).toBeInTheDocument();
- expect(screen.getByText('Applied')).toBeInTheDocument();
+ expect(screen.getByText('Cancelled')).toBeInTheDocument();
});
test('approved timeline shows all states', () => {
diff --git a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.tsx b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.tsx
index 9f7eac308b..b8758a2edc 100644
--- a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.tsx
+++ b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.tsx
@@ -15,6 +15,13 @@ import { HtmlTooltip } from '../../../common/HtmlTooltip/HtmlTooltip.tsx';
import ErrorIcon from '@mui/icons-material/Error';
import { useLocationSettings } from 'hooks/useLocationSettings';
import { formatDateYMDHM } from 'utils/formatDate.ts';
+import {
+ stepsFromTimestamps,
+ rejectedSteps,
+ scheduledSteps,
+ cancelledSteps,
+ steps,
+} from './change-request-timeline-steps.ts';
export type ISuggestChangeTimelineProps = {
timestamps?: ChangeRequestType['stateTransitionTimestamps']; // todo: update with flag `timestampsInChangeRequestTimeline`
@@ -58,21 +65,6 @@ const StyledTimeline = styled(Timeline)(() => ({
},
}));
-const steps: ChangeRequestState[] = [
- 'Draft',
- 'In review',
- 'Approved',
- 'Applied',
-];
-const rejectedSteps: ChangeRequestState[] = ['Draft', 'In review', 'Rejected'];
-const scheduledSteps: ChangeRequestState[] = [
- 'Draft',
- 'In review',
- 'Approved',
- 'Scheduled',
- 'Applied',
-];
-
export const determineColor = (
changeRequestState: ChangeRequestState,
changeRequestStateIndex: number,
@@ -101,11 +93,22 @@ export const ChangeRequestTimeline: FC = ({
let data: ChangeRequestState[];
switch (state) {
case 'Rejected':
- data = rejectedSteps;
+ if (timestamps) {
+ data = stepsFromTimestamps(timestamps, 'Rejected');
+ } else {
+ data = rejectedSteps;
+ }
break;
case 'Scheduled':
data = scheduledSteps;
break;
+ case 'Cancelled':
+ if (timestamps) {
+ data = stepsFromTimestamps(timestamps, 'Cancelled');
+ } else {
+ data = cancelledSteps;
+ }
+ break;
default:
data = steps;
}
diff --git a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/change-request-timeline-steps.test.ts b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/change-request-timeline-steps.test.ts
new file mode 100644
index 0000000000..c196599a3b
--- /dev/null
+++ b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/change-request-timeline-steps.test.ts
@@ -0,0 +1,55 @@
+import { stepsFromTimestamps } from './change-request-timeline-steps.ts';
+
+describe('stepsFromTimestamps', () => {
+ test.each(['Rejected', 'Cancelled'])(
+ "always includes 'Draft' and 'In review' and the current stage (%s)",
+ (state) => {
+ expect(
+ stepsFromTimestamps({}, state as 'Rejected' | 'Cancelled'),
+ ).toStrictEqual(['Draft', 'In review', state]);
+ },
+ );
+
+ test('Includes all steps in the timestamps object', () => {
+ expect(
+ stepsFromTimestamps(
+ {
+ Draft: {},
+ 'In review': {},
+ Approved: {},
+ Rejected: {},
+ },
+ 'Rejected',
+ ),
+ ).toStrictEqual(['Draft', 'In review', 'Approved', 'Rejected']);
+
+ expect(
+ stepsFromTimestamps(
+ {
+ Draft: {},
+ Approved: {},
+ Scheduled: {},
+ },
+ 'Rejected',
+ ),
+ ).toStrictEqual([
+ 'Draft',
+ 'In review',
+ 'Approved',
+ 'Scheduled',
+ 'Rejected',
+ ]);
+
+ // The implementation is naïve, so even if a CR must be approved to be
+ // scheduled, if the timestamps object does not contain the 'Approved'
+ // step, it will not be included.
+ expect(
+ stepsFromTimestamps(
+ {
+ Scheduled: {},
+ },
+ 'Rejected',
+ ),
+ ).toStrictEqual(['Draft', 'In review', 'Scheduled', 'Rejected']);
+ });
+});
diff --git a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/change-request-timeline-steps.ts b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/change-request-timeline-steps.ts
new file mode 100644
index 0000000000..8a6c3785f6
--- /dev/null
+++ b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/change-request-timeline-steps.ts
@@ -0,0 +1,49 @@
+import type { ChangeRequestState } from 'component/changeRequest/changeRequest.types';
+
+export const stepsFromTimestamps = (
+ timestamps: Partial>,
+ currentState: Extract,
+): ChangeRequestState[] => {
+ const optionalSteps: ChangeRequestState[] = [
+ 'Approved',
+ 'Applied',
+ 'Cancelled',
+ 'Scheduled',
+ 'Rejected',
+ ];
+
+ return [
+ 'Draft',
+ 'In review',
+ ...optionalSteps.filter(
+ (step) => timestamps.hasOwnProperty(step) || step === currentState,
+ ),
+ ];
+};
+
+export const steps: ChangeRequestState[] = [
+ 'Draft',
+ 'In review',
+ 'Approved',
+ 'Applied',
+];
+
+export const rejectedSteps: ChangeRequestState[] = [
+ 'Draft',
+ 'In review',
+ 'Rejected',
+];
+export const cancelledSteps: ChangeRequestState[] = [
+ 'Draft',
+ 'In review',
+ 'Approved',
+ 'Cancelled',
+];
+
+export const scheduledSteps: ChangeRequestState[] = [
+ 'Draft',
+ 'In review',
+ 'Approved',
+ 'Scheduled',
+ 'Applied',
+];