mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-09 00:18:00 +01:00
Change request approvers displaying in UI (#2358)
This PR adds UI for approvers to the change requests feature.
This commit is contained in:
parent
f316e99dca
commit
ff11f30e1d
@ -1,4 +1,4 @@
|
|||||||
import { styled } from '@mui/material';
|
import { FormControlLabel, styled, Switch } from '@mui/material';
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { Box } from '@mui/material';
|
import { Box } from '@mui/material';
|
||||||
import { useChangeRequest } from 'hooks/api/getters/useChangeRequest/useChangeRequest';
|
import { useChangeRequest } from 'hooks/api/getters/useChangeRequest/useChangeRequest';
|
||||||
@ -15,6 +15,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
|
|||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
import Paper from '@mui/material/Paper';
|
import Paper from '@mui/material/Paper';
|
||||||
import { ReviewButton } from './ReviewButton/ReviewButton';
|
import { ReviewButton } from './ReviewButton/ReviewButton';
|
||||||
|
import { ChangeRequestReviewer } from './ChangeRequestReviewers/ChangeRequestReviewer';
|
||||||
|
|
||||||
const StyledAsideBox = styled(Box)(({ theme }) => ({
|
const StyledAsideBox = styled(Box)(({ theme }) => ({
|
||||||
width: '30%',
|
width: '30%',
|
||||||
@ -76,7 +77,22 @@ export const ChangeRequestOverview: FC = () => {
|
|||||||
<Box sx={{ display: 'flex' }}>
|
<Box sx={{ display: 'flex' }}>
|
||||||
<StyledAsideBox>
|
<StyledAsideBox>
|
||||||
<ChangeRequestTimeline state={changeRequest.state} />
|
<ChangeRequestTimeline state={changeRequest.state} />
|
||||||
{/* <ChangeRequestReviewers /> */}
|
<ConditionallyRender
|
||||||
|
condition={changeRequest.approvals.length > 0}
|
||||||
|
show={
|
||||||
|
<ChangeRequestReviewers>
|
||||||
|
{changeRequest.approvals.map(approver => (
|
||||||
|
<ChangeRequestReviewer
|
||||||
|
name={
|
||||||
|
approver.createdBy.username ||
|
||||||
|
'Test account'
|
||||||
|
}
|
||||||
|
imageUrl={approver.createdBy.imageUrl}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</ChangeRequestReviewers>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</StyledAsideBox>
|
</StyledAsideBox>
|
||||||
<StyledPaper elevation={0}>
|
<StyledPaper elevation={0}>
|
||||||
<StyledInnerContainer>
|
<StyledInnerContainer>
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
import { Box, Paper, styled, Typography } from '@mui/material';
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
import { StyledAvatar } from '../ChangeRequestHeader/ChangeRequestHeader.styles';
|
||||||
|
import { CheckCircle } from '@mui/icons-material';
|
||||||
|
|
||||||
|
interface IChangeRequestReviewerProps {
|
||||||
|
name?: string;
|
||||||
|
imageUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StyledBox = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
marginTop: theme.spacing(1.5),
|
||||||
|
gap: theme.spacing(1),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const StyledSuccessIcon = styled(CheckCircle)(({ theme }) => ({
|
||||||
|
color: theme.palette.success.main,
|
||||||
|
height: '25px',
|
||||||
|
width: '25px',
|
||||||
|
marginRight: theme.spacing(1),
|
||||||
|
marginLeft: 'auto',
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const ChangeRequestReviewer: FC<IChangeRequestReviewerProps> = ({
|
||||||
|
name,
|
||||||
|
imageUrl,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<StyledBox>
|
||||||
|
<StyledAvatar src={imageUrl} />
|
||||||
|
<Typography variant="body1" color="text.secondary">
|
||||||
|
{name}
|
||||||
|
</Typography>
|
||||||
|
<StyledSuccessIcon />
|
||||||
|
</StyledBox>
|
||||||
|
);
|
||||||
|
};
|
@ -1,16 +1,25 @@
|
|||||||
import { Box, Paper } from '@mui/material';
|
import { Box, Paper, styled, Typography } from '@mui/material';
|
||||||
|
import { FC } from 'react';
|
||||||
|
|
||||||
export const ChangeRequestReviewers = () => {
|
const StyledBox = styled(Box)(({ theme }) => ({
|
||||||
|
marginBottom: theme.spacing(2),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const ChangeRequestReviewers: FC = ({ children }) => {
|
||||||
return (
|
return (
|
||||||
<Paper
|
<Paper
|
||||||
elevation={0}
|
elevation={0}
|
||||||
sx={theme => ({
|
sx={theme => ({
|
||||||
marginTop: theme.spacing(2),
|
marginTop: theme.spacing(2),
|
||||||
padding: 2,
|
padding: theme.spacing(4),
|
||||||
borderRadius: theme => `${theme.shape.borderRadiusLarge}px`,
|
borderRadius: theme => `${theme.shape.borderRadiusLarge}px`,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Box sx={theme => ({ padding: theme.spacing(2) })}>Reviewers</Box>
|
<StyledBox>Reviewers</StyledBox>
|
||||||
|
<Typography variant="body1" color="text.secondary">
|
||||||
|
Approved by
|
||||||
|
</Typography>
|
||||||
|
{children}
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -9,6 +9,7 @@ export interface IChangeRequest {
|
|||||||
createdBy: Pick<IUser, 'id' | 'username' | 'imageUrl'>;
|
createdBy: Pick<IUser, 'id' | 'username' | 'imageUrl'>;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
features: IChangeRequestFeature[];
|
features: IChangeRequestFeature[];
|
||||||
|
approvals: IChangeRequestApproval[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IChangeRequestFeature {
|
export interface IChangeRequestFeature {
|
||||||
@ -17,6 +18,11 @@ export interface IChangeRequestFeature {
|
|||||||
changes: IChangeRequestEvent[];
|
changes: IChangeRequestEvent[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IChangeRequestApproval {
|
||||||
|
createdBy: Pick<IUser, 'id' | 'username' | 'imageUrl'>;
|
||||||
|
createdAt: Date;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IChangeRequestBase {
|
export interface IChangeRequestBase {
|
||||||
id: number;
|
id: number;
|
||||||
action: ChangeRequestAction;
|
action: ChangeRequestAction;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import { formatApiPath } from 'utils/formatPath';
|
import { formatApiPath } from 'utils/formatPath';
|
||||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||||
|
import { IChangeRequest } from 'component/changeRequest/changeRequest.types';
|
||||||
|
|
||||||
export const useChangeRequest = (projectId: string, id: string) => {
|
export const useChangeRequest = (projectId: string, id: string) => {
|
||||||
const { data, error, mutate } = useSWR(
|
const { data, error, mutate } = useSWR<IChangeRequest>(
|
||||||
formatApiPath(`api/admin/projects/${projectId}/change-requests/${id}`),
|
formatApiPath(`api/admin/projects/${projectId}/change-requests/${id}`),
|
||||||
fetcher
|
fetcher
|
||||||
);
|
);
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
export interface IChangeRequest {
|
|
||||||
id: number;
|
|
||||||
state:
|
|
||||||
| 'CREATED'
|
|
||||||
| 'UPDATED'
|
|
||||||
| 'SUBMITTED'
|
|
||||||
| 'APPROVED'
|
|
||||||
| 'REJECTED'
|
|
||||||
| 'CLOSED';
|
|
||||||
project: string;
|
|
||||||
environment: string;
|
|
||||||
createdBy?: string;
|
|
||||||
createdAt?: Date;
|
|
||||||
changes?: IChangeRequestEvent[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IChangeRequestEvent {
|
|
||||||
id: number;
|
|
||||||
action:
|
|
||||||
| 'updateEnabled'
|
|
||||||
| 'strategyAdd'
|
|
||||||
| 'strategyUpdate'
|
|
||||||
| 'strategyDelete';
|
|
||||||
feature: string;
|
|
||||||
payload?: unknown;
|
|
||||||
createdBy?: string;
|
|
||||||
createdAt?: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum ChangeRequestEvent {
|
|
||||||
CREATED = 'CREATED',
|
|
||||||
UPDATED = 'UPDATED',
|
|
||||||
SUBMITTED = 'SUBMITTED',
|
|
||||||
APPROVED = 'APPROVED',
|
|
||||||
REJECTED = 'REJECTED',
|
|
||||||
CLOSED = 'CLOSED',
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user