diff --git a/frontend/src/component/admin/banners/Banners.tsx b/frontend/src/component/admin/banners/Banners.tsx index 9e4a2070a8df..db86315e1495 100644 --- a/frontend/src/component/admin/banners/Banners.tsx +++ b/frontend/src/component/admin/banners/Banners.tsx @@ -3,6 +3,7 @@ import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuar import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature'; import { BannersTable } from './BannersTable/BannersTable'; +import { UPDATE_INSTANCE_BANNERS } from '@server/types/permissions'; export const Banners = () => { const { isEnterprise } = useUiConfig(); @@ -13,7 +14,7 @@ export const Banners = () => { return (
- +
diff --git a/frontend/src/component/admin/maintenance/index.tsx b/frontend/src/component/admin/maintenance/index.tsx index 505dd10e4963..9774adbc312e 100644 --- a/frontend/src/component/admin/maintenance/index.tsx +++ b/frontend/src/component/admin/maintenance/index.tsx @@ -6,10 +6,11 @@ import { Box, styled } from '@mui/material'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { MaintenanceTooltip } from './MaintenanceTooltip'; import { MaintenanceToggle } from './MaintenanceToggle'; +import { UPDATE_MAINTENANCE_MODE } from '@server/types/permissions'; export const MaintenanceAdmin = () => (
- +
diff --git a/frontend/src/component/admin/roles/RoleForm/RolePermissionCategories/RolePermissionCategories.tsx b/frontend/src/component/admin/roles/RoleForm/RolePermissionCategories/RolePermissionCategories.tsx index 0fbe05ea7967..d8097bc22a25 100644 --- a/frontend/src/component/admin/roles/RoleForm/RolePermissionCategories/RolePermissionCategories.tsx +++ b/frontend/src/component/admin/roles/RoleForm/RolePermissionCategories/RolePermissionCategories.tsx @@ -42,6 +42,9 @@ export const RolePermissionCategories = ({ }); const releasePlansEnabled = useUiFlag('releasePlans'); + const granularAdminPermissionsEnabled = useUiFlag( + 'granularAdminPermissions', + ); const isProjectRole = PROJECT_ROLE_TYPES.includes(type); @@ -85,10 +88,15 @@ export const RolePermissionCategories = ({ releasePlansEnabled || label !== 'Release plan templates', ) + .filter( + ({ label }) => + granularAdminPermissionsEnabled || + label !== 'Instance maintenance', + ) .map(({ label, type, permissions }) => ( permission.permission === 'ADMIN', + permissions = permissions.filter((permission) => + MAINTENANCE_MODE_PERMISSIONS.includes(permission.permission), ); } return permissions; diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index 19263be2b3e2..b135df6b0219 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -94,6 +94,7 @@ export type UiFlags = { showUserDeviceCount?: boolean; flagOverviewRedesign?: boolean; licensedUsers?: boolean; + granularAdminPermissions?: boolean; }; export interface IVersionInfo { diff --git a/src/lib/features/maintenance/maintenance-controller.ts b/src/lib/features/maintenance/maintenance-controller.ts index bba95b8d5921..71df5702ed0c 100644 --- a/src/lib/features/maintenance/maintenance-controller.ts +++ b/src/lib/features/maintenance/maintenance-controller.ts @@ -1,4 +1,9 @@ -import { ADMIN, type IUnleashConfig, type IUnleashServices } from '../../types'; +import { + ADMIN, + UPDATE_MAINTENANCE_MODE, + type IUnleashConfig, + type IUnleashServices, +} from '../../types'; import type { Request, Response } from 'express'; import Controller from '../../routes/controller'; import type { Logger } from '../../logger'; @@ -38,7 +43,7 @@ export default class MaintenanceController extends Controller { this.route({ method: 'post', path: '', - permission: ADMIN, + permission: [ADMIN, UPDATE_MAINTENANCE_MODE], handler: this.toggleMaintenance, middleware: [ this.openApiService.validPath({ @@ -58,7 +63,7 @@ export default class MaintenanceController extends Controller { this.route({ method: 'get', path: '', - permission: ADMIN, + permission: [ADMIN, UPDATE_MAINTENANCE_MODE], handler: this.getMaintenance, middleware: [ this.openApiService.validPath({ diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index 493d439efa99..3896f6e21074 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -60,6 +60,7 @@ export type IFlagKey = | 'deleteStaleUserSessions' | 'memorizeStats' | 'licensedUsers' + | 'granularAdminPermissions' | 'streaming' | 'etagVariant' | 'oidcRedirect'; @@ -282,6 +283,10 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_FLAG_LICENSED_USERS, false, ), + granularAdminPermissions: parseEnvVarBoolean( + process.env.UNLEASH_EXPERIMENTAL_GRANULAR_ADMIN_PERMISSIONS, + false, + ), streaming: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_STREAMING, false, diff --git a/src/lib/types/permissions.ts b/src/lib/types/permissions.ts index 245526ca2b3e..2ce1d977a011 100644 --- a/src/lib/types/permissions.ts +++ b/src/lib/types/permissions.ts @@ -41,6 +41,9 @@ export const CREATE_TAG_TYPE = 'CREATE_TAG_TYPE'; export const UPDATE_TAG_TYPE = 'UPDATE_TAG_TYPE'; export const DELETE_TAG_TYPE = 'DELETE_TAG_TYPE'; +export const UPDATE_MAINTENANCE_MODE = 'UPDATE_MAINTENANCE_MODE'; +export const UPDATE_INSTANCE_BANNERS = 'UPDATE_INSTANCE_BANNERS'; + // Project export const CREATE_FEATURE = 'CREATE_FEATURE'; export const UPDATE_FEATURE = 'UPDATE_FEATURE'; @@ -83,7 +86,7 @@ export const RELEASE_PLAN_TEMPLATE_DELETE = 'RELEASE_PLAN_TEMPLATE_DELETE'; export const ROOT_PERMISSION_CATEGORIES = [ { - label: 'Addon', + label: 'Integration', permissions: [CREATE_ADDON, UPDATE_ADDON, DELETE_ADDON], }, { @@ -141,4 +144,17 @@ export const ROOT_PERMISSION_CATEGORIES = [ RELEASE_PLAN_TEMPLATE_UPDATE, ], }, + { + label: 'Instance maintenance', + permissions: [UPDATE_MAINTENANCE_MODE, UPDATE_INSTANCE_BANNERS], + }, +]; + +// Used on Frontend, to allow admin panel use for users with custom root roles +export const MAINTENANCE_MODE_PERMISSIONS = [ + ADMIN, + READ_ROLE, + READ_CLIENT_API_TOKEN, + READ_FRONTEND_API_TOKEN, + UPDATE_MAINTENANCE_MODE, ]; diff --git a/src/server-dev.ts b/src/server-dev.ts index 1b0d7b0eb7e5..d4b7e36deb20 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -57,6 +57,7 @@ process.nextTick(async () => { showUserDeviceCount: true, flagOverviewRedesign: false, licensedUsers: true, + granularAdminPermissions: true, }, }, authentication: {