1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-10 01:16:39 +02:00

Feat/review page timeline (#2310)

* fix: styling

* feat: overview timeline

* fix: rename types

* fix: pr comments
This commit is contained in:
Fredrik Strand Oseberg 2022-11-02 11:14:26 +01:00 committed by GitHub
parent 9fb431aab7
commit 9b10a8815b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 141 additions and 53 deletions

View File

@ -7,9 +7,9 @@ import { ChangeRequestReviewers } from './ChangeRequestReviewers/ChangeRequestRe
import { ChangeRequest } from '../ChangeRequest/ChangeRequest';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi';
import { ChangeRequestReviewStatus } from './ChangeRequestReviewStatus/ChangeRequestReviewStatus';
import useToast from 'hooks/useToast';
import { formatUnknownError } from 'utils/formatUnknownError';
import { ChangeRequestReviewStatus } from './ChangeRequestReviewStatus/ChangeRequestReviewStatus';
export const ChangeRequestOverview: FC = () => {
const projectId = useRequiredPathParam('projectId');
@ -46,7 +46,7 @@ export const ChangeRequestOverview: FC = () => {
flexDirection: 'column',
}}
>
<ChangeRequestTimeline />
<ChangeRequestTimeline state={changeRequest.state} />
<ChangeRequestReviewers />
</Box>
<Paper
@ -66,7 +66,13 @@ export const ChangeRequestOverview: FC = () => {
})}
>
<ChangeRequest changeRequest={changeRequest} />
<ChangeRequestReviewStatus approved={true} />
<ChangeRequestReviewStatus
approved={
changeRequest.state === 'Approved' ||
changeRequest.state === 'Applied'
}
/>
<Button
variant="contained"
sx={{ marginTop: 2 }}

View File

@ -3,7 +3,7 @@ import { Cancel, CheckCircle } from '@mui/icons-material';
import { Box, Typography, Divider } from '@mui/material';
const styledComponentPropCheck = () => (prop: string) =>
prop !== 'color' && prop !== 'sx';
prop !== 'color' && prop !== 'sx' && prop !== 'approved';
export const StyledFlexAlignCenterBox = styled(Box)(({ theme }) => ({
display: 'flex',

View File

@ -12,7 +12,6 @@ import {
StyledReviewTitle,
StyledDivider,
} from './ChangeRequestReviewStatus.styles';
interface ISuggestChangeReviewsStatusProps {
approved: boolean;
}
@ -30,13 +29,11 @@ export const ChangeRequestReviewStatus: FC<
/>
</StyledButtonContainer>
<StyledReviewStatusContainer approved={approved}>
<StyledFlexAlignCenterBox>
<ConditionallyRender
condition={approved}
show={<Approved approved={approved} />}
elseShow={<ReviewRequired approved={approved} />}
/>
</StyledFlexAlignCenterBox>
<ConditionallyRender
condition={approved}
show={<Approved approved={approved} />}
elseShow={<ReviewRequired approved={approved} />}
/>
</StyledReviewStatusContainer>
</StyledOuterContainer>
);

View File

@ -1,4 +1,5 @@
import { FC } from 'react';
import { styled } from '@mui/material';
import { Box, Paper } from '@mui/material';
import Timeline from '@mui/lab/Timeline';
import TimelineItem, { timelineItemClasses } from '@mui/lab/TimelineItem';
@ -6,47 +7,123 @@ import TimelineSeparator from '@mui/lab/TimelineSeparator';
import TimelineDot from '@mui/lab/TimelineDot';
import TimelineConnector from '@mui/lab/TimelineConnector';
import TimelineContent from '@mui/lab/TimelineContent';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { ChangeRequestState } from '../changeRequest.types';
interface ISuggestChangeTimelineProps {
state: ChangeRequestState;
}
interface ITimelineData {
title: string;
active: boolean;
}
const StyledPaper = styled(Paper)(({ theme }) => ({
marginTop: theme.spacing(2),
borderRadius: `${theme.shape.borderRadiusLarge}px`,
}));
const StyledBox = styled(Box)(({ theme }) => ({
padding: theme.spacing(2),
marginBottom: `-${theme.spacing(4)}`,
}));
const StyledTimeline = styled(Timeline)(() => ({
[`& .${timelineItemClasses.root}:before`]: {
flex: 0,
padding: 0,
},
}));
export const ChangeRequestTimeline: FC<ISuggestChangeTimelineProps> = ({
state,
}) => {
const createTimeLineData = (state: ChangeRequestState): ITimelineData[] => {
const steps: ChangeRequestState[] = [
'Draft',
'In review',
'Approved',
'Applied',
];
return steps.map(step => ({
title: step,
active: step === state,
}));
};
const renderTimeline = () => {
const data = createTimeLineData(state);
const index = data.findIndex(item => item.active);
const activeIndex: number | null = index !== -1 ? index : null;
if (state === 'Cancelled') {
return createCancelledTimeline(data);
}
return createTimeline(data, activeIndex);
};
export const ChangeRequestTimeline: FC = () => {
return (
<Paper
elevation={0}
sx={theme => ({
marginTop: theme.spacing(2),
borderRadius: theme => `${theme.shape.borderRadiusLarge}px`,
})}
>
<Box sx={theme => ({ padding: theme.spacing(2) })}>
<Timeline
sx={{
[`& .${timelineItemClasses.root}:before`]: {
flex: 0,
padding: 0,
},
}}
>
<TimelineItem>
<TimelineSeparator>
<TimelineDot color="success" />
<TimelineConnector color="success" />
</TimelineSeparator>
<TimelineContent>Draft</TimelineContent>
</TimelineItem>
<TimelineItem>
<TimelineSeparator>
<TimelineDot color="success" />
<TimelineConnector />
</TimelineSeparator>
<TimelineContent>Approved</TimelineContent>
</TimelineItem>
<TimelineItem>
<TimelineSeparator>
<TimelineDot />
</TimelineSeparator>
<TimelineContent>Applied</TimelineContent>
</TimelineItem>
</Timeline>
</Box>
</Paper>
<StyledPaper elevation={0}>
<StyledBox>
<StyledTimeline>{renderTimeline()}</StyledTimeline>
</StyledBox>
</StyledPaper>
);
};
const createTimeline = (data: ITimelineData[], activeIndex: number | null) => {
return data.map(({ title }, index) => {
const shouldConnectToNextItem = index < data.length - 1;
const connector = (
<ConditionallyRender
condition={shouldConnectToNextItem}
show={<TimelineConnector />}
/>
);
if (activeIndex !== null && activeIndex >= index) {
return createTimelineItem('success', title, connector);
}
if (activeIndex !== null && activeIndex + 1 === index) {
return createTimelineItem('primary', title, connector, {
variant: 'outlined',
});
}
return createTimelineItem('grey', title, connector);
});
};
const createCancelledTimeline = (data: ITimelineData[]) => {
return data.map(({ title }, index) => {
const shouldConnectToNextItem = index < data.length - 1;
const connector = (
<ConditionallyRender
condition={shouldConnectToNextItem}
show={<TimelineConnector />}
/>
);
return createTimelineItem('grey', title, connector);
});
};
const createTimelineItem = (
color: 'primary' | 'success' | 'grey',
title: string,
connector: JSX.Element,
timelineDotProps: { [key: string]: string } = {}
) => {
return (
<TimelineItem key={title}>
<TimelineSeparator>
<TimelineDot color={color} {...timelineDotProps} />
{connector}
</TimelineSeparator>
<TimelineContent>{title}</TimelineContent>
</TimelineItem>
);
};

View File

@ -0,0 +1,6 @@
export type ChangeRequestState =
| 'Draft'
| 'Approved'
| 'In review'
| 'Applied'
| 'Cancelled';

View File

@ -84,6 +84,8 @@ export const FeatureView = () => {
return <FeatureNotFound />;
}
console.log(uiConfig?.flags);
return (
<MainLayout
ref={ref}

View File

@ -124,7 +124,7 @@ const Project = () => {
<MainLayout
ref={ref}
subheader={
!uiConfig?.flags?.changeRequests ? (
uiConfig?.flags?.changeRequests ? (
<DraftBanner project={projectId} />
) : null
}