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
AllowedButtonandAllowedIconButtonwill 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.