Skip to content

Commit cb51aa8

Browse files
committed
refactor: extract UserRoleCell into separate component
1 parent 2029543 commit cb51aa8

File tree

4 files changed

+189
-140
lines changed

4 files changed

+189
-140
lines changed

site/src/pages/UsersPage/UsersPageView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ export interface UsersPageViewProps {
1212
users?: TypesGen.User[];
1313
roles?: TypesGen.AssignableRoles[];
1414
isUpdatingUserRoles?: boolean;
15-
canEditUsers?: boolean;
15+
canEditUsers: boolean;
1616
oidcRoleSyncEnabled: boolean;
1717
canViewActivity?: boolean;
18-
isLoading?: boolean;
18+
isLoading: boolean;
1919
authMethods?: TypesGen.AuthMethods;
2020
onSuspendUser: (user: TypesGen.User) => void;
2121
onDeleteUser: (user: TypesGen.User) => void;
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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+
}

site/src/pages/UsersPage/UsersTable/UsersTable.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ export const Language = {
1616
statusLabel: "Status",
1717
lastSeenLabel: "Last Seen",
1818
loginTypeLabel: "Login Type",
19-
};
19+
} as const;
2020

2121
export interface UsersTableProps {
2222
users?: TypesGen.User[];
2323
roles?: TypesGen.AssignableRoles[];
2424
isUpdatingUserRoles?: boolean;
25-
canEditUsers?: boolean;
25+
canEditUsers: boolean;
2626
canViewActivity?: boolean;
27-
isLoading?: boolean;
27+
isLoading: boolean;
2828
onSuspendUser: (user: TypesGen.User) => void;
2929
onActivateUser: (user: TypesGen.User) => void;
3030
onDeleteUser: (user: TypesGen.User) => void;
@@ -78,6 +78,7 @@ export const UsersTable: FC<React.PropsWithChildren<UsersTableProps>> = ({
7878
{canEditUsers && <TableCell width="1%" />}
7979
</TableRow>
8080
</TableHead>
81+
8182
<TableBody>
8283
<UsersTableBody
8384
users={users}

0 commit comments

Comments
 (0)