mirror of
https://github.com/Unleash/unleash.git
synced 2025-03-04 00:18:40 +01:00
Permission for variant environments (#2490)
adds permissions for variants per environment
This commit is contained in:
parent
137d2caaa4
commit
2a4ca96da2
@ -1,11 +1,13 @@
|
|||||||
import { Add, CloudCircle } from '@mui/icons-material';
|
import { Add, CloudCircle } from '@mui/icons-material';
|
||||||
import { Button, Divider, styled } from '@mui/material';
|
import { Divider, styled } from '@mui/material';
|
||||||
import { IFeatureEnvironment, IFeatureVariant } from 'interfaces/featureToggle';
|
import { IFeatureEnvironment, IFeatureVariant } from 'interfaces/featureToggle';
|
||||||
import { EnvironmentVariantsTable } from './EnvironmentVariantsTable/EnvironmentVariantsTable';
|
import { EnvironmentVariantsTable } from './EnvironmentVariantsTable/EnvironmentVariantsTable';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect';
|
import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
|
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
|
||||||
|
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
|
||||||
|
import { UPDATE_FEATURE_ENVIRONMENT_VARIANTS } from 'component/providers/AccessProvider/permissions';
|
||||||
|
|
||||||
const StyledCard = styled('div')(({ theme }) => ({
|
const StyledCard = styled('div')(({ theme }) => ({
|
||||||
padding: theme.spacing(3),
|
padding: theme.spacing(3),
|
||||||
@ -58,6 +60,7 @@ const StyledGeneralSelect = styled(GeneralSelect)(({ theme }) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
interface IEnvironmentVariantsCardProps {
|
interface IEnvironmentVariantsCardProps {
|
||||||
|
projectId: string;
|
||||||
environment: IFeatureEnvironment;
|
environment: IFeatureEnvironment;
|
||||||
searchValue: string;
|
searchValue: string;
|
||||||
onAddVariant: () => void;
|
onAddVariant: () => void;
|
||||||
@ -68,6 +71,7 @@ interface IEnvironmentVariantsCardProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const EnvironmentVariantsCard = ({
|
export const EnvironmentVariantsCard = ({
|
||||||
|
projectId,
|
||||||
environment,
|
environment,
|
||||||
searchValue,
|
searchValue,
|
||||||
onAddVariant,
|
onAddVariant,
|
||||||
@ -127,13 +131,16 @@ export const EnvironmentVariantsCard = ({
|
|||||||
onEditVariant={onEditVariant}
|
onEditVariant={onEditVariant}
|
||||||
onDeleteVariant={onDeleteVariant}
|
onDeleteVariant={onDeleteVariant}
|
||||||
/>
|
/>
|
||||||
<Button
|
<PermissionButton
|
||||||
|
permission={UPDATE_FEATURE_ENVIRONMENT_VARIANTS}
|
||||||
|
projectId={projectId}
|
||||||
|
environmentId={environment.name}
|
||||||
onClick={onAddVariant}
|
onClick={onAddVariant}
|
||||||
variant="text"
|
variant="text"
|
||||||
startIcon={<Add />}
|
startIcon={<Add />}
|
||||||
>
|
>
|
||||||
add variant
|
add variant
|
||||||
</Button>
|
</PermissionButton>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={variants.length > 1}
|
condition={variants.length > 1}
|
||||||
show={
|
show={
|
||||||
|
@ -111,6 +111,7 @@ export const EnvironmentVariantsTable = ({
|
|||||||
<VariantsActionCell
|
<VariantsActionCell
|
||||||
variant={original}
|
variant={original}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
|
environmentId={environment.name}
|
||||||
editVariant={onEditVariant}
|
editVariant={onEditVariant}
|
||||||
deleteVariant={onDeleteVariant}
|
deleteVariant={onDeleteVariant}
|
||||||
/>
|
/>
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { Edit, Delete } from '@mui/icons-material';
|
import { Edit, Delete } from '@mui/icons-material';
|
||||||
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
||||||
import { ActionCell } from 'component/common/Table/cells/ActionCell/ActionCell';
|
import { ActionCell } from 'component/common/Table/cells/ActionCell/ActionCell';
|
||||||
import { UPDATE_FEATURE_VARIANTS } from 'component/providers/AccessProvider/permissions';
|
import { UPDATE_FEATURE_ENVIRONMENT_VARIANTS } from 'component/providers/AccessProvider/permissions';
|
||||||
import { IFeatureVariant } from 'interfaces/featureToggle';
|
import { IFeatureVariant } from 'interfaces/featureToggle';
|
||||||
|
|
||||||
interface IVarintsActionCellProps {
|
interface IVarintsActionCellProps {
|
||||||
projectId: string;
|
projectId: string;
|
||||||
|
environmentId: string;
|
||||||
variant: IFeatureVariant;
|
variant: IFeatureVariant;
|
||||||
editVariant: (variant: IFeatureVariant) => void;
|
editVariant: (variant: IFeatureVariant) => void;
|
||||||
deleteVariant: (variant: IFeatureVariant) => void;
|
deleteVariant: (variant: IFeatureVariant) => void;
|
||||||
@ -13,6 +14,7 @@ interface IVarintsActionCellProps {
|
|||||||
|
|
||||||
export const VariantsActionCell = ({
|
export const VariantsActionCell = ({
|
||||||
projectId,
|
projectId,
|
||||||
|
environmentId,
|
||||||
variant,
|
variant,
|
||||||
editVariant,
|
editVariant,
|
||||||
deleteVariant,
|
deleteVariant,
|
||||||
@ -22,8 +24,9 @@ export const VariantsActionCell = ({
|
|||||||
<PermissionIconButton
|
<PermissionIconButton
|
||||||
size="large"
|
size="large"
|
||||||
data-testid={`VARIANT_EDIT_BUTTON_${variant.name}`}
|
data-testid={`VARIANT_EDIT_BUTTON_${variant.name}`}
|
||||||
permission={UPDATE_FEATURE_VARIANTS}
|
permission={UPDATE_FEATURE_ENVIRONMENT_VARIANTS}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
|
environmentId={environmentId}
|
||||||
onClick={() => editVariant(variant)}
|
onClick={() => editVariant(variant)}
|
||||||
tooltipProps={{
|
tooltipProps={{
|
||||||
title: 'Edit variant',
|
title: 'Edit variant',
|
||||||
@ -33,9 +36,10 @@ export const VariantsActionCell = ({
|
|||||||
</PermissionIconButton>
|
</PermissionIconButton>
|
||||||
<PermissionIconButton
|
<PermissionIconButton
|
||||||
size="large"
|
size="large"
|
||||||
permission={UPDATE_FEATURE_VARIANTS}
|
permission={UPDATE_FEATURE_ENVIRONMENT_VARIANTS}
|
||||||
data-testid={`VARIANT_DELETE_BUTTON_${variant.name}`}
|
data-testid={`VARIANT_DELETE_BUTTON_${variant.name}`}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
|
environmentId={environmentId}
|
||||||
onClick={() => deleteVariant(variant)}
|
onClick={() => deleteVariant(variant)}
|
||||||
tooltipProps={{
|
tooltipProps={{
|
||||||
title: 'Delete variant',
|
title: 'Delete variant',
|
||||||
|
@ -14,6 +14,7 @@ interface IEnvironmentVariantsCopyFromProps {
|
|||||||
environment: IFeatureEnvironment;
|
environment: IFeatureEnvironment;
|
||||||
permission: string;
|
permission: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
|
environmentId: string;
|
||||||
onCopyVariantsFrom: (
|
onCopyVariantsFrom: (
|
||||||
fromEnvironment: IFeatureEnvironment,
|
fromEnvironment: IFeatureEnvironment,
|
||||||
toEnvironment: IFeatureEnvironment
|
toEnvironment: IFeatureEnvironment
|
||||||
@ -25,6 +26,7 @@ export const EnvironmentVariantsCopyFrom = ({
|
|||||||
environment,
|
environment,
|
||||||
permission,
|
permission,
|
||||||
projectId,
|
projectId,
|
||||||
|
environmentId,
|
||||||
onCopyVariantsFrom,
|
onCopyVariantsFrom,
|
||||||
otherEnvsWithVariants,
|
otherEnvsWithVariants,
|
||||||
}: IEnvironmentVariantsCopyFromProps) => {
|
}: IEnvironmentVariantsCopyFromProps) => {
|
||||||
@ -48,6 +50,7 @@ export const EnvironmentVariantsCopyFrom = ({
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
permission={permission}
|
permission={permission}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
|
environmentId={environmentId}
|
||||||
>
|
>
|
||||||
Copy variants from
|
Copy variants from
|
||||||
</PermissionButton>
|
</PermissionButton>
|
||||||
|
@ -7,7 +7,7 @@ import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
|||||||
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
|
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
|
||||||
import { Search } from 'component/common/Search/Search';
|
import { Search } from 'component/common/Search/Search';
|
||||||
import { updateWeight } from 'component/common/util';
|
import { updateWeight } from 'component/common/util';
|
||||||
import { UPDATE_FEATURE_VARIANTS } from 'component/providers/AccessProvider/permissions';
|
import { UPDATE_FEATURE_ENVIRONMENT_VARIANTS } from 'component/providers/AccessProvider/permissions';
|
||||||
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
|
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
|
||||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||||
import { IFeatureEnvironment, IFeatureVariant } from 'interfaces/featureToggle';
|
import { IFeatureEnvironment, IFeatureVariant } from 'interfaces/featureToggle';
|
||||||
@ -232,6 +232,7 @@ export const FeatureEnvironmentVariants = () => {
|
|||||||
return (
|
return (
|
||||||
<EnvironmentVariantsCard
|
<EnvironmentVariantsCard
|
||||||
key={environment.name}
|
key={environment.name}
|
||||||
|
projectId={projectId}
|
||||||
environment={environment}
|
environment={environment}
|
||||||
searchValue={searchValue}
|
searchValue={searchValue}
|
||||||
onAddVariant={() => addVariant(environment)}
|
onAddVariant={() => addVariant(environment)}
|
||||||
@ -252,15 +253,21 @@ export const FeatureEnvironmentVariants = () => {
|
|||||||
<PermissionButton
|
<PermissionButton
|
||||||
onClick={() => addVariant(environment)}
|
onClick={() => addVariant(environment)}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
permission={UPDATE_FEATURE_VARIANTS}
|
permission={
|
||||||
|
UPDATE_FEATURE_ENVIRONMENT_VARIANTS
|
||||||
|
}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
|
environmentId={environment.name}
|
||||||
>
|
>
|
||||||
Add variant
|
Add variant
|
||||||
</PermissionButton>
|
</PermissionButton>
|
||||||
<EnvironmentVariantsCopyFrom
|
<EnvironmentVariantsCopyFrom
|
||||||
environment={environment}
|
environment={environment}
|
||||||
permission={UPDATE_FEATURE_VARIANTS}
|
permission={
|
||||||
|
UPDATE_FEATURE_ENVIRONMENT_VARIANTS
|
||||||
|
}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
|
environmentId={environment.name}
|
||||||
onCopyVariantsFrom={onCopyVariantsFrom}
|
onCopyVariantsFrom={onCopyVariantsFrom}
|
||||||
otherEnvsWithVariants={
|
otherEnvsWithVariants={
|
||||||
otherEnvsWithVariants
|
otherEnvsWithVariants
|
||||||
|
@ -27,6 +27,8 @@ export const UPDATE_FEATURE_STRATEGY = 'UPDATE_FEATURE_STRATEGY';
|
|||||||
export const DELETE_FEATURE_STRATEGY = 'DELETE_FEATURE_STRATEGY';
|
export const DELETE_FEATURE_STRATEGY = 'DELETE_FEATURE_STRATEGY';
|
||||||
export const UPDATE_FEATURE_ENVIRONMENT = 'UPDATE_FEATURE_ENVIRONMENT';
|
export const UPDATE_FEATURE_ENVIRONMENT = 'UPDATE_FEATURE_ENVIRONMENT';
|
||||||
export const UPDATE_FEATURE_VARIANTS = 'UPDATE_FEATURE_VARIANTS';
|
export const UPDATE_FEATURE_VARIANTS = 'UPDATE_FEATURE_VARIANTS';
|
||||||
|
export const UPDATE_FEATURE_ENVIRONMENT_VARIANTS =
|
||||||
|
'UPDATE_FEATURE_ENVIRONMENT_VARIANTS';
|
||||||
export const MOVE_FEATURE_TOGGLE = 'MOVE_FEATURE_TOGGLE';
|
export const MOVE_FEATURE_TOGGLE = 'MOVE_FEATURE_TOGGLE';
|
||||||
export const CREATE_SEGMENT = 'CREATE_SEGMENT';
|
export const CREATE_SEGMENT = 'CREATE_SEGMENT';
|
||||||
export const UPDATE_SEGMENT = 'UPDATE_SEGMENT';
|
export const UPDATE_SEGMENT = 'UPDATE_SEGMENT';
|
||||||
|
@ -5,7 +5,11 @@ import { IUnleashConfig } from '../../../types/option';
|
|||||||
import { IUnleashServices } from '../../../types';
|
import { IUnleashServices } from '../../../types';
|
||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import { Operation } from 'fast-json-patch';
|
import { Operation } from 'fast-json-patch';
|
||||||
import { NONE, UPDATE_FEATURE_VARIANTS } from '../../../types/permissions';
|
import {
|
||||||
|
NONE,
|
||||||
|
UPDATE_FEATURE_ENVIRONMENT_VARIANTS,
|
||||||
|
UPDATE_FEATURE_VARIANTS,
|
||||||
|
} from '../../../types/permissions';
|
||||||
import { IVariant } from '../../../types/model';
|
import { IVariant } from '../../../types/model';
|
||||||
import { extractUsername } from '../../../util/extract-user';
|
import { extractUsername } from '../../../util/extract-user';
|
||||||
import { IAuthRequest } from '../../unleash-types';
|
import { IAuthRequest } from '../../unleash-types';
|
||||||
@ -108,7 +112,7 @@ export default class VariantsController extends Controller {
|
|||||||
this.route({
|
this.route({
|
||||||
method: 'patch',
|
method: 'patch',
|
||||||
path: ENV_PREFIX,
|
path: ENV_PREFIX,
|
||||||
permission: UPDATE_FEATURE_VARIANTS,
|
permission: UPDATE_FEATURE_ENVIRONMENT_VARIANTS,
|
||||||
handler: this.patchVariantsOnEnv,
|
handler: this.patchVariantsOnEnv,
|
||||||
middleware: [
|
middleware: [
|
||||||
openApiService.validPath({
|
openApiService.validPath({
|
||||||
@ -124,7 +128,7 @@ export default class VariantsController extends Controller {
|
|||||||
this.route({
|
this.route({
|
||||||
method: 'put',
|
method: 'put',
|
||||||
path: ENV_PREFIX,
|
path: ENV_PREFIX,
|
||||||
permission: UPDATE_FEATURE_VARIANTS,
|
permission: UPDATE_FEATURE_ENVIRONMENT_VARIANTS,
|
||||||
handler: this.overwriteVariantsOnEnv,
|
handler: this.overwriteVariantsOnEnv,
|
||||||
middleware: [
|
middleware: [
|
||||||
openApiService.validPath({
|
openApiService.validPath({
|
||||||
|
@ -33,6 +33,8 @@ export const READ_API_TOKEN = 'READ_API_TOKEN';
|
|||||||
export const UPDATE_TAG_TYPE = 'UPDATE_TAG_TYPE';
|
export const UPDATE_TAG_TYPE = 'UPDATE_TAG_TYPE';
|
||||||
export const DELETE_TAG_TYPE = 'DELETE_TAG_TYPE';
|
export const DELETE_TAG_TYPE = 'DELETE_TAG_TYPE';
|
||||||
export const UPDATE_FEATURE_VARIANTS = 'UPDATE_FEATURE_VARIANTS';
|
export const UPDATE_FEATURE_VARIANTS = 'UPDATE_FEATURE_VARIANTS';
|
||||||
|
export const UPDATE_FEATURE_ENVIRONMENT_VARIANTS =
|
||||||
|
'UPDATE_FEATURE_ENVIRONMENT_VARIANTS';
|
||||||
export const MOVE_FEATURE_TOGGLE = 'MOVE_FEATURE_TOGGLE';
|
export const MOVE_FEATURE_TOGGLE = 'MOVE_FEATURE_TOGGLE';
|
||||||
export const CREATE_SEGMENT = 'CREATE_SEGMENT';
|
export const CREATE_SEGMENT = 'CREATE_SEGMENT';
|
||||||
export const UPDATE_SEGMENT = 'UPDATE_SEGMENT';
|
export const UPDATE_SEGMENT = 'UPDATE_SEGMENT';
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
exports.up = function (db, callback) {
|
||||||
|
db.runSql(
|
||||||
|
`
|
||||||
|
INSERT INTO permissions (permission, display_name, type)
|
||||||
|
values('UPDATE_FEATURE_ENVIRONMENT_VARIANTS', 'Update variants on environment', 'environment');
|
||||||
|
|
||||||
|
INSERT INTO role_permission (role_id, permission_id, environment)
|
||||||
|
(WITH perm_id as (SELECT id from permissions WHERE permission = 'UPDATE_FEATURE_ENVIRONMENT_VARIANTS')
|
||||||
|
SELECT rp.role_id, perm_id.id, rp.environment FROM perm_id, role_permission as rp
|
||||||
|
JOIN permissions p ON p.id = rp.permission_id
|
||||||
|
WHERE p.permission = 'UPDATE_FEATURE_ENVIRONMENT'
|
||||||
|
);
|
||||||
|
`,
|
||||||
|
callback,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = function (db, callback) {
|
||||||
|
db.runSql(
|
||||||
|
`
|
||||||
|
DELETE FROM role_permission WHERE permission_id =
|
||||||
|
(SELECT id FROM permissions WHERE permission = 'UPDATE_FEATURE_ENVIRONMENT_VARIANTS');
|
||||||
|
|
||||||
|
DELETE FROM permissions WHERE permission = 'UPDATE_FEATURE_ENVIRONMENT_VARIANTS';
|
||||||
|
`,
|
||||||
|
callback,
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user