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 { Alert, styled } from '@mui/material';
|
||||||
import { FC } from 'react';
|
import { FC, useContext } 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';
|
||||||
import { ChangeRequestHeader } from './ChangeRequestHeader/ChangeRequestHeader';
|
import { ChangeRequestHeader } from './ChangeRequestHeader/ChangeRequestHeader';
|
||||||
@ -12,10 +12,13 @@ import { ChangeRequestReviewStatus } from './ChangeRequestReviewStatus/ChangeReq
|
|||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
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';
|
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 }) => ({
|
const StyledAsideBox = styled(Box)(({ theme }) => ({
|
||||||
width: '30%',
|
width: '30%',
|
||||||
@ -43,6 +46,9 @@ const StyledInnerContainer = styled(Box)(({ theme }) => ({
|
|||||||
|
|
||||||
export const ChangeRequestOverview: FC = () => {
|
export const ChangeRequestOverview: FC = () => {
|
||||||
const projectId = useRequiredPathParam('projectId');
|
const projectId = useRequiredPathParam('projectId');
|
||||||
|
const { user } = useAuthUser();
|
||||||
|
const { isAdmin } = useContext(AccessContext);
|
||||||
|
|
||||||
const id = useRequiredPathParam('id');
|
const id = useRequiredPathParam('id');
|
||||||
const { data: changeRequest, refetchChangeRequest } = useChangeRequest(
|
const { data: changeRequest, refetchChangeRequest } = useChangeRequest(
|
||||||
projectId,
|
projectId,
|
||||||
@ -71,6 +77,11 @@ export const ChangeRequestOverview: FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isSelfReview =
|
||||||
|
changeRequest?.createdBy.id === user?.id &&
|
||||||
|
changeRequest.state === 'In review' &&
|
||||||
|
!isAdmin;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ChangeRequestHeader changeRequest={changeRequest} />
|
<ChangeRequestHeader changeRequest={changeRequest} />
|
||||||
@ -98,6 +109,19 @@ export const ChangeRequestOverview: FC = () => {
|
|||||||
<StyledInnerContainer>
|
<StyledInnerContainer>
|
||||||
Changes
|
Changes
|
||||||
<ChangeRequest changeRequest={changeRequest} />
|
<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
|
<ChangeRequestReviewStatus
|
||||||
state={changeRequest.state}
|
state={changeRequest.state}
|
||||||
/>
|
/>
|
||||||
@ -109,12 +133,17 @@ export const ChangeRequestOverview: FC = () => {
|
|||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={changeRequest.state === 'Approved'}
|
condition={changeRequest.state === 'Approved'}
|
||||||
show={
|
show={
|
||||||
<Button
|
<PermissionButton
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={onApplyChanges}
|
onClick={onApplyChanges}
|
||||||
|
projectId={projectId}
|
||||||
|
permission={APPLY_CHANGE_REQUEST}
|
||||||
|
environmentId={
|
||||||
|
changeRequest.environment
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Apply changes
|
Apply changes
|
||||||
</Button>
|
</PermissionButton>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</StyledButtonBox>
|
</StyledButtonBox>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||||
import { useChangeRequest } from 'hooks/api/getters/useChangeRequest/useChangeRequest';
|
import { useChangeRequest } from 'hooks/api/getters/useChangeRequest/useChangeRequest';
|
||||||
import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi';
|
import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi';
|
||||||
@ -6,21 +6,27 @@ import { formatUnknownError } from 'utils/formatUnknownError';
|
|||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
Grow,
|
Grow,
|
||||||
Paper,
|
Paper,
|
||||||
Popper,
|
Popper,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
MenuList,
|
MenuList,
|
||||||
ClickAwayListener,
|
ClickAwayListener,
|
||||||
|
Alert,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
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 = () => {
|
export const ReviewButton = () => {
|
||||||
|
const { isAdmin } = useContext(AccessContext);
|
||||||
const projectId = useRequiredPathParam('projectId');
|
const projectId = useRequiredPathParam('projectId');
|
||||||
const id = useRequiredPathParam('id');
|
const id = useRequiredPathParam('id');
|
||||||
const { refetchChangeRequest } = useChangeRequest(projectId, id);
|
const { user } = useAuthUser();
|
||||||
|
const { refetchChangeRequest, data } = useChangeRequest(projectId, id);
|
||||||
const { setToastApiError, setToastData } = useToast();
|
const { setToastApiError, setToastData } = useToast();
|
||||||
|
|
||||||
const { changeState } = useChangeRequestApi();
|
const { changeState } = useChangeRequestApi();
|
||||||
@ -77,8 +83,9 @@ export const ReviewButton = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Button
|
<PermissionButton
|
||||||
variant="contained"
|
variant="contained"
|
||||||
|
disabled={data?.createdBy.id === user?.id && !isAdmin}
|
||||||
aria-controls={open ? 'review-options-menu' : undefined}
|
aria-controls={open ? 'review-options-menu' : undefined}
|
||||||
aria-expanded={open ? 'true' : undefined}
|
aria-expanded={open ? 'true' : undefined}
|
||||||
aria-label="review changes"
|
aria-label="review changes"
|
||||||
@ -86,9 +93,12 @@ export const ReviewButton = () => {
|
|||||||
onClick={onToggle}
|
onClick={onToggle}
|
||||||
ref={anchorRef}
|
ref={anchorRef}
|
||||||
endIcon={<ArrowDropDownIcon />}
|
endIcon={<ArrowDropDownIcon />}
|
||||||
|
permission={APPROVE_CHANGE_REQUEST}
|
||||||
|
projectId={projectId}
|
||||||
|
environmentId={data?.environment}
|
||||||
>
|
>
|
||||||
Review changes
|
Review changes
|
||||||
</Button>
|
</PermissionButton>
|
||||||
<Popper
|
<Popper
|
||||||
sx={{
|
sx={{
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
|
@ -19,75 +19,86 @@ export interface IPermissionButtonProps extends Omit<ButtonProps, 'title'> {
|
|||||||
tooltipProps?: Omit<ITooltipResolverProps, 'children'>;
|
tooltipProps?: Omit<ITooltipResolverProps, 'children'>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PermissionButton: React.FC<IPermissionButtonProps> = ({
|
const PermissionButton: React.FC<IPermissionButtonProps> = React.forwardRef(
|
||||||
permission,
|
(
|
||||||
variant = 'contained',
|
{
|
||||||
color = 'primary',
|
permission,
|
||||||
onClick,
|
variant = 'contained',
|
||||||
children,
|
color = 'primary',
|
||||||
disabled,
|
onClick,
|
||||||
projectId,
|
children,
|
||||||
environmentId,
|
disabled,
|
||||||
tooltipProps,
|
projectId,
|
||||||
...rest
|
environmentId,
|
||||||
}) => {
|
tooltipProps,
|
||||||
const { hasAccess } = useContext(AccessContext);
|
...rest
|
||||||
const id = useId();
|
},
|
||||||
let access;
|
ref
|
||||||
|
) => {
|
||||||
const handleAccess = () => {
|
const { hasAccess } = useContext(AccessContext);
|
||||||
|
const id = useId();
|
||||||
let access;
|
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;
|
const handleAccess = () => {
|
||||||
};
|
let access;
|
||||||
|
if (Array.isArray(permission)) {
|
||||||
access = handleAccess();
|
access = permission.some(permission => {
|
||||||
|
if (projectId && environmentId) {
|
||||||
return (
|
return hasAccess(permission, projectId, environmentId);
|
||||||
<TooltipResolver
|
} else if (projectId) {
|
||||||
{...tooltipProps}
|
return hasAccess(permission, projectId);
|
||||||
title={formatAccessText(access, tooltipProps?.title)}
|
} else {
|
||||||
arrow
|
return hasAccess(permission);
|
||||||
>
|
|
||||||
<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" />}
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
>
|
});
|
||||||
{children}
|
} else {
|
||||||
</Button>
|
if (projectId && environmentId) {
|
||||||
</span>
|
access = hasAccess(permission, projectId, environmentId);
|
||||||
</TooltipResolver>
|
} 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;
|
export default PermissionButton;
|
||||||
|
Loading…
Reference in New Issue
Block a user