From 0dc5f306cc5fb4e46cf125fda3900b672feeb8c0 Mon Sep 17 00:00:00 2001 From: andreas-unleash Date: Fri, 17 Nov 2023 11:20:14 +0200 Subject: [PATCH] Feat: change request scheduled timeline (#5346) Adds the scheduled state to the timeline Closes # [1-1632](https://linear.app/unleash/issue/1-1632/update-the-progress-bar-for-scheduled-changes) ![Screenshot 2023-11-16 at 10 51 03](https://github.com/Unleash/unleash/assets/104830839/6267299e-d5c3-4cbf-9ab2-25da53f2d526) --------- Signed-off-by: andreas-unleash --- .../ChangeRequestOverview.tsx | 5 +- .../ChangeRequestTimeline.test.tsx | 25 ++++++++ .../ChangeRequestTimeline.tsx | 57 +++++++++++++++++-- 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestOverview.tsx b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestOverview.tsx index 65601f800b..bbeb908730 100644 --- a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestOverview.tsx +++ b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestOverview.tsx @@ -238,7 +238,10 @@ export const ChangeRequestOverview: FC = () => { - + diff --git a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.test.tsx b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.test.tsx index af047454f5..86625909c5 100644 --- a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.test.tsx +++ b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.test.tsx @@ -41,6 +41,21 @@ test('rejected timeline shows all states', () => { expect(screen.queryByText('Applied')).not.toBeInTheDocument(); }); +test('scheduled timeline shows all states', () => { + render( + , + ); + + expect(screen.getByText('Draft')).toBeInTheDocument(); + expect(screen.getByText('In review')).toBeInTheDocument(); + expect(screen.queryByText('Approved')).toBeInTheDocument(); + expect(screen.getByText('Scheduled')).toBeInTheDocument(); + expect(screen.queryByText('Applied')).toBeInTheDocument(); +}); + const irrelevantIndex = -99; // Using a number that's unlikely to be a valid index test('returns grey for Cancelled state regardless of displayed stage', () => { @@ -87,6 +102,16 @@ test('returns success for stages other than Rejected in Rejected state', () => { ), ).toBe('success'); }); +test('returns warning for Scheduled stage in Scheduled state', () => { + expect( + determineColor( + 'Scheduled', + irrelevantIndex, + 'Scheduled', + irrelevantIndex, + ), + ).toBe('warning'); +}); test('returns success for stages at or before activeIndex', () => { expect(determineColor('In review', 1, 'Draft', 0)).toBe('success'); diff --git a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.tsx b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.tsx index 86f5721574..3cd36dffd2 100644 --- a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.tsx +++ b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestTimeline/ChangeRequestTimeline.tsx @@ -1,5 +1,5 @@ import { FC } from 'react'; -import { Box, Paper, styled } from '@mui/material'; +import { Box, Paper, styled, Typography } from '@mui/material'; import Timeline from '@mui/lab/Timeline'; import TimelineItem, { timelineItemClasses } from '@mui/lab/TimelineItem'; import TimelineSeparator from '@mui/lab/TimelineSeparator'; @@ -7,9 +7,11 @@ import TimelineDot from '@mui/lab/TimelineDot'; import TimelineConnector from '@mui/lab/TimelineConnector'; import TimelineContent from '@mui/lab/TimelineContent'; import { ChangeRequestState } from '../../changeRequest.types'; +import { ConditionallyRender } from '../../../common/ConditionallyRender/ConditionallyRender'; interface ISuggestChangeTimelineProps { state: ChangeRequestState; + scheduledAt?: string; } const StyledPaper = styled(Paper)(({ theme }) => ({ @@ -36,6 +38,13 @@ const steps: ChangeRequestState[] = [ 'Applied', ]; const rejectedSteps: ChangeRequestState[] = ['Draft', 'In review', 'Rejected']; +const scheduledSteps: ChangeRequestState[] = [ + 'Draft', + 'In review', + 'Approved', + 'Scheduled', + 'Applied', +]; export const determineColor = ( changeRequestState: ChangeRequestState, @@ -44,21 +53,40 @@ export const determineColor = ( displayStageIndex: number, ) => { if (changeRequestState === 'Cancelled') return 'grey'; + if (changeRequestState === 'Rejected') return displayStage === 'Rejected' ? 'error' : 'success'; if ( changeRequestStateIndex !== -1 && - changeRequestStateIndex >= displayStageIndex + changeRequestStateIndex > displayStageIndex ) return 'success'; + if ( + changeRequestStateIndex !== -1 && + changeRequestStateIndex === displayStageIndex + ) { + return changeRequestState === 'Scheduled' ? 'warning' : 'success'; + } + if (changeRequestStateIndex + 1 === displayStageIndex) return 'primary'; return 'grey'; }; export const ChangeRequestTimeline: FC = ({ state, + scheduledAt, }) => { - const data = state === 'Rejected' ? rejectedSteps : steps; + let data; + switch (state) { + case 'Rejected': + data = rejectedSteps; + break; + case 'Scheduled': + data = scheduledSteps; + break; + default: + data = steps; + } const activeIndex = data.findIndex((item) => item === state); return ( @@ -66,6 +94,12 @@ export const ChangeRequestTimeline: FC = ({ {data.map((title, index) => { + const subtitle = + scheduledAt && + state === 'Scheduled' && + state === title + ? new Date(scheduledAt).toLocaleString() + : undefined; const color = determineColor( state, activeIndex, @@ -85,6 +119,7 @@ export const ChangeRequestTimeline: FC = ({ return createTimelineItem( color, title, + subtitle, index < data.length - 1, timelineDotProps, ); @@ -96,8 +131,9 @@ export const ChangeRequestTimeline: FC = ({ }; const createTimelineItem = ( - color: 'primary' | 'success' | 'grey' | 'error', + color: 'primary' | 'success' | 'grey' | 'error' | 'warning', title: string, + subtitle: string | undefined, shouldConnectToNextItem: boolean, timelineDotProps: { [key: string]: string | undefined } = {}, ) => ( @@ -106,6 +142,17 @@ const createTimelineItem = ( {shouldConnectToNextItem && } - {title} + + {title} +
+ {`(for ${subtitle})`} + } + /> +
);