1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-22 11:45:59 +01:00

[PM-14554] Condition the display of members bulk actions based on selection (#11922)

* Refactor organization user API service to support bulk deletion of users

* Add copy for bulk user delete dialog

* Add bulk user delete dialog component

* Add bulk user delete functionality to members component

* Make bulk user actions in the members component conditional based on the selected members

* Refactor members component to only display bulk user deletion option if the Account Deprovisioning flag is enabled

* Refactor bulk action visibility in members component based on Account Deprovisioning flag

* Patch build process

* Refactor bulk action visibility conditions in members component

* Simplify status checks in members component by using loose equality and removing redundant boolean comparisons

* Refactor bulk action visibility logic in members component to use computed properties for improved readability and maintainability

* Refactor bulk action visibility logic in members component to eliminate redundant methods and improve readability

* Revert "Patch build process"

This reverts commit 917c969f00.

* Refactor bulk action visibility logic in members component

---------

Co-authored-by: Matt Bishop <mbishop@bitwarden.com>
This commit is contained in:
Rui Tomé 2024-11-22 10:42:45 +00:00 committed by GitHub
parent 587327bc4a
commit 773bdd2167
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 91 additions and 12 deletions

View File

@ -123,25 +123,40 @@
{{ "confirmSelected" | i18n }}
</span>
</button>
<button type="button" bitMenuItem (click)="bulkRestore()">
<button
type="button"
bitMenuItem
(click)="bulkRestore()"
*ngIf="showBulkRestoreUsers"
>
<i class="bwi bwi-fw bwi-plus-circle" aria-hidden="true"></i>
{{ "restoreAccess" | i18n }}
</button>
<button type="button" bitMenuItem (click)="bulkRevoke()">
<button
type="button"
bitMenuItem
(click)="bulkRevoke()"
*ngIf="showBulkRevokeUsers"
>
<i class="bwi bwi-fw bwi-minus-circle" aria-hidden="true"></i>
{{ "revokeAccess" | i18n }}
</button>
<button type="button" bitMenuItem (click)="bulkRemove()">
<button
type="button"
bitMenuItem
(click)="bulkRemove()"
*ngIf="showBulkRemoveUsers"
>
<span class="tw-text-danger">
<i aria-hidden="true" class="bwi bwi-close"></i>
{{ "remove" | i18n }}
</span>
</button>
<button
*ngIf="accountDeprovisioningEnabled$ | async"
type="button"
bitMenuItem
(click)="bulkDelete()"
*ngIf="showBulkDeleteUsers"
>
<span class="tw-text-danger">
<i aria-hidden="true" class="bwi bwi-trash"></i>
@ -327,7 +342,7 @@
{{ "revokeAccess" | i18n }}
</button>
<button
*ngIf="!(accountDeprovisioningEnabled$ | async) || !u.managedByOrganization"
*ngIf="!accountDeprovisioningEnabled || !u.managedByOrganization"
type="button"
bitMenuItem
(click)="remove(u)"
@ -337,7 +352,7 @@
</span>
</button>
<button
*ngIf="(accountDeprovisioningEnabled$ | async) && u.managedByOrganization"
*ngIf="accountDeprovisioningEnabled && u.managedByOrganization"
type="button"
bitMenuItem
(click)="deleteUser(u)"

View File

@ -1,4 +1,4 @@
import { Component, ViewChild, ViewContainerRef } from "@angular/core";
import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { ActivatedRoute, Router } from "@angular/router";
import {
@ -83,7 +83,7 @@ class MembersTableDataSource extends PeopleTableDataSource<OrganizationUserView>
@Component({
templateUrl: "members.component.html",
})
export class MembersComponent extends BaseMembersComponent<OrganizationUserView> {
export class MembersComponent extends BaseMembersComponent<OrganizationUserView> implements OnInit {
@ViewChild("resetPasswordTemplate", { read: ViewContainerRef, static: true })
resetPasswordModalRef: ViewContainerRef;
@ -96,13 +96,10 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
status: OrganizationUserStatusType = null;
orgResetPasswordPolicyEnabled = false;
orgIsOnSecretsManagerStandalone = false;
accountDeprovisioningEnabled = false;
protected canUseSecretsManager$: Observable<boolean>;
protected accountDeprovisioningEnabled$: Observable<boolean> = this.configService.getFeatureFlag$(
FeatureFlag.AccountDeprovisioning,
);
// Fixed sizes used for cdkVirtualScroll
protected rowHeight = 69;
protected rowHeightClass = `tw-h-[69px]`;
@ -216,6 +213,12 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
.subscribe();
}
async ngOnInit() {
this.accountDeprovisioningEnabled = await this.configService.getFeatureFlag(
FeatureFlag.AccountDeprovisioning,
);
}
async getUsers(): Promise<OrganizationUserView[]> {
let groupsPromise: Promise<Map<string, string>>;
let collectionsPromise: Promise<Map<string, string>>;
@ -779,4 +782,65 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
type: "warning",
});
}
get showBulkConfirmUsers(): boolean {
if (!this.accountDeprovisioningEnabled) {
return super.showBulkConfirmUsers;
}
return this.dataSource
.getCheckedUsers()
.every((member) => member.status == this.userStatusType.Accepted);
}
get showBulkReinviteUsers(): boolean {
if (!this.accountDeprovisioningEnabled) {
return super.showBulkReinviteUsers;
}
return this.dataSource
.getCheckedUsers()
.every((member) => member.status == this.userStatusType.Invited);
}
get showBulkRestoreUsers(): boolean {
return (
!this.accountDeprovisioningEnabled ||
this.dataSource
.getCheckedUsers()
.every((member) => member.status == this.userStatusType.Revoked)
);
}
get showBulkRevokeUsers(): boolean {
return (
!this.accountDeprovisioningEnabled ||
this.dataSource
.getCheckedUsers()
.every((member) => member.status != this.userStatusType.Revoked)
);
}
get showBulkRemoveUsers(): boolean {
return (
!this.accountDeprovisioningEnabled ||
this.dataSource.getCheckedUsers().every((member) => !member.managedByOrganization)
);
}
get showBulkDeleteUsers(): boolean {
if (!this.accountDeprovisioningEnabled) {
return false;
}
const validStatuses = [
this.userStatusType.Accepted,
this.userStatusType.Confirmed,
this.userStatusType.Revoked,
];
return this.dataSource
.getCheckedUsers()
.every((member) => member.managedByOrganization && validStatuses.includes(member.status));
}
}