|
| 1 | +import { makeStyles } from "@mui/styles"; |
| 2 | +import { type User, type Role } from "api/typesGenerated"; |
| 3 | +import { combineClasses } from "utils/combineClasses"; |
| 4 | + |
| 5 | +import { EditRolesButton } from "./EditRolesButton"; |
| 6 | +import { Pill } from "components/Pill/Pill"; |
| 7 | +import TableCell from "@mui/material/TableCell"; |
| 8 | +import Stack from "@mui/material/Stack"; |
| 9 | + |
| 10 | +const useStyles = makeStyles((theme) => ({ |
| 11 | + rolePill: { |
| 12 | + backgroundColor: theme.palette.background.paperLight, |
| 13 | + borderColor: theme.palette.divider, |
| 14 | + }, |
| 15 | + rolePillOwner: { |
| 16 | + backgroundColor: theme.palette.info.dark, |
| 17 | + borderColor: theme.palette.info.light, |
| 18 | + }, |
| 19 | +})); |
| 20 | + |
| 21 | +const roleOrder = ["owner", "user-admin", "template-admin", "auditor"]; |
| 22 | + |
| 23 | +const sortRoles = (roles: readonly Role[]) => { |
| 24 | + return [...roles].sort( |
| 25 | + (a, b) => roleOrder.indexOf(a.name) - roleOrder.indexOf(b.name), |
| 26 | + ); |
| 27 | +}; |
| 28 | + |
| 29 | +type Props = { |
| 30 | + canEditUsers: boolean; |
| 31 | + roles: undefined | readonly Role[]; |
| 32 | + user: User; |
| 33 | + isLoading: boolean; |
| 34 | + oidcRoleSyncEnabled: boolean; |
| 35 | + onUserRolesUpdate: (user: User, newRoleNames: string[]) => void; |
| 36 | +}; |
| 37 | + |
| 38 | +// When the user has no role we want to show they are a Member |
| 39 | +const fallbackRole: Role = { |
| 40 | + name: "member", |
| 41 | + display_name: "Member", |
| 42 | +} as const; |
| 43 | + |
| 44 | +export function UserRoleCell({ |
| 45 | + canEditUsers, |
| 46 | + roles, |
| 47 | + user, |
| 48 | + isLoading, |
| 49 | + oidcRoleSyncEnabled, |
| 50 | + onUserRolesUpdate, |
| 51 | +}: Props) { |
| 52 | + const styles = useStyles(); |
| 53 | + |
| 54 | + const userRoles = |
| 55 | + user.roles.length === 0 ? [fallbackRole] : sortRoles(user.roles); |
| 56 | + |
| 57 | + return ( |
| 58 | + <TableCell> |
| 59 | + <Stack direction="row" spacing={1}> |
| 60 | + {canEditUsers && ( |
| 61 | + <EditRolesButton |
| 62 | + roles={roles ? sortRoles(roles) : []} |
| 63 | + selectedRoles={userRoles} |
| 64 | + isLoading={isLoading} |
| 65 | + userLoginType={user.login_type} |
| 66 | + oidcRoleSync={oidcRoleSyncEnabled} |
| 67 | + onChange={(roles) => { |
| 68 | + // Remove the fallback role because it is only for the UI |
| 69 | + const rolesWithoutFallback = roles.filter( |
| 70 | + (role) => role !== fallbackRole.name, |
| 71 | + ); |
| 72 | + onUserRolesUpdate(user, rolesWithoutFallback); |
| 73 | + }} |
| 74 | + /> |
| 75 | + )} |
| 76 | + |
| 77 | + {userRoles.map((role) => ( |
| 78 | + <Pill |
| 79 | + key={role.name} |
| 80 | + text={role.display_name} |
| 81 | + className={combineClasses({ |
| 82 | + [styles.rolePill]: true, |
| 83 | + [styles.rolePillOwner]: role.name === "owner", |
| 84 | + })} |
| 85 | + /> |
| 86 | + ))} |
| 87 | + </Stack> |
| 88 | + </TableCell> |
| 89 | + ); |
| 90 | +} |
0 commit comments