From 83ad4041bf83b025b6fd28b15af1f9b3dcb00eae Mon Sep 17 00:00:00 2001 From: Christopher Kolstad Date: Thu, 21 Oct 2021 13:25:39 +0200 Subject: [PATCH] fix: Adds PermissionSwitch (#456) - This adds a generic way to control permission to mutations in the same way as our PermissionButton and PermissionIconButton already does the same. - This also switches the StrategiesList to use PermissionIconButton so users without ADMIN role do not believe they can deprecate/reactivate strategies. --- .../PermissionSwitch/PermissionSwitch.tsx | 40 ++++ .../FeatureToggleListNewItem.tsx | 14 +- .../FeatureOverviewMetaData.tsx | 8 +- .../AddFeatureVariant/AddFeatureVariant.tsx | 6 +- .../FeatureViewEnvironment.tsx | 13 +- .../ProjectEnvironment/ProjectEnvironment.tsx | 16 +- .../StrategiesList/StrategiesList.jsx | 90 ++++---- .../list-component-test.jsx.snap | 214 ++++++++++-------- 8 files changed, 225 insertions(+), 176 deletions(-) create mode 100644 frontend/src/component/common/PermissionSwitch/PermissionSwitch.tsx diff --git a/frontend/src/component/common/PermissionSwitch/PermissionSwitch.tsx b/frontend/src/component/common/PermissionSwitch/PermissionSwitch.tsx new file mode 100644 index 0000000000..1e9bb3eab2 --- /dev/null +++ b/frontend/src/component/common/PermissionSwitch/PermissionSwitch.tsx @@ -0,0 +1,40 @@ +import { Switch, Tooltip } from '@material-ui/core'; +import { OverridableComponent } from '@material-ui/core/OverridableComponent'; +import AccessContext from '../../../contexts/AccessContext'; +import React, { useContext } from 'react'; + +interface IPermissionSwitchProps extends OverridableComponent { + permission: string; + tooltip: string; + onChange?: (e: any) => void; + disabled?: boolean; + projectId?: string; +} + +const PermissionSwitch: React.FC = ({ + permission, + tooltip = '', + disabled, + projectId, + onChange, + ...rest +}) => { + const { hasAccess } = useContext(AccessContext); + const access = projectId + ? hasAccess(permission, projectId) + : hasAccess(permission); + + const tooltipText = access + ? tooltip + : "You don't have access to perform this operation"; + + return ( + + + + + + ) +} + +export default PermissionSwitch; diff --git a/frontend/src/component/feature/FeatureToggleListNew/FeatureToggleListNewItem/FeatureToggleListNewItem.tsx b/frontend/src/component/feature/FeatureToggleListNew/FeatureToggleListNewItem/FeatureToggleListNewItem.tsx index e65ee960fd..10c5aed07f 100644 --- a/frontend/src/component/feature/FeatureToggleListNew/FeatureToggleListNewItem/FeatureToggleListNewItem.tsx +++ b/frontend/src/component/feature/FeatureToggleListNew/FeatureToggleListNewItem/FeatureToggleListNewItem.tsx @@ -1,5 +1,5 @@ -import { useContext, useRef } from 'react'; -import { Switch, TableCell, TableRow } from '@material-ui/core'; +import { useRef } from 'react'; +import { TableCell, TableRow } from '@material-ui/core'; import { useHistory } from 'react-router'; import { useStyles } from '../FeatureToggleListNew.styles'; @@ -15,7 +15,7 @@ import classNames from 'classnames'; import CreatedAt from './CreatedAt'; import useProject from '../../../../hooks/api/getters/useProject/useProject'; import { UPDATE_FEATURE } from '../../../providers/AccessProvider/permissions'; -import AccessContext from '../../../../contexts/AccessContext'; +import PermissionSwitch from '../../../common/PermissionSwitch/PermissionSwitch'; interface IFeatureToggleListNewItemProps { name: string; @@ -34,7 +34,6 @@ const FeatureToggleListNewItem = ({ projectId, createdAt, }: IFeatureToggleListNewItemProps) => { - const { hasAccess } = useContext(AccessContext); const { toast, setToastData } = useToast(); const { toggleFeatureByEnvironment } = useToggleFeatureByEnv( projectId, @@ -127,11 +126,10 @@ const FeatureToggleListNewItem = ({ key={env.name} > - diff --git a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewMetaData/FeatureOverviewMetaData.tsx b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewMetaData/FeatureOverviewMetaData.tsx index 87d2d7f9fc..5bdabd12e1 100644 --- a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewMetaData/FeatureOverviewMetaData.tsx +++ b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewMetaData/FeatureOverviewMetaData.tsx @@ -9,6 +9,8 @@ import { useStyles } from './FeatureOverviewMetadata.styles'; import { Edit } from '@material-ui/icons'; import { IFeatureViewParams } from '../../../../../interfaces/params'; +import PermissionIconButton from '../../../../common/PermissionIconButton/PermissionIconButton'; +import { UPDATE_FEATURE } from '../../../../providers/AccessProvider/permissions'; const FeatureOverviewMetaData = () => { const styles = useStyles(); @@ -39,12 +41,14 @@ const FeatureOverviewMetaData = () => {
Description:

{description}

- - +
} diff --git a/frontend/src/component/feature/FeatureView2/FeatureVariants/FeatureVariantsList/AddFeatureVariant/AddFeatureVariant.tsx b/frontend/src/component/feature/FeatureView2/FeatureVariants/FeatureVariantsList/AddFeatureVariant/AddFeatureVariant.tsx index 0c20848aa2..45aa1221bf 100644 --- a/frontend/src/component/feature/FeatureView2/FeatureVariants/FeatureVariantsList/AddFeatureVariant/AddFeatureVariant.tsx +++ b/frontend/src/component/feature/FeatureView2/FeatureVariants/FeatureVariantsList/AddFeatureVariant/AddFeatureVariant.tsx @@ -4,7 +4,6 @@ import { FormControl, FormControlLabel, Grid, - Switch, TextField, InputAdornment, Button, @@ -20,6 +19,8 @@ import GeneralSelect from '../../../../../common/GeneralSelect/GeneralSelect'; import { useCommonStyles } from '../../../../../../common.styles'; import Dialogue from '../../../../../common/Dialogue'; import { trim, modalStyles } from '../../../../../common/util'; +import PermissionSwitch from '../../../../../common/PermissionSwitch/PermissionSwitch'; +import { UPDATE_FEATURE } from '../../../../../providers/AccessProvider/permissions'; const payloadOptions = [ { key: 'string', label: 'string' }, @@ -242,7 +243,8 @@ const AddVariant = ({ = ({ condition={env?.strategies?.length > 0} show={
- { - const { hasAccess } = useContext(AccessContext); - // api state const { toast, setToastData } = useToast(); const { uiConfig } = useUiConfig(); @@ -126,8 +124,6 @@ const ProjectEnvironmentList = ({ projectId }: ProjectEnvironmentListProps) => { enabled: project?.environments.includes(e.name), })); - const hasPermission = hasAccess(UPDATE_PROJECT, projectId); - const genLabel = (env: ProjectEnvironment) => ( <> {env.name} environment is{' '} @@ -143,9 +139,11 @@ const ProjectEnvironmentList = ({ projectId }: ProjectEnvironmentListProps) => { key={env.name} label={genLabel(env)} control={ - diff --git a/frontend/src/component/strategies/StrategiesList/StrategiesList.jsx b/frontend/src/component/strategies/StrategiesList/StrategiesList.jsx index 30dcd3ac77..88c8811376 100644 --- a/frontend/src/component/strategies/StrategiesList/StrategiesList.jsx +++ b/frontend/src/component/strategies/StrategiesList/StrategiesList.jsx @@ -4,27 +4,10 @@ import classnames from 'classnames'; import { Link, useHistory } from 'react-router-dom'; import useMediaQuery from '@material-ui/core/useMediaQuery'; -import { - List, - ListItem, - ListItemAvatar, - IconButton, - ListItemText, - Button, - Tooltip, -} from '@material-ui/core'; -import { - Add, - Visibility, - VisibilityOff, - Delete, - Extension, -} from '@material-ui/icons'; +import { IconButton, List, ListItem, ListItemAvatar, ListItemText, Tooltip } from '@material-ui/core'; +import { Add, Delete, Extension, Visibility, VisibilityOff } from '@material-ui/icons'; -import { - CREATE_STRATEGY, - DELETE_STRATEGY, -} from '../../providers/AccessProvider/permissions'; +import { CREATE_STRATEGY, DELETE_STRATEGY, UPDATE_STRATEGY } from '../../providers/AccessProvider/permissions'; import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyRender'; import PageContent from '../../common/PageContent/PageContent'; @@ -34,6 +17,8 @@ import { useStyles } from './styles'; import AccessContext from '../../../contexts/AccessContext'; import Dialogue from '../../common/Dialogue'; import { ADD_NEW_STRATEGY_ID } from '../../../testIds'; +import PermissionIconButton from '../../common/PermissionIconButton/PermissionIconButton'; +import PermissionButton from '../../common/PermissionButton/PermissionButton'; const StrategiesList = ({ strategies, @@ -60,26 +45,29 @@ const StrategiesList = ({ - history.push('/strategies/create') } + permission={CREATE_STRATEGY} + tooltip={'Add new strategy'} > - - + + } elseShow={ - + } /> } @@ -98,7 +86,7 @@ const StrategiesList = ({ const reactivateButton = strategy => ( - setDialogueMetaData({ show: true, @@ -106,9 +94,9 @@ const StrategiesList = ({ onConfirm: () => reactivateStrategy(strategy), }) } - > - - + permission={UPDATE_STRATEGY} + tooltip={'Reactivate activation strategy'} + > ); @@ -119,28 +107,28 @@ const StrategiesList = ({
- +
} elseShow={ - -
- - setDialogueMetaData({ - show: true, - title: 'Really deprecate strategy?', - onConfirm: () => - deprecateStrategy(strategy), - }) - } - > - - -
-
+
+ + setDialogueMetaData({ + show: true, + title: 'Really deprecate strategy?', + onConfirm: () => + deprecateStrategy(strategy), + }) + } + permission={UPDATE_STRATEGY} + tooltip={'Deprecate activation strategy'} + > + + +
} /> ); @@ -149,8 +137,7 @@ const StrategiesList = ({ - setDialogueMetaData({ show: true, @@ -158,10 +145,11 @@ const StrategiesList = ({ onConfirm: () => removeStrategy(strategy), }) } + permission={DELETE_STRATEGY} + tooltip={'Delete strategy'} > - - + } elseShow={ diff --git a/frontend/src/component/strategies/__tests__/__snapshots__/list-component-test.jsx.snap b/frontend/src/component/strategies/__tests__/__snapshots__/list-component-test.jsx.snap index e5c87bfe99..7a872fe07e 100644 --- a/frontend/src/component/strategies/__tests__/__snapshots__/list-component-test.jsx.snap +++ b/frontend/src/component/strategies/__tests__/__snapshots__/list-component-test.jsx.snap @@ -81,53 +81,52 @@ exports[`renders correctly with one strategy 1`] = ` another's description

-
- + + + + + +
@@ -164,34 +163,49 @@ exports[`renders correctly with one strategy without permissions 1`] = `
- + + Add new strategy + + + + +
@@ -245,53 +259,55 @@ exports[`renders correctly with one strategy without permissions 1`] = ` another's description

-
- + + + + + + +