Implement custom roles and improve permissions logic

The commit refactors the handling of account roles and enhances permissions checks. The account role has been shifted to use a string type, providing the ability to define custom roles. It also introduces the RolesDataProvider component, which stipulates role-related data for different forms and tables. The modification goes further to consider user role hierarchy in permissions checks, offering a more granular access control.
This commit is contained in:
giancarlo
2024-03-29 14:48:45 +08:00
parent f1967a686c
commit 99db8f4ca4
41 changed files with 498 additions and 228 deletions

View File

@@ -35,6 +35,7 @@ type AccountInvitationsTableProps = {
permissions: {
canUpdateInvitation: boolean;
canRemoveInvitation: boolean;
currentUserRoleHierarchy: number;
};
};
@@ -72,6 +73,7 @@ export function AccountInvitationsTable({
function useGetColumns(permissions: {
canUpdateInvitation: boolean;
canRemoveInvitation: boolean;
currentUserRoleHierarchy: number;
}): ColumnDef<Invitations[0]>[] {
const { t } = useTranslation('teams');
@@ -197,6 +199,7 @@ function ActionsDropdown({
setIsOpen={setIsUpdatingRole}
invitationId={invitation.id}
userRole={invitation.role}
userRoleHierarchy={permissions.currentUserRoleHierarchy}
/>
</If>

View File

@@ -4,7 +4,6 @@ import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { Database } from '@kit/supabase/database';
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
import { Button } from '@kit/ui/button';
import {
@@ -29,15 +28,17 @@ import { Trans } from '@kit/ui/trans';
import { UpdateRoleSchema } from '../../schema/update-role-schema';
import { updateInvitationAction } from '../../server/actions/team-invitations-server-actions';
import { MembershipRoleSelector } from '../members/membership-role-selector';
import { RolesDataProvider } from '../members/roles-data-provider';
type Role = Database['public']['Enums']['account_role'];
type Role = string;
export const UpdateInvitationDialog: React.FC<{
isOpen: boolean;
setIsOpen: (isOpen: boolean) => void;
invitationId: number;
userRole: Role;
}> = ({ isOpen, setIsOpen, invitationId, userRole }) => {
userRoleHierarchy: number;
}> = ({ isOpen, setIsOpen, invitationId, userRole, userRoleHierarchy }) => {
return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogContent>
@@ -51,11 +52,16 @@ export const UpdateInvitationDialog: React.FC<{
</DialogDescription>
</DialogHeader>
<UpdateInvitationForm
setIsOpen={setIsOpen}
invitationId={invitationId}
userRole={userRole}
/>
<RolesDataProvider maxRoleHierarchy={userRoleHierarchy}>
{(roles) => (
<UpdateInvitationForm
invitationId={invitationId}
userRole={userRole}
userRoleHierarchy={roles.length}
setIsOpen={setIsOpen}
/>
)}
</RolesDataProvider>
</DialogContent>
</Dialog>
);
@@ -64,10 +70,12 @@ export const UpdateInvitationDialog: React.FC<{
function UpdateInvitationForm({
invitationId,
userRole,
userRoleHierarchy,
setIsOpen,
}: React.PropsWithChildren<{
invitationId: number;
userRole: Role;
userRoleHierarchy: number;
setIsOpen: (isOpen: boolean) => void;
}>) {
const { t } = useTranslation('teams');
@@ -128,11 +136,18 @@ function UpdateInvitationForm({
</FormLabel>
<FormControl>
<MembershipRoleSelector
currentUserRole={userRole}
value={field.value}
onChange={(newRole) => form.setValue('role', newRole)}
/>
<RolesDataProvider maxRoleHierarchy={userRoleHierarchy}>
{(roles) => (
<MembershipRoleSelector
roles={roles}
currentUserRole={userRole}
value={field.value}
onChange={(newRole) =>
form.setValue(field.name, newRole)
}
/>
)}
</RolesDataProvider>
</FormControl>
<FormDescription>