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:
- }
+ {
setShowDependencyDialogue(true);
}}
>
Add parent feature
-
+
}
@@ -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
+ );
+};