feat: add role selector in the create user form (#24711)

Adds a role selector to the create user form so admins can assign
site-level roles at creation time rather than navigating to the user
afterward.

The `POST /api/v2/users` endpoint now accepts an optional `roles` field,
wiring it through to the existing `RBACRoles` field on the internal
`CreateUserRequest`. No database changes are needed since roles are
already stored inline on the user row.

On the frontend, a `RoleSelector` component renders the assignable roles
as a scrollable multiselect checklist with the non-assignable Member
role pinned as a non-interactive footer. The selector appears once a
login type is chosen.

Also adds a `condensed` size (690px) to `Margins` between the existing
`small` (460px) and `medium` (1080px), and exposes a `size` prop on
`FullPageForm`. The create user form uses `condensed` to give the role
selector more breathing room. Also fixes `MockUserAdminRole` and
`MockTemplateAdminRole` in test helpers to use hyphenated names
(`user-admin`, `template-admin`) matching the canonical names in the Go
RBAC layer.

Fixes `sortRolesByAccessLevel` in `UserRoleCell` to sort unranked roles
(e.g. `member`) after all known roles. Previously, `indexOf` returned -1
for unknown names, placing them first; now they receive
`POSITIVE_INFINITY` as their rank.

🤖 Generated with [Claude Code](<https://claude.ai/claude-code>)

---


https://github.com/user-attachments/assets/75e7c8c5-d0d2-481d-86e8-1fcfb574517c

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeremy Ruppel
2026-04-29 10:57:10 -04:00
committed by GitHub
co-authored by Claude Sonnet 4.6
parent ab75e46f1d
commit 0754016512
15 changed files with 302 additions and 42 deletions
+7
View File
@@ -15411,6 +15411,13 @@ const docTemplate = `{
"password": {
"type": "string"
},
"roles": {
"description": "Roles is an optional list of site-level roles to assign at creation.",
"type": "array",
"items": {
"type": "string"
}
},
"service_account": {
"description": "Service accounts are admin-managed accounts that cannot login.",
"type": "boolean"
+7
View File
@@ -13890,6 +13890,13 @@
"password": {
"type": "string"
},
"roles": {
"description": "Roles is an optional list of site-level roles to assign at creation.",
"type": "array",
"items": {
"type": "string"
}
},
"service_account": {
"description": "Service accounts are admin-managed accounts that cannot login.",
"type": "boolean"
+1
View File
@@ -615,6 +615,7 @@ func (api *API) postUser(rw http.ResponseWriter, r *http.Request) {
CreateUserRequestWithOrgs: req,
LoginType: loginType,
accountCreatorName: accountCreator.Name,
RBACRoles: req.Roles,
})
if dbauthz.IsNotAuthorizedError(err) {