mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +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:
		
							parent
							
								
									c860d8e434
								
							
						
					
					
						commit
						5cc0e589e8
					
				@ -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 (
 | 
			
		||||
        <div>
 | 
			
		||||
            <PermissionGuard permissions={ADMIN}>
 | 
			
		||||
            <PermissionGuard permissions={[ADMIN, UPDATE_INSTANCE_BANNERS]}>
 | 
			
		||||
                <BannersTable />
 | 
			
		||||
            </PermissionGuard>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
@ -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 = () => (
 | 
			
		||||
    <div>
 | 
			
		||||
        <PermissionGuard permissions={ADMIN}>
 | 
			
		||||
        <PermissionGuard permissions={[ADMIN, UPDATE_MAINTENANCE_MODE]}>
 | 
			
		||||
            <MaintenancePage />
 | 
			
		||||
        </PermissionGuard>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -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 }) => (
 | 
			
		||||
                        <RolePermissionCategory
 | 
			
		||||
                            key={label}
 | 
			
		||||
                            title={`${label} permissions`}
 | 
			
		||||
                            title={label}
 | 
			
		||||
                            context={label.toLowerCase()}
 | 
			
		||||
                            Icon={
 | 
			
		||||
                                type === PROJECT_PERMISSION_TYPE ? (
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ import {
 | 
			
		||||
} from './useAuthEndpoint';
 | 
			
		||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
 | 
			
		||||
import type { IUiConfig } from 'interfaces/uiConfig';
 | 
			
		||||
import { MAINTENANCE_MODE_PERMISSIONS } from '@server/types/permissions';
 | 
			
		||||
 | 
			
		||||
interface IUseAuthPermissionsOutput {
 | 
			
		||||
    permissions?: IPermission[];
 | 
			
		||||
@ -22,8 +23,8 @@ const getPermissions = (
 | 
			
		||||
            ? auth.data.permissions
 | 
			
		||||
            : undefined;
 | 
			
		||||
    if (permissions && uiConfig?.maintenanceMode) {
 | 
			
		||||
        permissions = permissions.filter(
 | 
			
		||||
            (permission) => permission.permission === 'ADMIN',
 | 
			
		||||
        permissions = permissions.filter((permission) =>
 | 
			
		||||
            MAINTENANCE_MODE_PERMISSIONS.includes(permission.permission),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    return permissions;
 | 
			
		||||
 | 
			
		||||
@ -94,6 +94,7 @@ export type UiFlags = {
 | 
			
		||||
    showUserDeviceCount?: boolean;
 | 
			
		||||
    flagOverviewRedesign?: boolean;
 | 
			
		||||
    licensedUsers?: boolean;
 | 
			
		||||
    granularAdminPermissions?: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export interface IVersionInfo {
 | 
			
		||||
 | 
			
		||||
@ -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({
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@ -57,6 +57,7 @@ process.nextTick(async () => {
 | 
			
		||||
                        showUserDeviceCount: true,
 | 
			
		||||
                        flagOverviewRedesign: false,
 | 
			
		||||
                        licensedUsers: true,
 | 
			
		||||
                        granularAdminPermissions: true,
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                authentication: {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user