diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanelDetails/DependencyRow.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanelDetails/DependencyRow.tsx index a147edae88cf..6a4e68815555 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanelDetails/DependencyRow.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanelDetails/DependencyRow.tsx @@ -1,6 +1,4 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import { Button } from '@mui/material'; -import { Add } from '@mui/icons-material'; import { AddDependencyDialogue } from 'component/feature/Dependencies/AddDependencyDialogue'; import { IFeatureToggle } from 'interfaces/featureToggle'; import { FC, useState } from 'react'; @@ -9,6 +7,9 @@ import { DependencyActions } from './DependencyActions'; import { useDependentFeaturesApi } from 'hooks/api/actions/useDependentFeaturesApi/useDependentFeaturesApi'; import { useFeature } from 'hooks/api/getters/useFeature/useFeature'; import { ChildrenTooltip } from './ChildrenTooltip'; +import PermissionButton from 'component/common/PermissionButton/PermissionButton'; +import { UPDATE_FEATURE_DEPENDENCY } from 'component/providers/AccessProvider/permissions'; +import { useCheckProjectPermissions } from 'hooks/useHasAccess'; export const DependencyRow: FC<{ feature: IFeatureToggle }> = ({ feature }) => { const { removeDependencies } = useDependentFeaturesApi(feature.project); @@ -21,6 +22,7 @@ export const DependencyRow: FC<{ feature: IFeatureToggle }> = ({ feature }) => { const hasParentDependency = Boolean(feature.project) && Boolean(feature.dependencies.length > 0); const hasChildren = Boolean(feature.project) && feature.children.length > 0; + const checkAccess = useCheckProjectPermissions(feature.project); return ( <> @@ -30,14 +32,16 @@ export const DependencyRow: FC<{ feature: IFeatureToggle }> = ({ feature }) => { Dependency: - + } @@ -54,13 +58,20 @@ export const DependencyRow: FC<{ feature: IFeatureToggle }> = ({ feature }) => { {feature.dependencies[0]?.feature} - setShowDependencyDialogue(true)} - onDelete={async () => { - await removeDependencies(feature.name); - await refetchFeature(); - }} + + setShowDependencyDialogue(true) + } + onDelete={async () => { + await removeDependencies(feature.name); + await refetchFeature(); + }} + /> + } /> } diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanelDetails/FeatureOverviewSidePanelDetails.test.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanelDetails/FeatureOverviewSidePanelDetails.test.tsx index 2cde87ee7a39..de6cfe839c7d 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanelDetails/FeatureOverviewSidePanelDetails.test.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanelDetails/FeatureOverviewSidePanelDetails.test.tsx @@ -38,6 +38,11 @@ test('show dependency dialogue', async () => { } header={''} />, + { + permissions: [ + { permission: 'UPDATE_FEATURE_DEPENDENCY', project: 'default' }, + ], + }, ); const addParentButton = await screen.findByText('Add parent feature'); @@ -100,6 +105,11 @@ test('delete dependency', async () => { } header={''} />, + { + permissions: [ + { permission: 'UPDATE_FEATURE_DEPENDENCY', project: 'default' }, + ], + }, ); await screen.findByText('Dependency:'); @@ -127,6 +137,11 @@ test('edit dependency', async () => { } header={''} />, + { + permissions: [ + { permission: 'UPDATE_FEATURE_DEPENDENCY', project: 'default' }, + ], + }, ); await screen.findByText('Dependency:'); diff --git a/frontend/src/component/providers/AccessProvider/permissions.ts b/frontend/src/component/providers/AccessProvider/permissions.ts index 8a731a64c931..9e64bb71c92e 100644 --- a/frontend/src/component/providers/AccessProvider/permissions.ts +++ b/frontend/src/component/providers/AccessProvider/permissions.ts @@ -1,6 +1,7 @@ export const ADMIN = 'ADMIN'; export const CREATE_FEATURE = 'CREATE_FEATURE'; export const UPDATE_FEATURE = 'UPDATE_FEATURE'; +export const UPDATE_FEATURE_DEPENDENCY = 'UPDATE_FEATURE_DEPENDENCY'; export const DELETE_FEATURE = 'DELETE_FEATURE'; export const CREATE_STRATEGY = 'CREATE_STRATEGY'; export const UPDATE_STRATEGY = 'UPDATE_STRATEGY'; diff --git a/src/lib/features/dependent-features/dependent-features-controller.ts b/src/lib/features/dependent-features/dependent-features-controller.ts index ccd6df2fb9d9..b6439f66db12 100644 --- a/src/lib/features/dependent-features/dependent-features-controller.ts +++ b/src/lib/features/dependent-features/dependent-features-controller.ts @@ -6,7 +6,7 @@ import { IUnleashConfig, IUnleashServices, NONE, - UPDATE_FEATURE, + UPDATE_FEATURE_DEPENDENCY, } from '../../types'; import { Logger } from '../../logger'; import { @@ -88,7 +88,7 @@ export default class DependentFeaturesController extends Controller { method: 'post', path: PATH_DEPENDENCIES, handler: this.addFeatureDependency, - permission: UPDATE_FEATURE, + permission: UPDATE_FEATURE_DEPENDENCY, middleware: [ openApiService.validPath({ tags: ['Features'], @@ -111,7 +111,7 @@ export default class DependentFeaturesController extends Controller { method: 'delete', path: PATH_DEPENDENCY, handler: this.deleteFeatureDependency, - permission: UPDATE_FEATURE, + permission: UPDATE_FEATURE_DEPENDENCY, acceptAnyContentType: true, middleware: [ openApiService.validPath({ @@ -131,7 +131,7 @@ export default class DependentFeaturesController extends Controller { method: 'delete', path: PATH_DEPENDENCIES, handler: this.deleteFeatureDependencies, - permission: UPDATE_FEATURE, + permission: UPDATE_FEATURE_DEPENDENCY, acceptAnyContentType: true, middleware: [ openApiService.validPath({ diff --git a/src/lib/types/permissions.ts b/src/lib/types/permissions.ts index a9922315813f..146f45a7b295 100644 --- a/src/lib/types/permissions.ts +++ b/src/lib/types/permissions.ts @@ -43,6 +43,7 @@ export const DELETE_TAG_TYPE = 'DELETE_TAG_TYPE'; // Project export const CREATE_FEATURE = 'CREATE_FEATURE'; export const UPDATE_FEATURE = 'UPDATE_FEATURE'; +export const UPDATE_FEATURE_DEPENDENCY = 'UPDATE_FEATURE_DEPENDENCY'; export const DELETE_FEATURE = 'DELETE_FEATURE'; export const UPDATE_PROJECT = 'UPDATE_PROJECT'; export const DELETE_PROJECT = 'DELETE_PROJECT'; diff --git a/src/migrations/20231002122426-update-dependency-permission.js b/src/migrations/20231002122426-update-dependency-permission.js new file mode 100644 index 000000000000..84f8c49b7f6d --- /dev/null +++ b/src/migrations/20231002122426-update-dependency-permission.js @@ -0,0 +1,19 @@ +exports.up = function (db, cb) { + db.runSql( + ` + INSERT INTO permissions (permission, display_name, type) VALUES ('UPDATE_FEATURE_DEPENDENCY', 'Update feature dependency', 'project'); + SELECT assign_unleash_permission_to_role('UPDATE_FEATURE_DEPENDENCY', 'Member'); + SELECT assign_unleash_permission_to_role('UPDATE_FEATURE_DEPENDENCY', 'Owner'); + `, + cb + ); +}; + +exports.down = function (db, cb) { + db.runSql( + ` + DELETE FROM permissions WHERE permission = 'UPDATE_FEATURE_DEPENDENCY'; + `, + cb + ); +};