Skip to content

Access Control Components

This section describes how to use the access control components provided by our shared library to manage permissions within the HortiView application. These components and hooks help ensure that only authorized users can view or interact with sensitive features.

For more information refer to the ReadMe or StoryBook of the Shared components and Default components.

Integration Steps

1. Application Setup: Permission Provider

To enable permission checks throughout our application, wrap the main app component (e.g. RemoteModule.tsx) with the <SharedComponentsPermissionProvider />. This provider supplies permission context to all child components.

Example:

import { SharedComponentsPermissionProvider } from '@hortiview/shared-components';

function App() {
  // Retrieve user permissions and active organization from your state management (e.g., Zustand)
  const userPermissions = useClaimsIdentityStore(state => state.userPermissions);
  const activeOrganizationId = useActiveOrganizationStore(state => state.activeOrganization?.id);

  return (
    <SharedComponentsPermissionProvider
      userPermissions={userPermissions}
      activeOrganizationId={activeOrganizationId}
    >
      <YourAppComponents />
    </SharedComponentsPermissionProvider>
  );
}

2. Permission Checks in the UI

Once the provider is set up, you can use the following components and hooks to enforce access control:

2.1 <Allowed /> Component

Use the <Allowed /> component to conditionally render child components based on user permissions. No additional props are needed except the required permissions and entity ID.

Example:

import { Allowed } from '@hortiview/shared-components';

function MyComponent() {
  return (
    <Allowed neededPermissions={["organization-read", "organization-edit"]} entityId={organizationId}>
      <OrganizationSettings />
    </Allowed>
  );
}

2.2 useIsAllowed Hook

The useIsAllowed hook returns a boolean indicating whether the user has the specified permissions for a given entity. Use this to control rendering or logic in your components.

Example:

import { useIsAllowed } from '@hortiview/shared-components';

function MyComponent() {
  const isAllowed = useIsAllowed();
  const canEditMembers = isAllowed(['member-edit', 'member-create'], orgId);
  return <MembersList isDisabled={!canEditMembers} />;
}

2.3 AllowedButton and AllowedIconButton

These components are specialized buttons that only render if the user has the required permissions. They use the useIsAllowed hook internally and automatically hide themselves if the user is not authorized.

AllowedButton Example:

import { AllowedButton } from '@hortiview/shared-components';

function FarmActions({ farmId }) {
  return (
    <div>
      <AllowedButton
        data-testid='edit-season-button'
        label='Edit Season'
        permissions={['season-edit']}
        entityId={organizationId}
        buttonVariant='filled'
        onClick={() => handleEditSeason(seasonId)}
      />
      <AllowedButton
        data-testid='delete-season-button'
        label='Delete Season'
        permissions={['season-delete']}
        entityId={organizationId}
        buttonVariant='danger'
        onClick={() => handleDeleteSeason(seasonId)}
      />
    </div>
  );
}

AllowedIconButton Example:

import { AllowedIconButton } from '@hortiview/shared-components';

function BlockActions({ blockId, farmId }) {
  return (
    <div>
      <AllowedIconButton
        data-testid='edit-block-icon'
        icon='edit'
        permissions={['block-edit', 'block-create']}
        entityId={farmId}
        iconButtonVariant='filled-primary'
        onClick={() => handleEditBlock(blockId)}
      />
      <AllowedIconButton
        data-testid='delete-block-icon'
        icon='delete'
        permissions={['block-delete']}
        entityId={farmId}
        iconButtonVariant='filled-danger'
        onClick={() => handleDeleteBlock(blockId)}
      />
    </div>
  );
}

Note: Both AllowedButton and AllowedIconButton will not render if the user lacks the required permissions, ensuring that unauthorized actions are never visible or accessible in the UI.

2.4 Other components

Other component such as the <ContextMenu /> or the <BaseView /> accept isAllowed values as well. That property can be used to conditionally add or remove items from the rendered lists depending on the current user“s permissions.