1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-03-18 00:19:49 +01:00

feat(cjux-278): maintenance root roles (#8875)

Custom root roles for changing maintenance mode state and banners.

Internal ticket: CJUX-278
This commit is contained in:
Tymoteusz Czech 2024-12-10 15:22:46 +01:00 committed by GitHub
parent c860d8e434
commit 5cc0e589e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 48 additions and 9 deletions

View File

@ -3,6 +3,7 @@ import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuar
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature'; import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature';
import { BannersTable } from './BannersTable/BannersTable'; import { BannersTable } from './BannersTable/BannersTable';
import { UPDATE_INSTANCE_BANNERS } from '@server/types/permissions';
export const Banners = () => { export const Banners = () => {
const { isEnterprise } = useUiConfig(); const { isEnterprise } = useUiConfig();
@ -13,7 +14,7 @@ export const Banners = () => {
return ( return (
<div> <div>
<PermissionGuard permissions={ADMIN}> <PermissionGuard permissions={[ADMIN, UPDATE_INSTANCE_BANNERS]}>
<BannersTable /> <BannersTable />
</PermissionGuard> </PermissionGuard>
</div> </div>

View File

@ -6,10 +6,11 @@ import { Box, styled } from '@mui/material';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { MaintenanceTooltip } from './MaintenanceTooltip'; import { MaintenanceTooltip } from './MaintenanceTooltip';
import { MaintenanceToggle } from './MaintenanceToggle'; import { MaintenanceToggle } from './MaintenanceToggle';
import { UPDATE_MAINTENANCE_MODE } from '@server/types/permissions';
export const MaintenanceAdmin = () => ( export const MaintenanceAdmin = () => (
<div> <div>
<PermissionGuard permissions={ADMIN}> <PermissionGuard permissions={[ADMIN, UPDATE_MAINTENANCE_MODE]}>
<MaintenancePage /> <MaintenancePage />
</PermissionGuard> </PermissionGuard>
</div> </div>

View File

@ -42,6 +42,9 @@ export const RolePermissionCategories = ({
}); });
const releasePlansEnabled = useUiFlag('releasePlans'); const releasePlansEnabled = useUiFlag('releasePlans');
const granularAdminPermissionsEnabled = useUiFlag(
'granularAdminPermissions',
);
const isProjectRole = PROJECT_ROLE_TYPES.includes(type); const isProjectRole = PROJECT_ROLE_TYPES.includes(type);
@ -85,10 +88,15 @@ export const RolePermissionCategories = ({
releasePlansEnabled || releasePlansEnabled ||
label !== 'Release plan templates', label !== 'Release plan templates',
) )
.filter(
({ label }) =>
granularAdminPermissionsEnabled ||
label !== 'Instance maintenance',
)
.map(({ label, type, permissions }) => ( .map(({ label, type, permissions }) => (
<RolePermissionCategory <RolePermissionCategory
key={label} key={label}
title={`${label} permissions`} title={label}
context={label.toLowerCase()} context={label.toLowerCase()}
Icon={ Icon={
type === PROJECT_PERMISSION_TYPE ? ( type === PROJECT_PERMISSION_TYPE ? (

View File

@ -5,6 +5,7 @@ import {
} from './useAuthEndpoint'; } from './useAuthEndpoint';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import type { IUiConfig } from 'interfaces/uiConfig'; import type { IUiConfig } from 'interfaces/uiConfig';
import { MAINTENANCE_MODE_PERMISSIONS } from '@server/types/permissions';
interface IUseAuthPermissionsOutput { interface IUseAuthPermissionsOutput {
permissions?: IPermission[]; permissions?: IPermission[];
@ -22,8 +23,8 @@ const getPermissions = (
? auth.data.permissions ? auth.data.permissions
: undefined; : undefined;
if (permissions && uiConfig?.maintenanceMode) { if (permissions && uiConfig?.maintenanceMode) {
permissions = permissions.filter( permissions = permissions.filter((permission) =>
(permission) => permission.permission === 'ADMIN', MAINTENANCE_MODE_PERMISSIONS.includes(permission.permission),
); );
} }
return permissions; return permissions;

View File

@ -94,6 +94,7 @@ export type UiFlags = {
showUserDeviceCount?: boolean; showUserDeviceCount?: boolean;
flagOverviewRedesign?: boolean; flagOverviewRedesign?: boolean;
licensedUsers?: boolean; licensedUsers?: boolean;
granularAdminPermissions?: boolean;
}; };
export interface IVersionInfo { export interface IVersionInfo {

View File

@ -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 type { Request, Response } from 'express';
import Controller from '../../routes/controller'; import Controller from '../../routes/controller';
import type { Logger } from '../../logger'; import type { Logger } from '../../logger';
@ -38,7 +43,7 @@ export default class MaintenanceController extends Controller {
this.route({ this.route({
method: 'post', method: 'post',
path: '', path: '',
permission: ADMIN, permission: [ADMIN, UPDATE_MAINTENANCE_MODE],
handler: this.toggleMaintenance, handler: this.toggleMaintenance,
middleware: [ middleware: [
this.openApiService.validPath({ this.openApiService.validPath({
@ -58,7 +63,7 @@ export default class MaintenanceController extends Controller {
this.route({ this.route({
method: 'get', method: 'get',
path: '', path: '',
permission: ADMIN, permission: [ADMIN, UPDATE_MAINTENANCE_MODE],
handler: this.getMaintenance, handler: this.getMaintenance,
middleware: [ middleware: [
this.openApiService.validPath({ this.openApiService.validPath({

View File

@ -60,6 +60,7 @@ export type IFlagKey =
| 'deleteStaleUserSessions' | 'deleteStaleUserSessions'
| 'memorizeStats' | 'memorizeStats'
| 'licensedUsers' | 'licensedUsers'
| 'granularAdminPermissions'
| 'streaming' | 'streaming'
| 'etagVariant' | 'etagVariant'
| 'oidcRedirect'; | 'oidcRedirect';
@ -282,6 +283,10 @@ const flags: IFlags = {
process.env.UNLEASH_EXPERIMENTAL_FLAG_LICENSED_USERS, process.env.UNLEASH_EXPERIMENTAL_FLAG_LICENSED_USERS,
false, false,
), ),
granularAdminPermissions: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_GRANULAR_ADMIN_PERMISSIONS,
false,
),
streaming: parseEnvVarBoolean( streaming: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_STREAMING, process.env.UNLEASH_EXPERIMENTAL_STREAMING,
false, false,

View File

@ -41,6 +41,9 @@ export const CREATE_TAG_TYPE = 'CREATE_TAG_TYPE';
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_MAINTENANCE_MODE = 'UPDATE_MAINTENANCE_MODE';
export const UPDATE_INSTANCE_BANNERS = 'UPDATE_INSTANCE_BANNERS';
// Project // Project
export const CREATE_FEATURE = 'CREATE_FEATURE'; export const CREATE_FEATURE = 'CREATE_FEATURE';
export const UPDATE_FEATURE = 'UPDATE_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 = [ export const ROOT_PERMISSION_CATEGORIES = [
{ {
label: 'Addon', label: 'Integration',
permissions: [CREATE_ADDON, UPDATE_ADDON, DELETE_ADDON], permissions: [CREATE_ADDON, UPDATE_ADDON, DELETE_ADDON],
}, },
{ {
@ -141,4 +144,17 @@ export const ROOT_PERMISSION_CATEGORIES = [
RELEASE_PLAN_TEMPLATE_UPDATE, 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,
]; ];

View File

@ -57,6 +57,7 @@ process.nextTick(async () => {
showUserDeviceCount: true, showUserDeviceCount: true,
flagOverviewRedesign: false, flagOverviewRedesign: false,
licensedUsers: true, licensedUsers: true,
granularAdminPermissions: true,
}, },
}, },
authentication: { authentication: {