Skip to content

Commit b415ee4

Browse files
committed
feat: create advanced roles collapsible section
1 parent 59e1eb1 commit b415ee4

File tree

1 file changed

+57
-3
lines changed

1 file changed

+57
-3
lines changed

site/src/pages/OrganizationSettingsPage/UserTable/EditRolesButton.tsx

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ import {
1616
PopoverContent,
1717
PopoverTrigger,
1818
} from "components/deprecated/Popover/Popover";
19-
import type { FC } from "react";
19+
import { ChevronDownIcon, ChevronRightIcon } from "lucide-react";
20+
import { type FC, useEffect, useState } from "react";
21+
import { cn } from "utils/cn";
2022

2123
const roleDescriptions: Record<string, string> = {
2224
owner:
@@ -57,7 +59,7 @@ const Option: FC<OptionProps> = ({
5759
}}
5860
/>
5961
<div className="flex flex-col">
60-
<strong>{name}</strong>
62+
<strong className="text-sm">{name}</strong>
6163
<span className="text-xs text-content-secondary">{description}</span>
6264
</div>
6365
</div>
@@ -91,6 +93,7 @@ export const EditRolesButton: FC<EditRolesButtonProps> = ({
9193

9294
onChange([...selectedRoleNames, roleName]);
9395
};
96+
const [isAdvancedOpen, setIsAdvancedOpen] = useState(false);
9497

9598
const canSetRoles =
9699
userLoginType !== "oidc" || (userLoginType === "oidc" && !oidcRoleSync);
@@ -109,6 +112,20 @@ export const EditRolesButton: FC<EditRolesButtonProps> = ({
109112
);
110113
}
111114

115+
const filteredRoles = roles.filter(
116+
(role) => role.name !== "organization-workspace-creation-ban",
117+
);
118+
const advancedRoles = roles.filter(
119+
(role) => role.name === "organization-workspace-creation-ban",
120+
);
121+
122+
// make sure the advanced roles are always visible if the user has one of these roles
123+
useEffect(() => {
124+
if (selectedRoleNames.has("organization-workspace-creation-ban")) {
125+
setIsAdvancedOpen(true);
126+
}
127+
}, [selectedRoleNames]);
128+
112129
return (
113130
<Popover>
114131
<PopoverTrigger>
@@ -131,7 +148,7 @@ export const EditRolesButton: FC<EditRolesButtonProps> = ({
131148
title="Available roles"
132149
>
133150
<div className="flex flex-col gap-4 p-6">
134-
{roles.map((role) => (
151+
{filteredRoles.map((role) => (
135152
<Option
136153
key={role.name}
137154
onChange={handleChange}
@@ -141,6 +158,43 @@ export const EditRolesButton: FC<EditRolesButtonProps> = ({
141158
description={roleDescriptions[role.name] ?? ""}
142159
/>
143160
))}
161+
{advancedRoles.length > 0 && (
162+
<>
163+
<button
164+
className={cn([
165+
"flex items-center gap-1 p-0 bg-transparent border-0 text-inherit text-sm cursor-pointer",
166+
"transition-colors text-content-secondary hover:text-content-primary font-medium whitespace-nowrap",
167+
isAdvancedOpen && "text-content-primary",
168+
])}
169+
type="button"
170+
onClick={() => {
171+
setIsAdvancedOpen((v) => !v);
172+
}}
173+
>
174+
{isAdvancedOpen ? (
175+
<ChevronDownIcon className="size-icon-sm p-0.5" />
176+
) : (
177+
<ChevronRightIcon className="size-icon-sm p-0.5" />
178+
)}
179+
<span className="sr-only">
180+
({isAdvancedOpen ? "Hide" : "Show advanced"})
181+
</span>
182+
<span className="[&:first-letter]:uppercase">Advanced</span>
183+
</button>
184+
185+
{isAdvancedOpen &&
186+
advancedRoles.map((role) => (
187+
<Option
188+
key={role.name}
189+
onChange={handleChange}
190+
isChecked={selectedRoleNames.has(role.name)}
191+
value={role.name}
192+
name={role.display_name || role.name}
193+
description={roleDescriptions[role.name] ?? ""}
194+
/>
195+
))}
196+
</>
197+
)}
144198
</div>
145199
</fieldset>
146200
<div className="p-6 border-t-1 border-solid border-border text-sm">

0 commit comments

Comments
 (0)