Create React Permission Utilities

Created on 1 April 2025, 1 day ago

Overview

XB UI needs to be able to check permissions and alter the UI accordingly. We need some basic utilities that will allow this to be handled consistently throughout the app.

Proposed resolution

Communicate permissions

Provide a list of permissions to the FE within drupalSettings.xb.permissions or similar.

type Permissions = string[];
interface DrupalSettings {
  xb: {
     ...
     permissions: Permissions;
  }
}

Utility functions

Create utility functions to help manage and check permissions:

  • Check if a user has an individual permission
    const hasPermission = (permission: string, userPermissions: Permissions): boolean => {
      return userPermissions.includes(permission);
    };
    
  • Check if a user has multiple permissions
    const hasPermissions = (requiredPermissions: Permissions, userPermissions: Permissions): boolean => {
      return requiredPermissions.every(permission => userPermissions.includes(permission));
    };
    
  • Check if a user has one or more of a given list of permissions
    const hasAnyPermission = (requiredPermissions: Permissions, userPermissions: Permissions): boolean => {
      return requiredPermissions.some(permission => userPermissions.includes(permission));
    };
    

React Component

A reusable React component that can be used to conditionally render UI elements based on permissions:

import React, { ReactNode } from 'react';

interface PermissionCheckProps {
  hasPermission?: string;
  hasAnyPermission?: Permissions;
  hasPermissions?: Permissions;
  denied?: ReactNode;
  children: ReactNode;
  userPermissions: Permissions;
}

const PermissionCheck: React.FC<PermissionCheckProps> = ({
  hasPermission,
  hasAnyPermission,
  hasPermissions,
  denied = <div>You don’t have permission</div>,
  children,
  userPermissions
}) => {
  const isAllowed = 
    (hasPermission && hasPermission(userPermissions)) ||
    (hasAnyPermission && hasAnyPermission(hasAnyPermission, userPermissions)) ||
    (hasPermissions && hasPermissions(hasPermissions, userPermissions));

  return <>{isAllowed ? children : denied}</>;
};

export default PermissionCheck;

Example of how it would be used:

<PermissionCheck hasPermission="canAdd" denied={(<button disabled title="You do not have permission to add">Add</button>)}>
  <button>Add</button>
</PermissionCheck>

Important Note

Backend Enforcement: Always enforce permissions on the backend as frontend checks can be bypassed.

Out of scope

Real-time Updates: Real-time updates to permissions don't need to be supported; users must reload the page to get updated permissions.

User interface changes

Design Considerations:

We need to come up with a set of common rules/UX guidelines to cover the following and when they should be used

  • UI Element Visibility: Show or remove UI elements based on permissions.
  • UI Element State: Enable or disable UI (visuals for disabled states) elements based on permissions.
  • Custom UI: Display custom UI in place of the regular UI when a permission is missing.
  • Custom dialog: Display custom dialog when a user performs an action they don't have permission to do.
✨ Feature request
Status

Active

Version

0.0

Component

Page builder

Created by

πŸ‡¬πŸ‡§United Kingdom jessebaker

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024