From 470ddf79ab1b2b4be402ebad8bf4fd560dc66fae Mon Sep 17 00:00:00 2001 From: Alex Morask <144709477+amorask-bitwarden@users.noreply.github.com> Date: Tue, 22 Oct 2024 08:46:45 -0400 Subject: [PATCH] [PM-12425] Remove FF: AC-2828_provider-portal-members-page (#11241) * Remove FF: AC-2828_provider-portal-members-page * Thomas' feedback: Fix provider layout --- ...tml => bulk-confirm-dialog.component.html} | 0 .../bulk/bulk-confirm-dialog.component.ts | 87 ++++++ .../components/bulk/bulk-confirm.component.ts | 132 --------- ...html => bulk-remove-dialog.component.html} | 0 .../bulk/bulk-remove-dialog.component.ts | 54 ++++ .../components/bulk/bulk-remove.component.ts | 76 ----- .../members/members.component.ts | 8 +- .../organizations/members/members.module.ts | 8 +- .../manage/bulk/bulk-confirm.component.ts | 37 --- .../manage/bulk/bulk-remove.component.ts | 24 -- .../dialogs/bulk-confirm-dialog.component.ts | 2 +- .../dialogs/bulk-remove-dialog.component.ts | 2 +- .../providers/manage/people.component.html | 203 ------------- .../providers/manage/people.component.ts | 267 ------------------ .../providers/providers-layout.component.html | 2 +- .../providers/providers-routing.module.ts | 27 +- .../providers/providers.module.ts | 6 - libs/common/src/enums/feature-flag.enum.ts | 4 +- 18 files changed, 164 insertions(+), 775 deletions(-) rename apps/web/src/app/admin-console/organizations/members/components/bulk/{bulk-confirm.component.html => bulk-confirm-dialog.component.html} (100%) create mode 100644 apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm-dialog.component.ts delete mode 100644 apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.ts rename apps/web/src/app/admin-console/organizations/members/components/bulk/{bulk-remove.component.html => bulk-remove-dialog.component.html} (100%) create mode 100644 apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove-dialog.component.ts delete mode 100644 apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.ts delete mode 100644 bitwarden_license/bit-web/src/app/admin-console/providers/manage/bulk/bulk-confirm.component.ts delete mode 100644 bitwarden_license/bit-web/src/app/admin-console/providers/manage/bulk/bulk-remove.component.ts delete mode 100644 bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.html delete mode 100644 bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.ts diff --git a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.html b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm-dialog.component.html similarity index 100% rename from apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.html rename to apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm-dialog.component.html diff --git a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm-dialog.component.ts b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm-dialog.component.ts new file mode 100644 index 0000000000..8e6ec1dbc3 --- /dev/null +++ b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm-dialog.component.ts @@ -0,0 +1,87 @@ +import { DIALOG_DATA, DialogConfig } from "@angular/cdk/dialog"; +import { Component, Inject } from "@angular/core"; +import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; +import { firstValueFrom, map, Observable, switchMap } from "rxjs"; + +import { + OrganizationUserApiService, + OrganizationUserBulkConfirmRequest, + OrganizationUserBulkPublicKeyResponse, + OrganizationUserBulkResponse, +} from "@bitwarden/admin-console/common"; +import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums"; +import { ProviderUserBulkPublicKeyResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-user-bulk-public-key.response"; +import { ProviderUserBulkResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-user-bulk.response"; +import { ListResponse } from "@bitwarden/common/models/response/list.response"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { StateProvider } from "@bitwarden/common/platform/state"; +import { OrganizationId } from "@bitwarden/common/types/guid"; +import { OrgKey } from "@bitwarden/common/types/key"; +import { DialogService } from "@bitwarden/components"; + +import { BaseBulkConfirmComponent } from "./base-bulk-confirm.component"; +import { BulkUserDetails } from "./bulk-status.component"; + +type BulkConfirmDialogParams = { + organizationId: string; + users: BulkUserDetails[]; +}; + +@Component({ + templateUrl: "bulk-confirm-dialog.component.html", +}) +export class BulkConfirmDialogComponent extends BaseBulkConfirmComponent { + organizationId: string; + organizationKey$: Observable; + users: BulkUserDetails[]; + + constructor( + protected cryptoService: CryptoService, + @Inject(DIALOG_DATA) protected dialogParams: BulkConfirmDialogParams, + protected encryptService: EncryptService, + private organizationUserApiService: OrganizationUserApiService, + protected i18nService: I18nService, + private stateProvider: StateProvider, + ) { + super(cryptoService, encryptService, i18nService); + + this.organizationId = dialogParams.organizationId; + this.organizationKey$ = this.stateProvider.activeUserId$.pipe( + switchMap((userId) => this.cryptoService.orgKeys$(userId)), + map((organizationKeysById) => organizationKeysById[this.organizationId as OrganizationId]), + takeUntilDestroyed(), + ); + this.users = dialogParams.users; + } + + protected getCryptoKey = async (): Promise => + await firstValueFrom(this.organizationKey$); + + protected getPublicKeys = async (): Promise< + ListResponse + > => + await this.organizationUserApiService.postOrganizationUsersPublicKey( + this.organizationId, + this.filteredUsers.map((user) => user.id), + ); + + protected isAccepted = (user: BulkUserDetails) => + user.status === OrganizationUserStatusType.Accepted; + + protected postConfirmRequest = async ( + userIdsWithKeys: { id: string; key: string }[], + ): Promise> => { + const request = new OrganizationUserBulkConfirmRequest(userIdsWithKeys); + return await this.organizationUserApiService.postOrganizationUserBulkConfirm( + this.organizationId, + request, + ); + }; + + static open(dialogService: DialogService, config: DialogConfig) { + return dialogService.open(BulkConfirmDialogComponent, config); + } +} diff --git a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.ts b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.ts deleted file mode 100644 index ee50684062..0000000000 --- a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { DIALOG_DATA, DialogConfig } from "@angular/cdk/dialog"; -import { Component, Inject, OnInit } from "@angular/core"; - -import { - OrganizationUserApiService, - OrganizationUserBulkConfirmRequest, -} from "@bitwarden/admin-console/common"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums"; -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; -import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; -import { DialogService } from "@bitwarden/components"; - -import { BulkUserDetails } from "./bulk-status.component"; - -type BulkConfirmDialogData = { - organizationId: string; - users: BulkUserDetails[]; -}; - -@Component({ - selector: "app-bulk-confirm", - templateUrl: "bulk-confirm.component.html", -}) -export class BulkConfirmComponent implements OnInit { - organizationId: string; - users: BulkUserDetails[]; - - excludedUsers: BulkUserDetails[]; - filteredUsers: BulkUserDetails[]; - publicKeys: Map = new Map(); - fingerprints: Map = new Map(); - statuses: Map = new Map(); - - loading = true; - done = false; - error: string; - - constructor( - @Inject(DIALOG_DATA) protected data: BulkConfirmDialogData, - protected cryptoService: CryptoService, - protected encryptService: EncryptService, - protected apiService: ApiService, - private organizationUserApiService: OrganizationUserApiService, - private i18nService: I18nService, - ) { - this.organizationId = data.organizationId; - this.users = data.users; - } - - async ngOnInit() { - this.excludedUsers = this.users.filter((u) => !this.isAccepted(u)); - this.filteredUsers = this.users.filter((u) => this.isAccepted(u)); - - if (this.filteredUsers.length <= 0) { - this.done = true; - } - - const response = await this.getPublicKeys(); - - for (const entry of response.data) { - const publicKey = Utils.fromB64ToArray(entry.key); - const fingerprint = await this.cryptoService.getFingerprint(entry.userId, publicKey); - if (fingerprint != null) { - this.publicKeys.set(entry.id, publicKey); - this.fingerprints.set(entry.id, fingerprint.join("-")); - } - } - - this.loading = false; - } - - async submit() { - this.loading = true; - try { - const key = await this.getCryptoKey(); - const userIdsWithKeys: any[] = []; - for (const user of this.filteredUsers) { - const publicKey = this.publicKeys.get(user.id); - if (publicKey == null) { - continue; - } - const encryptedKey = await this.encryptService.rsaEncrypt(key.key, publicKey); - userIdsWithKeys.push({ - id: user.id, - key: encryptedKey.encryptedString, - }); - } - const response = await this.postConfirmRequest(userIdsWithKeys); - - response.data.forEach((entry) => { - const error = entry.error !== "" ? entry.error : this.i18nService.t("bulkConfirmMessage"); - this.statuses.set(entry.id, error); - }); - - this.done = true; - } catch (e) { - this.error = e.message; - } - this.loading = false; - } - - protected isAccepted(user: BulkUserDetails) { - return user.status === OrganizationUserStatusType.Accepted; - } - - protected async getPublicKeys() { - return await this.organizationUserApiService.postOrganizationUsersPublicKey( - this.organizationId, - this.filteredUsers.map((user) => user.id), - ); - } - - protected getCryptoKey(): Promise { - return this.cryptoService.getOrgKey(this.organizationId); - } - - protected async postConfirmRequest(userIdsWithKeys: any[]) { - const request = new OrganizationUserBulkConfirmRequest(userIdsWithKeys); - return await this.organizationUserApiService.postOrganizationUserBulkConfirm( - this.organizationId, - request, - ); - } - - static open(dialogService: DialogService, config: DialogConfig) { - return dialogService.open(BulkConfirmComponent, config); - } -} diff --git a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.html b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove-dialog.component.html similarity index 100% rename from apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.html rename to apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove-dialog.component.html diff --git a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove-dialog.component.ts b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove-dialog.component.ts new file mode 100644 index 0000000000..9ff097debb --- /dev/null +++ b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove-dialog.component.ts @@ -0,0 +1,54 @@ +import { DIALOG_DATA, DialogConfig } from "@angular/cdk/dialog"; +import { Component, Inject } from "@angular/core"; + +import { + OrganizationUserApiService, + OrganizationUserBulkResponse, +} from "@bitwarden/admin-console/common"; +import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums"; +import { ListResponse } from "@bitwarden/common/models/response/list.response"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { DialogService } from "@bitwarden/components"; + +import { BaseBulkRemoveComponent } from "./base-bulk-remove.component"; +import { BulkUserDetails } from "./bulk-status.component"; + +type BulkRemoveDialogParams = { + organizationId: string; + users: BulkUserDetails[]; +}; + +@Component({ + templateUrl: "bulk-remove-dialog.component.html", +}) +export class BulkRemoveDialogComponent extends BaseBulkRemoveComponent { + organizationId: string; + users: BulkUserDetails[]; + + constructor( + @Inject(DIALOG_DATA) protected dialogParams: BulkRemoveDialogParams, + protected i18nService: I18nService, + private organizationUserApiService: OrganizationUserApiService, + ) { + super(i18nService); + this.organizationId = dialogParams.organizationId; + this.users = dialogParams.users; + this.showNoMasterPasswordWarning = this.users.some( + (u) => u.status > OrganizationUserStatusType.Invited && u.hasMasterPassword === false, + ); + } + + protected deleteUsers = (): Promise> => + this.organizationUserApiService.removeManyOrganizationUsers( + this.organizationId, + this.users.map((user) => user.id), + ); + + protected get removeUsersWarning() { + return this.i18nService.t("removeOrgUsersConfirmation"); + } + + static open(dialogService: DialogService, config: DialogConfig) { + return dialogService.open(BulkRemoveDialogComponent, config); + } +} diff --git a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.ts b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.ts deleted file mode 100644 index 74939238fc..0000000000 --- a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { DIALOG_DATA, DialogConfig } from "@angular/cdk/dialog"; -import { Component, Inject } from "@angular/core"; - -import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -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 BulkRemoveDialogData = { - organizationId: string; - users: BulkUserDetails[]; -}; - -@Component({ - selector: "app-bulk-remove", - templateUrl: "bulk-remove.component.html", -}) -export class BulkRemoveComponent { - organizationId: string; - users: BulkUserDetails[]; - - statuses: Map = new Map(); - - loading = false; - done = false; - error: string; - showNoMasterPasswordWarning = false; - - constructor( - @Inject(DIALOG_DATA) protected data: BulkRemoveDialogData, - protected apiService: ApiService, - protected i18nService: I18nService, - private organizationUserApiService: OrganizationUserApiService, - ) { - this.organizationId = data.organizationId; - this.users = data.users; - this.showNoMasterPasswordWarning = this.users.some( - (u) => u.status > OrganizationUserStatusType.Invited && u.hasMasterPassword === false, - ); - } - - submit = async () => { - this.loading = true; - try { - const response = await this.removeUsers(); - - response.data.forEach((entry) => { - const error = entry.error !== "" ? entry.error : this.i18nService.t("bulkRemovedMessage"); - this.statuses.set(entry.id, error); - }); - this.done = true; - } catch (e) { - this.error = e.message; - } - - this.loading = false; - }; - - protected async removeUsers() { - return await this.organizationUserApiService.removeManyOrganizationUsers( - this.organizationId, - this.users.map((user) => user.id), - ); - } - - protected get removeUsersWarning() { - return this.i18nService.t("removeOrgUsersConfirmation"); - } - - static open(dialogService: DialogService, config: DialogConfig) { - return dialogService.open(BulkRemoveComponent, config); - } -} 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 3cc73c84a9..7ee99ff2e3 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 @@ -60,9 +60,9 @@ import { GroupService } from "../core"; import { OrganizationUserView } from "../core/views/organization-user.view"; import { openEntityEventsDialog } from "../manage/entity-events.component"; -import { BulkConfirmComponent } from "./components/bulk/bulk-confirm.component"; +import { BulkConfirmDialogComponent } from "./components/bulk/bulk-confirm-dialog.component"; import { BulkEnableSecretsManagerDialogComponent } from "./components/bulk/bulk-enable-sm-dialog.component"; -import { BulkRemoveComponent } from "./components/bulk/bulk-remove.component"; +import { BulkRemoveDialogComponent } from "./components/bulk/bulk-remove-dialog.component"; import { BulkRestoreRevokeComponent } from "./components/bulk/bulk-restore-revoke.component"; import { BulkStatusComponent } from "./components/bulk/bulk-status.component"; import { @@ -541,7 +541,7 @@ export class MembersComponent extends BaseMembersComponent return; } - const dialogRef = BulkRemoveComponent.open(this.dialogService, { + const dialogRef = BulkRemoveDialogComponent.open(this.dialogService, { data: { organizationId: this.organization.id, users: this.dataSource.getCheckedUsers(), @@ -620,7 +620,7 @@ export class MembersComponent extends BaseMembersComponent return; } - const dialogRef = BulkConfirmComponent.open(this.dialogService, { + const dialogRef = BulkConfirmDialogComponent.open(this.dialogService, { data: { organizationId: this.organization.id, users: this.dataSource.getCheckedUsers(), 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 d849b1f1f3..d7c5a9bf1d 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 @@ -7,9 +7,9 @@ import { PasswordCalloutComponent } from "@bitwarden/auth/angular"; import { LooseComponentsModule } from "../../../shared"; import { SharedOrganizationModule } from "../shared"; -import { BulkConfirmComponent } from "./components/bulk/bulk-confirm.component"; +import { BulkConfirmDialogComponent } from "./components/bulk/bulk-confirm-dialog.component"; import { BulkEnableSecretsManagerDialogComponent } from "./components/bulk/bulk-enable-sm-dialog.component"; -import { BulkRemoveComponent } from "./components/bulk/bulk-remove.component"; +import { BulkRemoveDialogComponent } from "./components/bulk/bulk-remove-dialog.component"; import { BulkRestoreRevokeComponent } from "./components/bulk/bulk-restore-revoke.component"; import { BulkStatusComponent } from "./components/bulk/bulk-status.component"; import { UserDialogModule } from "./components/member-dialog"; @@ -28,9 +28,9 @@ import { MembersComponent } from "./members.component"; PasswordStrengthV2Component, ], declarations: [ - BulkConfirmComponent, + BulkConfirmDialogComponent, BulkEnableSecretsManagerDialogComponent, - BulkRemoveComponent, + BulkRemoveDialogComponent, BulkRestoreRevokeComponent, BulkStatusComponent, MembersComponent, diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/bulk/bulk-confirm.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/bulk/bulk-confirm.component.ts deleted file mode 100644 index 918673e63f..0000000000 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/bulk/bulk-confirm.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Component, Input } from "@angular/core"; - -import { ProviderUserStatusType } from "@bitwarden/common/admin-console/enums"; -import { ProviderUserBulkConfirmRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-user-bulk-confirm.request"; -import { ProviderUserBulkRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-user-bulk.request"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; -import { BulkConfirmComponent as OrganizationBulkConfirmComponent } from "@bitwarden/web-vault/app/admin-console/organizations/members/components/bulk/bulk-confirm.component"; -import { BulkUserDetails } from "@bitwarden/web-vault/app/admin-console/organizations/members/components/bulk/bulk-status.component"; - -/** - * @deprecated Please use the {@link BulkConfirmDialogComponent} instead. - */ -@Component({ - templateUrl: - "../../../../../../../../apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.html", -}) -export class BulkConfirmComponent extends OrganizationBulkConfirmComponent { - @Input() providerId: string; - - protected override isAccepted(user: BulkUserDetails) { - return user.status === ProviderUserStatusType.Accepted; - } - - protected override async getPublicKeys() { - const request = new ProviderUserBulkRequest(this.filteredUsers.map((user) => user.id)); - return await this.apiService.postProviderUsersPublicKey(this.providerId, request); - } - - protected override getCryptoKey(): Promise { - return this.cryptoService.getProviderKey(this.providerId); - } - - protected override async postConfirmRequest(userIdsWithKeys: any[]) { - const request = new ProviderUserBulkConfirmRequest(userIdsWithKeys); - return await this.apiService.postProviderUserBulkConfirm(this.providerId, request); - } -} diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/bulk/bulk-remove.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/bulk/bulk-remove.component.ts deleted file mode 100644 index ea3ea9b596..0000000000 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/bulk/bulk-remove.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Component, Input } from "@angular/core"; - -import { ProviderUserBulkRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-user-bulk.request"; -import { BulkRemoveComponent as OrganizationBulkRemoveComponent } from "@bitwarden/web-vault/app/admin-console/organizations/members/components/bulk/bulk-remove.component"; - -/** - * @deprecated Please use the {@link BulkRemoveDialogComponent} instead. - */ -@Component({ - templateUrl: - "../../../../../../../../apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.html", -}) -export class BulkRemoveComponent extends OrganizationBulkRemoveComponent { - @Input() providerId: string; - - async deleteUsers() { - const request = new ProviderUserBulkRequest(this.users.map((user) => user.id)); - return await this.apiService.deleteManyProviderUsers(this.providerId, request); - } - - protected get removeUsersWarning() { - return this.i18nService.t("removeUsersWarning"); - } -} diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/dialogs/bulk-confirm-dialog.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/dialogs/bulk-confirm-dialog.component.ts index 8a04cb6452..61145efb78 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/dialogs/bulk-confirm-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/dialogs/bulk-confirm-dialog.component.ts @@ -27,7 +27,7 @@ type BulkConfirmDialogParams = { @Component({ templateUrl: - "../../../../../../../../apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.html", + "../../../../../../../../apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm-dialog.component.html", }) export class BulkConfirmDialogComponent extends BaseBulkConfirmComponent { providerId: string; diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/dialogs/bulk-remove-dialog.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/dialogs/bulk-remove-dialog.component.ts index 16e6470370..b5d5274498 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/dialogs/bulk-remove-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/dialogs/bulk-remove-dialog.component.ts @@ -17,7 +17,7 @@ type BulkRemoveDialogParams = { @Component({ templateUrl: - "../../../../../../../../apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.html", + "../../../../../../../../apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove-dialog.component.html", }) export class BulkRemoveDialogComponent extends BaseBulkRemoveComponent { providerId: string; diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.html b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.html deleted file mode 100644 index 36bc654369..0000000000 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - -
- - - {{ "all" | i18n }} - {{ allCount }} - - - - {{ "invited" | i18n }} - {{ invitedCount }} - - - - {{ "needsConfirmation" | i18n }} - {{ acceptedCount }} - - - - -
- - - - {{ "loading" | i18n }} - - -

{{ "noUsersInList" | i18n }}

- - - {{ "providerUsersNeedConfirmed" | i18n }} - - - - - - - - - - - - -
- - - - - {{ u.email }} - {{ - "invited" | i18n - }} - {{ - "needsConfirmation" | i18n - }} - {{ u.name }} - - - - {{ "userUsingTwoStep" | i18n }} - - - {{ "providerAdmin" | i18n }} - {{ "serviceUser" | i18n }} - - -
-
-
- - - - - diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.ts deleted file mode 100644 index 9293f8c6eb..0000000000 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.ts +++ /dev/null @@ -1,267 +0,0 @@ -import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core"; -import { ActivatedRoute, Router } from "@angular/router"; -import { lastValueFrom } from "rxjs"; -import { first } from "rxjs/operators"; - -import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe"; -import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe"; -import { ModalService } from "@bitwarden/angular/services/modal.service"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service"; -import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service"; -import { ProviderUserStatusType, ProviderUserType } from "@bitwarden/common/admin-console/enums"; -import { ProviderUserBulkRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-user-bulk.request"; -import { ProviderUserConfirmRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-user-confirm.request"; -import { ProviderUserUserDetailsResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-user.response"; -import { ListResponse } from "@bitwarden/common/models/response/list.response"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; -import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; -import { DialogService, ToastService } from "@bitwarden/components"; -import { BasePeopleComponent } from "@bitwarden/web-vault/app/admin-console/common/base.people.component"; -import { openEntityEventsDialog } from "@bitwarden/web-vault/app/admin-console/organizations/manage/entity-events.component"; -import { BulkStatusComponent } from "@bitwarden/web-vault/app/admin-console/organizations/members/components/bulk/bulk-status.component"; - -import { BulkConfirmComponent } from "./bulk/bulk-confirm.component"; -import { BulkRemoveComponent } from "./bulk/bulk-remove.component"; -import { UserAddEditComponent } from "./user-add-edit.component"; - -/** - * @deprecated Please use the {@link MembersComponent} instead. - */ -@Component({ - selector: "provider-people", - templateUrl: "people.component.html", -}) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class PeopleComponent - extends BasePeopleComponent - implements OnInit -{ - @ViewChild("addEdit", { read: ViewContainerRef, static: true }) addEditModalRef: ViewContainerRef; - @ViewChild("groupsTemplate", { read: ViewContainerRef, static: true }) - groupsModalRef: ViewContainerRef; - @ViewChild("bulkStatusTemplate", { read: ViewContainerRef, static: true }) - bulkStatusModalRef: ViewContainerRef; - @ViewChild("bulkConfirmTemplate", { read: ViewContainerRef, static: true }) - bulkConfirmModalRef: ViewContainerRef; - @ViewChild("bulkRemoveTemplate", { read: ViewContainerRef, static: true }) - bulkRemoveModalRef: ViewContainerRef; - - userType = ProviderUserType; - userStatusType = ProviderUserStatusType; - status: ProviderUserStatusType = null; - providerId: string; - accessEvents = false; - - constructor( - apiService: ApiService, - private route: ActivatedRoute, - i18nService: I18nService, - modalService: ModalService, - platformUtilsService: PlatformUtilsService, - cryptoService: CryptoService, - private encryptService: EncryptService, - private router: Router, - searchService: SearchService, - validationService: ValidationService, - logService: LogService, - searchPipe: SearchPipe, - userNamePipe: UserNamePipe, - private providerService: ProviderService, - dialogService: DialogService, - organizationManagementPreferencesService: OrganizationManagementPreferencesService, - private configService: ConfigService, - protected toastService: ToastService, - ) { - super( - apiService, - searchService, - i18nService, - platformUtilsService, - cryptoService, - validationService, - modalService, - logService, - searchPipe, - userNamePipe, - dialogService, - organizationManagementPreferencesService, - toastService, - ); - } - - ngOnInit() { - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.parent.params.subscribe(async (params) => { - this.providerId = params.providerId; - const provider = await this.providerService.get(this.providerId); - - if (!provider.canManageUsers) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["../"], { relativeTo: this.route }); - return; - } - - this.accessEvents = provider.useEvents; - - await this.load(); - - /* eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe, rxjs/no-nested-subscribe */ - this.route.queryParams.pipe(first()).subscribe(async (qParams) => { - this.searchControl.setValue(qParams.search); - if (qParams.viewEvents != null) { - const user = this.users.filter((u) => u.id === qParams.viewEvents); - if (user.length > 0 && user[0].status === ProviderUserStatusType.Confirmed) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.events(user[0]); - } - } - }); - }); - } - - getUsers(): Promise> { - return this.apiService.getProviderUsers(this.providerId); - } - - deleteUser(id: string): Promise { - return this.apiService.deleteProviderUser(this.providerId, id); - } - - revokeUser(id: string): Promise { - // Not implemented. - return null; - } - - restoreUser(id: string): Promise { - // Not implemented. - return null; - } - - reinviteUser(id: string): Promise { - return this.apiService.postProviderUserReinvite(this.providerId, id); - } - - async confirmUser(user: ProviderUserUserDetailsResponse, publicKey: Uint8Array): Promise { - const providerKey = await this.cryptoService.getProviderKey(this.providerId); - const key = await this.encryptService.rsaEncrypt(providerKey.key, publicKey); - const request = new ProviderUserConfirmRequest(); - request.key = key.encryptedString; - await this.apiService.postProviderUserConfirm(this.providerId, user.id, request); - } - - async edit(user: ProviderUserUserDetailsResponse) { - const [modal] = await this.modalService.openViewRef( - UserAddEditComponent, - this.addEditModalRef, - (comp) => { - comp.name = this.userNamePipe.transform(user); - comp.providerId = this.providerId; - comp.providerUserId = user != null ? user.id : null; - comp.savedUser.subscribe(() => { - modal.close(); - this.load(); - }); - comp.deletedUser.subscribe(() => { - modal.close(); - this.removeUser(user); - }); - }, - ); - } - - async events(user: ProviderUserUserDetailsResponse) { - await openEntityEventsDialog(this.dialogService, { - data: { - name: this.userNamePipe.transform(user), - providerId: this.providerId, - entityId: user.id, - showUser: false, - entity: "user", - }, - }); - } - - async bulkRemove() { - if (this.actionPromise != null) { - return; - } - - const [modal] = await this.modalService.openViewRef( - BulkRemoveComponent, - this.bulkRemoveModalRef, - (comp) => { - comp.providerId = this.providerId; - comp.users = this.getCheckedUsers(); - }, - ); - - await modal.onClosedPromise(); - await this.load(); - } - - async bulkReinvite() { - if (this.actionPromise != null) { - return; - } - - const users = this.getCheckedUsers(); - const filteredUsers = users.filter((u) => u.status === ProviderUserStatusType.Invited); - - if (filteredUsers.length <= 0) { - this.toastService.showToast({ - variant: "error", - title: this.i18nService.t("errorOccurred"), - message: this.i18nService.t("noSelectedUsersApplicable"), - }); - return; - } - - try { - const request = new ProviderUserBulkRequest(filteredUsers.map((user) => user.id)); - const response = this.apiService.postManyProviderUserReinvite(this.providerId, request); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - - // Bulk Status component open - const dialogRef = BulkStatusComponent.open(this.dialogService, { - data: { - users: users, - filteredUsers: filteredUsers, - request: response, - successfulMessage: this.i18nService.t("bulkReinviteMessage"), - }, - }); - await lastValueFrom(dialogRef.closed); - } catch (e) { - this.validationService.showError(e); - } - this.actionPromise = null; - } - - async bulkConfirm() { - if (this.actionPromise != null) { - return; - } - - const [modal] = await this.modalService.openViewRef( - BulkConfirmComponent, - this.bulkConfirmModalRef, - (comp) => { - comp.providerId = this.providerId; - comp.users = this.getCheckedUsers(); - }, - ); - - await modal.onClosedPromise(); - await this.load(); - } -} diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html index 5f9b3f66bc..0536221caf 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html @@ -13,7 +13,7 @@ route="manage" *ngIf="showManageTab(provider)" > - + provider.canManageUsers), - ], - data: { - titleId: "people", - }, + { + path: "members", + component: MembersComponent, + canActivate: [ + providerPermissionsGuard((provider: Provider) => provider.canManageUsers), + ], + data: { + titleId: "members", }, - }), + }, { path: "events", component: EventsComponent, diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts index 8ed10a2d6e..b6c7125c48 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts @@ -24,14 +24,11 @@ import { AddOrganizationComponent } from "./clients/add-organization.component"; import { ClientsComponent } from "./clients/clients.component"; import { CreateOrganizationComponent } from "./clients/create-organization.component"; import { AcceptProviderComponent } from "./manage/accept-provider.component"; -import { BulkConfirmComponent } from "./manage/bulk/bulk-confirm.component"; -import { BulkRemoveComponent } from "./manage/bulk/bulk-remove.component"; import { AddEditMemberDialogComponent } from "./manage/dialogs/add-edit-member-dialog.component"; import { BulkConfirmDialogComponent } from "./manage/dialogs/bulk-confirm-dialog.component"; import { BulkRemoveDialogComponent } from "./manage/dialogs/bulk-remove-dialog.component"; import { EventsComponent } from "./manage/events.component"; import { MembersComponent } from "./manage/members.component"; -import { PeopleComponent } from "./manage/people.component"; import { UserAddEditComponent } from "./manage/user-add-edit.component"; import { ProvidersLayoutComponent } from "./providers-layout.component"; import { ProvidersRoutingModule } from "./providers-routing.module"; @@ -58,14 +55,11 @@ import { SetupComponent } from "./setup/setup.component"; AcceptProviderComponent, AccountComponent, AddOrganizationComponent, - BulkConfirmComponent, BulkConfirmDialogComponent, - BulkRemoveComponent, BulkRemoveDialogComponent, ClientsComponent, CreateOrganizationComponent, EventsComponent, - PeopleComponent, MembersComponent, SetupComponent, SetupProviderComponent, diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index fd3833d10e..905d729948 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -20,7 +20,7 @@ export enum FeatureFlag { EnableTimeThreshold = "PM-5864-dollar-threshold", InlineMenuPositioningImprovements = "inline-menu-positioning-improvements", ProviderClientVaultPrivacyBanner = "ac-2833-provider-client-vault-privacy-banner", - AC2828_ProviderPortalMembersPage = "AC-2828_provider-portal-members-page", + VaultBulkManagementAction = "vault-bulk-management-action", IdpAutoSubmitLogin = "idp-auto-submit-login", UnauthenticatedExtensionUIRefresh = "unauth-ui-refresh", EnableUpgradePasswordManagerSub = "AC-2708-upgrade-password-manager-sub", @@ -67,7 +67,7 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.EnableTimeThreshold]: FALSE, [FeatureFlag.InlineMenuPositioningImprovements]: FALSE, [FeatureFlag.ProviderClientVaultPrivacyBanner]: FALSE, - [FeatureFlag.AC2828_ProviderPortalMembersPage]: FALSE, + [FeatureFlag.VaultBulkManagementAction]: FALSE, [FeatureFlag.IdpAutoSubmitLogin]: FALSE, [FeatureFlag.UnauthenticatedExtensionUIRefresh]: FALSE, [FeatureFlag.EnableUpgradePasswordManagerSub]: FALSE,