diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index 8f79f2294..c66f607d1 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -44,6 +44,9 @@ } } }, + "bulk_add_users_modal": { + "button_title": "Bulk Add Users", + }, "create_user_modal": { "create_user": "Create User", "help_create_single_guest_user": "You can invite users to register and join a project by themselves with the **Add Project Member** button. See [Add Project Member]({helpLink}) for details.", diff --git a/frontend/src/routes/(authenticated)/admin/+page.svelte b/frontend/src/routes/(authenticated)/admin/+page.svelte index 1b045a5da..f9aec3f9d 100644 --- a/frontend/src/routes/(authenticated)/admin/+page.svelte +++ b/frontend/src/routes/(authenticated)/admin/+page.svelte @@ -23,6 +23,7 @@ import type { Confidentiality } from '$lib/components/Projects'; import { browser } from '$app/environment'; import UserTable from './UserTable.svelte'; + import type { UUID } from 'crypto'; export let data: PageData; $: projects = data.projects; @@ -41,6 +42,7 @@ memberSearch: queryParam.string(undefined), projectSearch: queryParam.string(''), tab: queryParam.string('projects'), + targetOrgId: queryParam.string(''), }); const userFilterKeys = ['userSearch'] as const satisfies Readonly<(keyof AdminSearchParams)[]>; @@ -60,6 +62,15 @@ $: users = $userData?.items ?? []; $: filteredUserCount = $userData?.totalCount ?? 0; $: shownUsers = lastLoadUsedActiveFilter ? users : users.slice(0, 10); + let selectedUsers: User[] = []; + + function bulkAddSelectedUsersToOrg(): void { + if (!$queryParamValues.targetOrgId) { + // Shouldn't have been called + return; + } + console.log(`Would add the following users to org with ID ${$queryParamValues.targetOrgId}:`, selectedUsers); + } function filterProjectsByUser(user: User): void { $queryParamValues.memberSearch = user.email ?? user.username ?? undefined; @@ -131,6 +142,15 @@ + {#if $queryParamValues.targetOrgId} + + {/if} createUserModal.open()}> @@ -157,6 +177,7 @@
userModal.open(event.detail)} on:editUser={(event) => openModal(event.detail)} on:filterProjectsByUser={(event) => filterProjectsByUser(event.detail)} diff --git a/frontend/src/routes/(authenticated)/admin/+page.ts b/frontend/src/routes/(authenticated)/admin/+page.ts index 5a2ea2f7f..1a3b3112e 100644 --- a/frontend/src/routes/(authenticated)/admin/+page.ts +++ b/frontend/src/routes/(authenticated)/admin/+page.ts @@ -22,11 +22,13 @@ import type { ProjectFilters } from '$lib/components/Projects'; import { DEFAULT_PAGE_SIZE } from '$lib/components/Paging'; import type { AdminTabId } from './AdminTabs.svelte'; import { derived, readable } from 'svelte/store'; +import type { UUID } from 'crypto'; // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents -- false positive? export type AdminSearchParams = ProjectFilters & { userSearch: string tab: AdminTabId + targetOrgId: UUID | '' }; export type Project = NonNullable[number]; diff --git a/frontend/src/routes/(authenticated)/org/[org_id]/+page.svelte b/frontend/src/routes/(authenticated)/org/[org_id]/+page.svelte index f4b7c35c0..36e37aa0e 100644 --- a/frontend/src/routes/(authenticated)/org/[org_id]/+page.svelte +++ b/frontend/src/routes/(authenticated)/org/[org_id]/+page.svelte @@ -138,6 +138,11 @@
+