diff --git a/backend/.sqlx/query-21e9a9fc33dcdb66a2c8e95b1359ca1b3e04b4ecf155757abf5798834ebfd0ce.json b/backend/.sqlx/query-21e9a9fc33dcdb66a2c8e95b1359ca1b3e04b4ecf155757abf5798834ebfd0ce.json new file mode 100644 index 0000000000..036de3ec31 --- /dev/null +++ b/backend/.sqlx/query-21e9a9fc33dcdb66a2c8e95b1359ca1b3e04b4ecf155757abf5798834ebfd0ce.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT email FROM password ORDER BY email", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "email", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "21e9a9fc33dcdb66a2c8e95b1359ca1b3e04b4ecf155757abf5798834ebfd0ce" +} diff --git a/backend/windmill-api-users/src/users.rs b/backend/windmill-api-users/src/users.rs index 014ad44931..e4a9749171 100644 --- a/backend/windmill-api-users/src/users.rs +++ b/backend/windmill-api-users/src/users.rs @@ -86,6 +86,10 @@ pub fn global_service() -> Router { .route("/decline_invite", post(decline_invite)) .route("/accept_invite", post(accept_invite)) .route("/list_as_super_admin", get(list_users_as_super_admin)) + .route( + "/list_instance_emails", + get(list_instance_emails), + ) .route("/set_login_type/:user", post(set_login_type)) .route("/update/:user", post(update_user)) .route("/delete/:user", delete(delete_user)) @@ -420,6 +424,21 @@ async fn list_users_as_super_admin( Ok(Json(rows)) } +async fn list_instance_emails( + _authed: ApiAuthed, + Extension(db): Extension, +) -> JsonResult> { + if *CLOUD_HOSTED { + return Err(Error::BadRequest( + "This endpoint is not available on cloud hosted instances".to_string(), + )); + } + let rows = sqlx::query_scalar!("SELECT email FROM password ORDER BY email") + .fetch_all(&db) + .await?; + Ok(Json(rows)) +} + #[derive(Serialize, Deserialize)] struct Progress { progress: u64, diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 497fab7c67..22f4af5da2 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -2306,6 +2306,22 @@ paths: items: $ref: "#/components/schemas/GlobalUserInfo" + /users/list_instance_emails: + get: + summary: list all instance user emails (only on non-cloud instances) + operationId: listInstanceEmails + tags: + - user + responses: + "200": + description: list of instance user emails + content: + application/json: + schema: + type: array + items: + type: string + /w/{workspace}/workspaces/list_pending_invites: get: summary: list pending invites for a workspace diff --git a/frontend/src/lib/components/AddUser.svelte b/frontend/src/lib/components/AddUser.svelte index 1872684410..8968e56f4b 100644 --- a/frontend/src/lib/components/AddUser.svelte +++ b/frontend/src/lib/components/AddUser.svelte @@ -10,6 +10,7 @@ import ToggleButtonGroup from './common/toggleButton-v2/ToggleButtonGroup.svelte' import ToggleButton from './common/toggleButton-v2/ToggleButton.svelte' import { UserPlus } from 'lucide-svelte' + import Select from './select/Select.svelte' const dispatch = createEventDispatcher() @@ -31,6 +32,19 @@ } getAutomateUsernameCreationSetting() + let instanceEmails: { label: string; value: string }[] | undefined = $state(undefined) + + async function loadInstanceEmails() { + if (isCloudHosted()) return + try { + const emails = await UserService.listInstanceEmails() + instanceEmails = emails.map((e) => ({ label: e, value: e })) + } catch { + instanceEmails = undefined + } + } + loadInstanceEmails() + async function addUser() { await WorkspaceService.addUser({ workspace: $workspaceStore!, @@ -84,7 +98,25 @@ Add a new user Email - + {#if instanceEmails} + + {/if} {#if !automateUsernameCreation} Username