diff --git a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-delete-dialog.component.html b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-delete-dialog.component.html new file mode 100644 index 0000000000..9a4ce89671 --- /dev/null +++ b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-delete-dialog.component.html @@ -0,0 +1,85 @@ + + + + {{ "noSelectedMembersApplicable" | i18n }} + + + {{ error }} + + + 0 && !error"> + {{ "deleteOrganizationUserWarning" | i18n }} + + + + + {{ "member" | i18n }} + + + + + + + + + + {{ user.email }} + + {{ "invited" | i18n }} + + + {{ user.name }} + + + + + + + + + + {{ "member" | i18n }} + {{ "status" | i18n }} + + + + + + + + + {{ user.email }} + {{ user.name }} + + + {{ statuses.get(user.id) }} + + + {{ "bulkFilteredMessage" | i18n }} + + + + + + + + 0" + bitButton + type="submit" + buttonType="primary" + [disabled]="loading" + (click)="submit()" + > + {{ "deleteMembers" | i18n }} + + + {{ "close" | i18n }} + + + diff --git a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-delete-dialog.component.ts b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-delete-dialog.component.ts new file mode 100644 index 0000000000..1755b0b0b9 --- /dev/null +++ b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-delete-dialog.component.ts @@ -0,0 +1,65 @@ +import { DIALOG_DATA, DialogConfig } from "@angular/cdk/dialog"; +import { Component, Inject } from "@angular/core"; + +import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; +import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { DialogService } from "@bitwarden/components"; + +import { BulkUserDetails } from "./bulk-status.component"; + +type BulkDeleteDialogParams = { + organizationId: string; + users: BulkUserDetails[]; +}; + +@Component({ + templateUrl: "bulk-delete-dialog.component.html", +}) +export class BulkDeleteDialogComponent { + organizationId: string; + users: BulkUserDetails[]; + loading = false; + done = false; + error: string = null; + statuses = new Map(); + userStatusType = OrganizationUserStatusType; + + constructor( + @Inject(DIALOG_DATA) protected dialogParams: BulkDeleteDialogParams, + protected i18nService: I18nService, + private organizationUserApiService: OrganizationUserApiService, + ) { + this.organizationId = dialogParams.organizationId; + this.users = dialogParams.users; + } + + async submit() { + try { + this.loading = true; + this.error = null; + + const response = await this.organizationUserApiService.deleteManyOrganizationUsers( + this.organizationId, + this.users.map((user) => user.id), + ); + + response.data.forEach((entry) => { + this.statuses.set( + entry.id, + entry.error ? entry.error : this.i18nService.t("deletedSuccessfully"), + ); + }); + + this.done = true; + } catch (e) { + this.error = e.message; + } finally { + this.loading = false; + } + } + + static open(dialogService: DialogService, config: DialogConfig) { + return dialogService.open(BulkDeleteDialogComponent, config); + } +} diff --git a/apps/web/src/app/admin-console/organizations/members/members.component.html b/apps/web/src/app/admin-console/organizations/members/members.component.html index f87934dbe8..a9c5ab3e4a 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.component.html +++ b/apps/web/src/app/admin-console/organizations/members/members.component.html @@ -137,6 +137,17 @@ {{ "remove" | i18n }} + + + + {{ "delete" | i18n }} + + diff --git a/apps/web/src/app/admin-console/organizations/members/members.component.ts b/apps/web/src/app/admin-console/organizations/members/members.component.ts index 30c5106a4f..6d2d3a4512 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/members.component.ts @@ -61,6 +61,7 @@ import { OrganizationUserView } from "../core/views/organization-user.view"; import { openEntityEventsDialog } from "../manage/entity-events.component"; import { BulkConfirmDialogComponent } from "./components/bulk/bulk-confirm-dialog.component"; +import { BulkDeleteDialogComponent } from "./components/bulk/bulk-delete-dialog.component"; import { BulkEnableSecretsManagerDialogComponent } from "./components/bulk/bulk-enable-sm-dialog.component"; import { BulkRemoveDialogComponent } from "./components/bulk/bulk-remove-dialog.component"; import { BulkRestoreRevokeComponent } from "./components/bulk/bulk-restore-revoke.component"; @@ -543,6 +544,21 @@ export class MembersComponent extends BaseMembersComponent await this.load(); } + async bulkDelete() { + if (this.actionPromise != null) { + return; + } + + const dialogRef = BulkDeleteDialogComponent.open(this.dialogService, { + data: { + organizationId: this.organization.id, + users: this.dataSource.getCheckedUsers(), + }, + }); + await lastValueFrom(dialogRef.closed); + await this.load(); + } + async bulkRevoke() { await this.bulkRevokeOrRestore(true); } diff --git a/apps/web/src/app/admin-console/organizations/members/members.module.ts b/apps/web/src/app/admin-console/organizations/members/members.module.ts index d7c5a9bf1d..81697f8c84 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.module.ts +++ b/apps/web/src/app/admin-console/organizations/members/members.module.ts @@ -8,6 +8,7 @@ import { LooseComponentsModule } from "../../../shared"; import { SharedOrganizationModule } from "../shared"; import { BulkConfirmDialogComponent } from "./components/bulk/bulk-confirm-dialog.component"; +import { BulkDeleteDialogComponent } from "./components/bulk/bulk-delete-dialog.component"; import { BulkEnableSecretsManagerDialogComponent } from "./components/bulk/bulk-enable-sm-dialog.component"; import { BulkRemoveDialogComponent } from "./components/bulk/bulk-remove-dialog.component"; import { BulkRestoreRevokeComponent } from "./components/bulk/bulk-restore-revoke.component"; @@ -35,6 +36,7 @@ import { MembersComponent } from "./members.component"; BulkStatusComponent, MembersComponent, ResetPasswordComponent, + BulkDeleteDialogComponent, ], }) export class MembersModule {} diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 00d2102c78..76cd45e149 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -9695,5 +9695,14 @@ }, "suspendedOwnerOrgMessage": { "message": "To regain access to your organization, add a payment method." + }, + "deleteMembers": { + "message": "Delete members" + }, + "noSelectedMembersApplicable": { + "message": "This action is not applicable to any of the selected members." + }, + "deletedSuccessfully": { + "message": "Deleted successfully" } } diff --git a/libs/admin-console/src/common/organization-user/abstractions/organization-user-api.service.ts b/libs/admin-console/src/common/organization-user/abstractions/organization-user-api.service.ts index 42cbe1438d..3186bdaa84 100644 --- a/libs/admin-console/src/common/organization-user/abstractions/organization-user-api.service.ts +++ b/libs/admin-console/src/common/organization-user/abstractions/organization-user-api.service.ts @@ -282,4 +282,15 @@ export abstract class OrganizationUserApiService { * @param id - Organization user identifier */ abstract deleteOrganizationUser(organizationId: string, id: string): Promise; + + /** + * Delete many organization users + * @param organizationId - Identifier for the organization the users belongs to + * @param ids - List of organization user identifiers to delete + * @return List of user ids, including both those that were successfully deleted and those that had an error + */ + abstract deleteManyOrganizationUsers( + organizationId: string, + ids: string[], + ): Promise>; } diff --git a/libs/admin-console/src/common/organization-user/services/default-organization-user-api.service.ts b/libs/admin-console/src/common/organization-user/services/default-organization-user-api.service.ts index d9e069dc93..7289f41d7e 100644 --- a/libs/admin-console/src/common/organization-user/services/default-organization-user-api.service.ts +++ b/libs/admin-console/src/common/organization-user/services/default-organization-user-api.service.ts @@ -369,4 +369,18 @@ export class DefaultOrganizationUserApiService implements OrganizationUserApiSer false, ); } + + async deleteManyOrganizationUsers( + organizationId: string, + ids: string[], + ): Promise> { + const r = await this.apiService.send( + "DELETE", + "/organizations/" + organizationId + "/users/delete-account", + new OrganizationUserBulkRequest(ids), + true, + true, + ); + return new ListResponse(r, OrganizationUserBulkResponse); + } }
{{ "deleteOrganizationUserWarning" | i18n }}