diff --git a/frontend/package.json b/frontend/package.json
index 62a66cb5a8..b67c373ed5 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "unleash-frontend",
"description": "unleash your features",
- "version": "4.2.8",
+ "version": "4.2.9",
"keywords": [
"unleash",
"feature toggle",
@@ -53,7 +53,7 @@
"@welldone-software/why-did-you-render": "6.2.1",
"array-move": "3.0.1",
"classnames": "2.3.1",
- "copy-to-clipboard": "^3.3.1",
+ "copy-to-clipboard": "3.3.1",
"craco": "0.0.3",
"css-loader": "6.4.0",
"cypress": "8.6.0",
diff --git a/frontend/src/component/api-token/ApiTokenCreate/ApiTokenCreate.tsx b/frontend/src/component/api-token/ApiTokenCreate/ApiTokenCreate.tsx
index a82cd6e1ca..3ae313f3e3 100644
--- a/frontend/src/component/api-token/ApiTokenCreate/ApiTokenCreate.tsx
+++ b/frontend/src/component/api-token/ApiTokenCreate/ApiTokenCreate.tsx
@@ -5,6 +5,8 @@ import { styles as commonStyles } from '../../../component/common';
import { IApiTokenCreate } from '../../../hooks/api/actions/useApiTokensApi/useApiTokensApi';
import useEnvironments from '../../../hooks/api/getters/useEnvironments/useEnvironments';
import useProjects from '../../../hooks/api/getters/useProjects/useProjects';
+import useUiConfig from '../../../hooks/api/getters/useUiConfig/useUiConfig';
+import ConditionallyRender from '../../common/ConditionallyRender';
import Dialogue from '../../common/Dialogue';
import GeneralSelect from '../../common/GeneralSelect/GeneralSelect';
@@ -41,6 +43,7 @@ const ApiTokenCreate = ({
const [error, setError] = useState({});
const { projects } = useProjects();
const { environments } = useEnvironments();
+ const { uiConfig } = useUiConfig();
useEffect(() => {
if (
@@ -192,18 +195,22 @@ const ApiTokenCreate = ({
className={undefined}
classes={undefined}
/>
-
+
+
+ >
+ } />
);
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/context/ContextList/ContextList.jsx b/frontend/src/component/context/ContextList/ContextList.jsx
index 21e2d8b191..d055e93a5f 100644
--- a/frontend/src/component/context/ContextList/ContextList.jsx
+++ b/frontend/src/component/context/ContextList/ContextList.jsx
@@ -4,7 +4,7 @@ import HeaderTitle from '../../common/HeaderTitle';
import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyRender';
import {
CREATE_CONTEXT_FIELD,
- DELETE_CONTEXT_FIELD,
+ DELETE_CONTEXT_FIELD, UPDATE_CONTEXT_FIELD,
} from '../../providers/AccessProvider/permissions';
import {
IconButton,
@@ -39,10 +39,10 @@ const ContextList = ({ removeContextField, history, contextFields }) => {
+
{field.name}
- }
+ } elseShow={{field.name}} />}
secondary={field.description}
/>
{
- 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:
}
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
-
-
+
+
+
+
+