mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
feat: add permission buttons for change requests (#2392)
* Adds permission buttons for change requests
This commit is contained in:
parent
74c5189159
commit
b9db7952fb
@ -1,5 +1,5 @@
|
||||
import { FormControlLabel, styled, Switch } from '@mui/material';
|
||||
import { FC } from 'react';
|
||||
import { Alert, styled } from '@mui/material';
|
||||
import { FC, useContext } from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import { useChangeRequest } from 'hooks/api/getters/useChangeRequest/useChangeRequest';
|
||||
import { ChangeRequestHeader } from './ChangeRequestHeader/ChangeRequestHeader';
|
||||
@ -12,10 +12,13 @@ import { ChangeRequestReviewStatus } from './ChangeRequestReviewStatus/ChangeReq
|
||||
import useToast from 'hooks/useToast';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import Button from '@mui/material/Button';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import { ReviewButton } from './ReviewButton/ReviewButton';
|
||||
import { ChangeRequestReviewer } from './ChangeRequestReviewers/ChangeRequestReviewer';
|
||||
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
|
||||
import { APPLY_CHANGE_REQUEST } from 'component/providers/AccessProvider/permissions';
|
||||
import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
|
||||
const StyledAsideBox = styled(Box)(({ theme }) => ({
|
||||
width: '30%',
|
||||
@ -43,6 +46,9 @@ const StyledInnerContainer = styled(Box)(({ theme }) => ({
|
||||
|
||||
export const ChangeRequestOverview: FC = () => {
|
||||
const projectId = useRequiredPathParam('projectId');
|
||||
const { user } = useAuthUser();
|
||||
const { isAdmin } = useContext(AccessContext);
|
||||
|
||||
const id = useRequiredPathParam('id');
|
||||
const { data: changeRequest, refetchChangeRequest } = useChangeRequest(
|
||||
projectId,
|
||||
@ -71,6 +77,11 @@ export const ChangeRequestOverview: FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const isSelfReview =
|
||||
changeRequest?.createdBy.id === user?.id &&
|
||||
changeRequest.state === 'In review' &&
|
||||
!isAdmin;
|
||||
|
||||
return (
|
||||
<>
|
||||
<ChangeRequestHeader changeRequest={changeRequest} />
|
||||
@ -98,6 +109,19 @@ export const ChangeRequestOverview: FC = () => {
|
||||
<StyledInnerContainer>
|
||||
Changes
|
||||
<ChangeRequest changeRequest={changeRequest} />
|
||||
<ConditionallyRender
|
||||
condition={isSelfReview}
|
||||
show={
|
||||
<Alert
|
||||
sx={theme => ({
|
||||
marginTop: theme.spacing(1.5),
|
||||
})}
|
||||
severity="info"
|
||||
>
|
||||
You can not approve your own change request
|
||||
</Alert>
|
||||
}
|
||||
/>
|
||||
<ChangeRequestReviewStatus
|
||||
state={changeRequest.state}
|
||||
/>
|
||||
@ -109,12 +133,17 @@ export const ChangeRequestOverview: FC = () => {
|
||||
<ConditionallyRender
|
||||
condition={changeRequest.state === 'Approved'}
|
||||
show={
|
||||
<Button
|
||||
<PermissionButton
|
||||
variant="contained"
|
||||
onClick={onApplyChanges}
|
||||
projectId={projectId}
|
||||
permission={APPLY_CHANGE_REQUEST}
|
||||
environmentId={
|
||||
changeRequest.environment
|
||||
}
|
||||
>
|
||||
Apply changes
|
||||
</Button>
|
||||
</PermissionButton>
|
||||
}
|
||||
/>
|
||||
</StyledButtonBox>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||
import { useChangeRequest } from 'hooks/api/getters/useChangeRequest/useChangeRequest';
|
||||
import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi';
|
||||
@ -6,21 +6,27 @@ import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
import useToast from 'hooks/useToast';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Grow,
|
||||
Paper,
|
||||
Popper,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
ClickAwayListener,
|
||||
Alert,
|
||||
} from '@mui/material';
|
||||
|
||||
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
||||
import { APPROVE_CHANGE_REQUEST } from 'component/providers/AccessProvider/permissions';
|
||||
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
|
||||
import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
|
||||
export const ReviewButton = () => {
|
||||
const { isAdmin } = useContext(AccessContext);
|
||||
const projectId = useRequiredPathParam('projectId');
|
||||
const id = useRequiredPathParam('id');
|
||||
const { refetchChangeRequest } = useChangeRequest(projectId, id);
|
||||
const { user } = useAuthUser();
|
||||
const { refetchChangeRequest, data } = useChangeRequest(projectId, id);
|
||||
const { setToastApiError, setToastData } = useToast();
|
||||
|
||||
const { changeState } = useChangeRequestApi();
|
||||
@ -77,8 +83,9 @@ export const ReviewButton = () => {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Button
|
||||
<PermissionButton
|
||||
variant="contained"
|
||||
disabled={data?.createdBy.id === user?.id && !isAdmin}
|
||||
aria-controls={open ? 'review-options-menu' : undefined}
|
||||
aria-expanded={open ? 'true' : undefined}
|
||||
aria-label="review changes"
|
||||
@ -86,9 +93,12 @@ export const ReviewButton = () => {
|
||||
onClick={onToggle}
|
||||
ref={anchorRef}
|
||||
endIcon={<ArrowDropDownIcon />}
|
||||
permission={APPROVE_CHANGE_REQUEST}
|
||||
projectId={projectId}
|
||||
environmentId={data?.environment}
|
||||
>
|
||||
Review changes
|
||||
</Button>
|
||||
</PermissionButton>
|
||||
<Popper
|
||||
sx={{
|
||||
zIndex: 1,
|
||||
|
@ -19,75 +19,86 @@ export interface IPermissionButtonProps extends Omit<ButtonProps, 'title'> {
|
||||
tooltipProps?: Omit<ITooltipResolverProps, 'children'>;
|
||||
}
|
||||
|
||||
const PermissionButton: React.FC<IPermissionButtonProps> = ({
|
||||
permission,
|
||||
variant = 'contained',
|
||||
color = 'primary',
|
||||
onClick,
|
||||
children,
|
||||
disabled,
|
||||
projectId,
|
||||
environmentId,
|
||||
tooltipProps,
|
||||
...rest
|
||||
}) => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
const id = useId();
|
||||
let access;
|
||||
|
||||
const handleAccess = () => {
|
||||
const PermissionButton: React.FC<IPermissionButtonProps> = React.forwardRef(
|
||||
(
|
||||
{
|
||||
permission,
|
||||
variant = 'contained',
|
||||
color = 'primary',
|
||||
onClick,
|
||||
children,
|
||||
disabled,
|
||||
projectId,
|
||||
environmentId,
|
||||
tooltipProps,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
const id = useId();
|
||||
let access;
|
||||
if (Array.isArray(permission)) {
|
||||
access = permission.some(permission => {
|
||||
if (projectId && environmentId) {
|
||||
return hasAccess(permission, projectId, environmentId);
|
||||
} else if (projectId) {
|
||||
return hasAccess(permission, projectId);
|
||||
} else {
|
||||
return hasAccess(permission);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (projectId && environmentId) {
|
||||
access = hasAccess(permission, projectId, environmentId);
|
||||
} else if (projectId) {
|
||||
access = hasAccess(permission, projectId);
|
||||
} else {
|
||||
access = hasAccess(permission);
|
||||
}
|
||||
}
|
||||
|
||||
return access;
|
||||
};
|
||||
|
||||
access = handleAccess();
|
||||
|
||||
return (
|
||||
<TooltipResolver
|
||||
{...tooltipProps}
|
||||
title={formatAccessText(access, tooltipProps?.title)}
|
||||
arrow
|
||||
>
|
||||
<span id={id}>
|
||||
<Button
|
||||
onClick={onClick}
|
||||
disabled={disabled || !access}
|
||||
aria-labelledby={id}
|
||||
variant={variant}
|
||||
color={color}
|
||||
{...rest}
|
||||
endIcon={
|
||||
<ConditionallyRender
|
||||
condition={!access}
|
||||
show={<Lock titleAccess="Locked" />}
|
||||
/>
|
||||
const handleAccess = () => {
|
||||
let access;
|
||||
if (Array.isArray(permission)) {
|
||||
access = permission.some(permission => {
|
||||
if (projectId && environmentId) {
|
||||
return hasAccess(permission, projectId, environmentId);
|
||||
} else if (projectId) {
|
||||
return hasAccess(permission, projectId);
|
||||
} else {
|
||||
return hasAccess(permission);
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
</span>
|
||||
</TooltipResolver>
|
||||
);
|
||||
};
|
||||
});
|
||||
} else {
|
||||
if (projectId && environmentId) {
|
||||
access = hasAccess(permission, projectId, environmentId);
|
||||
} else if (projectId) {
|
||||
access = hasAccess(permission, projectId);
|
||||
} else {
|
||||
access = hasAccess(permission);
|
||||
}
|
||||
}
|
||||
|
||||
return access;
|
||||
};
|
||||
|
||||
access = handleAccess();
|
||||
|
||||
return (
|
||||
<TooltipResolver
|
||||
{...tooltipProps}
|
||||
title={formatAccessText(access, tooltipProps?.title)}
|
||||
arrow
|
||||
>
|
||||
<span id={id}>
|
||||
<Button
|
||||
ref={ref}
|
||||
onClick={onClick}
|
||||
disabled={disabled || !access}
|
||||
aria-labelledby={id}
|
||||
variant={variant}
|
||||
color={color}
|
||||
{...rest}
|
||||
endIcon={
|
||||
<>
|
||||
<ConditionallyRender
|
||||
condition={!access}
|
||||
show={<Lock titleAccess="Locked" />}
|
||||
elseShow={
|
||||
Boolean(rest.endIcon) && rest.endIcon
|
||||
}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
</span>
|
||||
</TooltipResolver>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default PermissionButton;
|
||||
|
Loading…
Reference in New Issue
Block a user