You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Let a project admin type a colleague's email address in the Console and grant them admin access to the project, without the Console ever confirming whether that address belongs to anyone.
Current state
The Settings → Admins screen (shipped by PR #1167) adds people through a picker: apps/console/src/components/add-admin-dialog.tsx loads one page of up to 100 users via POST /users/query and filters them in the browser. The file's own comment explains why: the users API has no identifier filter, so an email could not be resolved server-side. That gap is what PR #1192 closes on the API side, and its description explicitly leaves the email UX to "a later PR". This is that change.
The picker has two problems the email field fixes: it shows any operator a list of up to 100 people (names and identifiers), and it cannot reach user 101.
Decisions that shape this work
A plain text input for the email address. No type-ahead, no suggestions, no picker.
Submitting calls grant create with user: { identifier } and relation: "admin". The invited person becomes an admin, same as the pane creates today. No role choice.
Whatever happens server-side, the Console shows the same message: "If the user exists in our system, they have been granted access to your project." The API is being made genuinely neutral in Neutral responses for grant creation by identifier #1229; the Console never branches on the outcome.
Strictly speaking the field holds an identifier (email in the default schema, per ADR 058); the UI can still call it an email address.
Typing your own address is caught in the Console before submitting (the shell already has the session's identifier from GET /sessions/me, apps/console/src/routes/_authed.tsx:55-59) and shown as a plain validation error. The API rejects it too.
A syntactically invalid address is a normal client-side validation error.
The invited person is not notified. No email is sent; they see the project next time they open the Console. Invitation emails, pending invites and signup links stay out of scope, as Give colleagues administrative access to a claimed Project #769 already decided.
@elinashoko: where should the email input live? The current pane opens an "Add admin" dialog from Settings → Admins. Keeping that dialog and swapping the picker for the input field is the smallest change; say if the design wants it somewhere else.
Write component tests first against the api-mock: submitting a well-formed address calls grant create with the identifier and shows the neutral message; an unknown address shows the exact same message; the caller's own address is blocked before any request is sent; a malformed address shows a validation error and sends nothing. Then implement.
Tasks
Replace the Combobox in apps/console/src/components/add-admin-dialog.tsx with a plain email input; drop the queryUsers call and the Person[] plumbing.
Send { user: { identifier }, relation: "admin" } on submit and render the fixed neutral message on completion.
Add the self-address pre-check and the email format validation.
Update the dialog specs and apps/console/src/routes/_authed/settings/admins.spec.tsx.
Reference
apps/console/src/components/add-admin-dialog.tsx (the picker being replaced, and its docblock on the missing identifier filter); PR #1192; PR #1167 (the pane this extends).
Update (2026-09-16)
Confirmed with @elinashoko and @bastionstack: the settings page and the invitation modal are already built (@bastionstack shipped them in #1167). Nothing new is being designed here, and the open question above is answered: the email input lives in the existing "Add admin" dialog. This ticket is only the swap inside that dialog, from searching a list of users to a plain email input.
On "can this be updated yet": not against the real backend. Creating a grant from an email address arrives with PR #1192, and #1229 makes the responses neutral so the fixed message stays honest. The component work can start now, test-first against the api-mock mirroring that contract; wiring to the real API waits for those two.
Part of #1022. Blocked by #1229 and PR #1192.
Goal
Let a project admin type a colleague's email address in the Console and grant them admin access to the project, without the Console ever confirming whether that address belongs to anyone.
Current state
The Settings → Admins screen (shipped by PR #1167) adds people through a picker:
apps/console/src/components/add-admin-dialog.tsxloads one page of up to 100 users viaPOST /users/queryand filters them in the browser. The file's own comment explains why: the users API has no identifier filter, so an email could not be resolved server-side. That gap is what PR #1192 closes on the API side, and its description explicitly leaves the email UX to "a later PR". This is that change.The picker has two problems the email field fixes: it shows any operator a list of up to 100 people (names and identifiers), and it cannot reach user 101.
Decisions that shape this work
user: { identifier }andrelation: "admin". The invited person becomes an admin, same as the pane creates today. No role choice.GET /sessions/me,apps/console/src/routes/_authed.tsx:55-59) and shown as a plain validation error. The API rejects it too.Open question ✅
@elinashoko: where should the email input live? The current pane opens an "Add admin" dialog from Settings → Admins. Keeping that dialog and swapping the picker for the input field is the smallest change; say if the design wants it somewhere else.Dependencies
Test first (TDD)
Write component tests first against the api-mock: submitting a well-formed address calls grant create with the identifier and shows the neutral message; an unknown address shows the exact same message; the caller's own address is blocked before any request is sent; a malformed address shows a validation error and sends nothing. Then implement.
Tasks
apps/console/src/components/add-admin-dialog.tsxwith a plain email input; drop thequeryUserscall and thePerson[]plumbing.{ user: { identifier }, relation: "admin" }on submit and render the fixed neutral message on completion.apps/console/src/routes/_authed/settings/admins.spec.tsx.Reference
apps/console/src/components/add-admin-dialog.tsx(the picker being replaced, and its docblock on the missing identifier filter); PR #1192; PR #1167 (the pane this extends).Update (2026-09-16)
Confirmed with @elinashoko and @bastionstack: the settings page and the invitation modal are already built (@bastionstack shipped them in #1167). Nothing new is being designed here, and the open question above is answered: the email input lives in the existing "Add admin" dialog. This ticket is only the swap inside that dialog, from searching a list of users to a plain email input.
On "can this be updated yet": not against the real backend. Creating a grant from an email address arrives with PR #1192, and #1229 makes the responses neutral so the fixed message stays honest. The component work can start now, test-first against the api-mock mirroring that contract; wiring to the real API waits for those two.