mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-25 12:15:18 +01:00
[PM-12425] Remove FF: AC-2828_provider-portal-members-page (#11241)
* Remove FF: AC-2828_provider-portal-members-page * Thomas' feedback: Fix provider layout
This commit is contained in:
parent
9a1879b96c
commit
470ddf79ab
@ -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<OrgKey>;
|
||||||
|
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<SymmetricCryptoKey> =>
|
||||||
|
await firstValueFrom(this.organizationKey$);
|
||||||
|
|
||||||
|
protected getPublicKeys = async (): Promise<
|
||||||
|
ListResponse<OrganizationUserBulkPublicKeyResponse | ProviderUserBulkPublicKeyResponse>
|
||||||
|
> =>
|
||||||
|
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<ListResponse<OrganizationUserBulkResponse | ProviderUserBulkResponse>> => {
|
||||||
|
const request = new OrganizationUserBulkConfirmRequest(userIdsWithKeys);
|
||||||
|
return await this.organizationUserApiService.postOrganizationUserBulkConfirm(
|
||||||
|
this.organizationId,
|
||||||
|
request,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
static open(dialogService: DialogService, config: DialogConfig<BulkConfirmDialogParams>) {
|
||||||
|
return dialogService.open(BulkConfirmDialogComponent, config);
|
||||||
|
}
|
||||||
|
}
|
@ -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<string, Uint8Array> = new Map();
|
|
||||||
fingerprints: Map<string, string> = new Map();
|
|
||||||
statuses: Map<string, string> = 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<SymmetricCryptoKey> {
|
|
||||||
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<BulkConfirmDialogData>) {
|
|
||||||
return dialogService.open(BulkConfirmComponent, config);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<ListResponse<OrganizationUserBulkResponse>> =>
|
||||||
|
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<BulkRemoveDialogParams>) {
|
||||||
|
return dialogService.open(BulkRemoveDialogComponent, config);
|
||||||
|
}
|
||||||
|
}
|
@ -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<string, string> = 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<BulkRemoveDialogData>) {
|
|
||||||
return dialogService.open(BulkRemoveComponent, config);
|
|
||||||
}
|
|
||||||
}
|
|
@ -60,9 +60,9 @@ import { GroupService } from "../core";
|
|||||||
import { OrganizationUserView } from "../core/views/organization-user.view";
|
import { OrganizationUserView } from "../core/views/organization-user.view";
|
||||||
import { openEntityEventsDialog } from "../manage/entity-events.component";
|
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 { 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 { BulkRestoreRevokeComponent } from "./components/bulk/bulk-restore-revoke.component";
|
||||||
import { BulkStatusComponent } from "./components/bulk/bulk-status.component";
|
import { BulkStatusComponent } from "./components/bulk/bulk-status.component";
|
||||||
import {
|
import {
|
||||||
@ -541,7 +541,7 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dialogRef = BulkRemoveComponent.open(this.dialogService, {
|
const dialogRef = BulkRemoveDialogComponent.open(this.dialogService, {
|
||||||
data: {
|
data: {
|
||||||
organizationId: this.organization.id,
|
organizationId: this.organization.id,
|
||||||
users: this.dataSource.getCheckedUsers(),
|
users: this.dataSource.getCheckedUsers(),
|
||||||
@ -620,7 +620,7 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dialogRef = BulkConfirmComponent.open(this.dialogService, {
|
const dialogRef = BulkConfirmDialogComponent.open(this.dialogService, {
|
||||||
data: {
|
data: {
|
||||||
organizationId: this.organization.id,
|
organizationId: this.organization.id,
|
||||||
users: this.dataSource.getCheckedUsers(),
|
users: this.dataSource.getCheckedUsers(),
|
||||||
|
@ -7,9 +7,9 @@ import { PasswordCalloutComponent } from "@bitwarden/auth/angular";
|
|||||||
import { LooseComponentsModule } from "../../../shared";
|
import { LooseComponentsModule } from "../../../shared";
|
||||||
import { SharedOrganizationModule } 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 { 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 { BulkRestoreRevokeComponent } from "./components/bulk/bulk-restore-revoke.component";
|
||||||
import { BulkStatusComponent } from "./components/bulk/bulk-status.component";
|
import { BulkStatusComponent } from "./components/bulk/bulk-status.component";
|
||||||
import { UserDialogModule } from "./components/member-dialog";
|
import { UserDialogModule } from "./components/member-dialog";
|
||||||
@ -28,9 +28,9 @@ import { MembersComponent } from "./members.component";
|
|||||||
PasswordStrengthV2Component,
|
PasswordStrengthV2Component,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
BulkConfirmComponent,
|
BulkConfirmDialogComponent,
|
||||||
BulkEnableSecretsManagerDialogComponent,
|
BulkEnableSecretsManagerDialogComponent,
|
||||||
BulkRemoveComponent,
|
BulkRemoveDialogComponent,
|
||||||
BulkRestoreRevokeComponent,
|
BulkRestoreRevokeComponent,
|
||||||
BulkStatusComponent,
|
BulkStatusComponent,
|
||||||
MembersComponent,
|
MembersComponent,
|
||||||
|
@ -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<SymmetricCryptoKey> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
@ -27,7 +27,7 @@ type BulkConfirmDialogParams = {
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl:
|
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 {
|
export class BulkConfirmDialogComponent extends BaseBulkConfirmComponent {
|
||||||
providerId: string;
|
providerId: string;
|
||||||
|
@ -17,7 +17,7 @@ type BulkRemoveDialogParams = {
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl:
|
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 {
|
export class BulkRemoveDialogComponent extends BaseBulkRemoveComponent {
|
||||||
providerId: string;
|
providerId: string;
|
||||||
|
@ -1,203 +0,0 @@
|
|||||||
<app-header>
|
|
||||||
<bit-search
|
|
||||||
class="tw-grow"
|
|
||||||
[formControl]="searchControl"
|
|
||||||
[placeholder]="'search' | i18n"
|
|
||||||
></bit-search>
|
|
||||||
<button type="button" bitButton buttonType="primary" (click)="invite()">
|
|
||||||
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
|
|
||||||
{{ "inviteMember" | i18n }}
|
|
||||||
</button>
|
|
||||||
</app-header>
|
|
||||||
|
|
||||||
<div class="ml-auto d-flex tw-mb-4">
|
|
||||||
<bit-toggle-group
|
|
||||||
[selected]="status"
|
|
||||||
(selectedChange)="filter($event)"
|
|
||||||
[attr.aria-label]="'memberStatusFilter' | i18n"
|
|
||||||
>
|
|
||||||
<bit-toggle [value]="null">
|
|
||||||
{{ "all" | i18n }}
|
|
||||||
<span bitBadge variant="info" *ngIf="allCount">{{ allCount }}</span>
|
|
||||||
</bit-toggle>
|
|
||||||
|
|
||||||
<bit-toggle [value]="userStatusType.Invited">
|
|
||||||
{{ "invited" | i18n }}
|
|
||||||
<span bitBadge variant="info" *ngIf="invitedCount">{{ invitedCount }}</span>
|
|
||||||
</bit-toggle>
|
|
||||||
|
|
||||||
<bit-toggle [value]="userStatusType.Accepted">
|
|
||||||
{{ "needsConfirmation" | i18n }}
|
|
||||||
<span bitBadge variant="warning" *ngIf="acceptedCount">{{ acceptedCount }}</span>
|
|
||||||
</bit-toggle>
|
|
||||||
</bit-toggle-group>
|
|
||||||
|
|
||||||
<div class="dropdown ml-3" appListDropdown>
|
|
||||||
<button
|
|
||||||
class="btn btn-outline-secondary dropdown-toggle"
|
|
||||||
type="button"
|
|
||||||
id="bulkActionsButton"
|
|
||||||
data-toggle="dropdown"
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-expanded="false"
|
|
||||||
appA11yTitle="{{ 'options' | i18n }}"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-cog" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="bulkActionsButton">
|
|
||||||
<button type="button" class="dropdown-item" appStopClick (click)="bulkReinvite()">
|
|
||||||
<i class="bwi bwi-fw bwi-envelope" aria-hidden="true"></i>
|
|
||||||
{{ "reinviteSelected" | i18n }}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="dropdown-item text-success"
|
|
||||||
appStopClick
|
|
||||||
(click)="bulkConfirm()"
|
|
||||||
*ngIf="showBulkConfirmUsers"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-fw bwi-check" aria-hidden="true"></i>
|
|
||||||
{{ "confirmSelected" | i18n }}
|
|
||||||
</button>
|
|
||||||
<button type="button" class="dropdown-item text-danger" appStopClick (click)="bulkRemove()">
|
|
||||||
<i class="bwi bwi-fw bwi-close" aria-hidden="true"></i>
|
|
||||||
{{ "remove" | i18n }}
|
|
||||||
</button>
|
|
||||||
<div class="dropdown-divider"></div>
|
|
||||||
<button type="button" class="dropdown-item" appStopClick (click)="selectAll(true)">
|
|
||||||
<i class="bwi bwi-fw bwi-check-square" aria-hidden="true"></i>
|
|
||||||
{{ "selectAll" | i18n }}
|
|
||||||
</button>
|
|
||||||
<button type="button" class="dropdown-item" appStopClick (click)="selectAll(false)">
|
|
||||||
<i class="bwi bwi-fw bwi-minus-square" aria-hidden="true"></i>
|
|
||||||
{{ "unselectAll" | i18n }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ng-container *ngIf="loading">
|
|
||||||
<i
|
|
||||||
class="bwi bwi-spinner bwi-spin text-muted"
|
|
||||||
title="{{ 'loading' | i18n }}"
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container
|
|
||||||
*ngIf="
|
|
||||||
!loading &&
|
|
||||||
((isPaging$ | async)
|
|
||||||
? pagedUsers
|
|
||||||
: (users | search: searchControl.value : 'name' : 'email' : 'id')) as searchedUsers
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<p *ngIf="!searchedUsers.length">{{ "noUsersInList" | i18n }}</p>
|
|
||||||
<ng-container *ngIf="searchedUsers.length">
|
|
||||||
<app-callout
|
|
||||||
type="info"
|
|
||||||
title="{{ 'confirmUsers' | i18n }}"
|
|
||||||
icon="bwi bwi-check-circle"
|
|
||||||
*ngIf="showConfirmUsers"
|
|
||||||
>
|
|
||||||
{{ "providerUsersNeedConfirmed" | i18n }}
|
|
||||||
</app-callout>
|
|
||||||
<table
|
|
||||||
class="table table-hover table-list"
|
|
||||||
infiniteScroll
|
|
||||||
[infiniteScrollDistance]="1"
|
|
||||||
[infiniteScrollDisabled]="!(isPaging$ | async)"
|
|
||||||
(scrolled)="loadMore()"
|
|
||||||
>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let u of searchedUsers">
|
|
||||||
<td (click)="checkUser(u)" class="table-list-checkbox">
|
|
||||||
<input type="checkbox" [(ngModel)]="$any(u).checked" appStopProp />
|
|
||||||
</td>
|
|
||||||
<td width="30">
|
|
||||||
<bit-avatar [text]="u | userName" [id]="u.userId" size="small"></bit-avatar>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a href="#" appStopClick (click)="edit(u)">{{ u.email }}</a>
|
|
||||||
<span bitBadge variant="secondary" *ngIf="u.status === userStatusType.Invited">{{
|
|
||||||
"invited" | i18n
|
|
||||||
}}</span>
|
|
||||||
<span bitBadge variant="warning" *ngIf="u.status === userStatusType.Accepted">{{
|
|
||||||
"needsConfirmation" | i18n
|
|
||||||
}}</span>
|
|
||||||
<small class="text-muted d-block" *ngIf="u.name">{{ u.name }}</small>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<ng-container *ngIf="$any(u).twoFactorEnabled">
|
|
||||||
<i
|
|
||||||
class="bwi bwi-lock"
|
|
||||||
title="{{ 'userUsingTwoStep' | i18n }}"
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
<span class="tw-sr-only">{{ "userUsingTwoStep" | i18n }}</span>
|
|
||||||
</ng-container>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span *ngIf="u.type === userType.ProviderAdmin">{{ "providerAdmin" | i18n }}</span>
|
|
||||||
<span *ngIf="u.type === userType.ServiceUser">{{ "serviceUser" | i18n }}</span>
|
|
||||||
</td>
|
|
||||||
<td class="table-list-options">
|
|
||||||
<div class="dropdown" appListDropdown>
|
|
||||||
<button
|
|
||||||
class="btn btn-outline-secondary dropdown-toggle"
|
|
||||||
type="button"
|
|
||||||
data-toggle="dropdown"
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-expanded="false"
|
|
||||||
appA11yTitle="{{ 'options' | i18n }}"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-cog bwi-lg" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
<div class="dropdown-menu dropdown-menu-right">
|
|
||||||
<a
|
|
||||||
class="dropdown-item"
|
|
||||||
href="#"
|
|
||||||
appStopClick
|
|
||||||
(click)="reinvite(u)"
|
|
||||||
*ngIf="u.status === userStatusType.Invited"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-fw bwi-envelope" aria-hidden="true"></i>
|
|
||||||
{{ "resendInvitation" | i18n }}
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class="dropdown-item text-success"
|
|
||||||
href="#"
|
|
||||||
appStopClick
|
|
||||||
(click)="confirm(u)"
|
|
||||||
*ngIf="u.status === userStatusType.Accepted"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-fw bwi-check" aria-hidden="true"></i>
|
|
||||||
{{ "confirm" | i18n }}
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class="dropdown-item"
|
|
||||||
href="#"
|
|
||||||
appStopClick
|
|
||||||
(click)="events(u)"
|
|
||||||
*ngIf="accessEvents && u.status === userStatusType.Confirmed"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-fw bwi-file-text" aria-hidden="true"></i>
|
|
||||||
{{ "eventLogs" | i18n }}
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item text-danger" href="#" appStopClick (click)="remove(u)">
|
|
||||||
<i class="bwi bwi-fw bwi-close" aria-hidden="true"></i>
|
|
||||||
{{ "remove" | i18n }}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</ng-container>
|
|
||||||
</ng-container>
|
|
||||||
<ng-template #addEdit></ng-template>
|
|
||||||
<ng-template #confirmTemplate></ng-template>
|
|
||||||
<ng-template #bulkStatusTemplate></ng-template>
|
|
||||||
<ng-template #bulkConfirmTemplate></ng-template>
|
|
||||||
<ng-template #bulkRemoveTemplate></ng-template>
|
|
@ -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<ProviderUserUserDetailsResponse>
|
|
||||||
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<ListResponse<ProviderUserUserDetailsResponse>> {
|
|
||||||
return this.apiService.getProviderUsers(this.providerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteUser(id: string): Promise<any> {
|
|
||||||
return this.apiService.deleteProviderUser(this.providerId, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
revokeUser(id: string): Promise<any> {
|
|
||||||
// Not implemented.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
restoreUser(id: string): Promise<any> {
|
|
||||||
// Not implemented.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
reinviteUser(id: string): Promise<any> {
|
|
||||||
return this.apiService.postProviderUserReinvite(this.providerId, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
async confirmUser(user: ProviderUserUserDetailsResponse, publicKey: Uint8Array): Promise<any> {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,7 +13,7 @@
|
|||||||
route="manage"
|
route="manage"
|
||||||
*ngIf="showManageTab(provider)"
|
*ngIf="showManageTab(provider)"
|
||||||
>
|
>
|
||||||
<bit-nav-item [text]="'people' | i18n" route="manage/people"></bit-nav-item>
|
<bit-nav-item [text]="'members' | i18n" route="manage/members"></bit-nav-item>
|
||||||
<bit-nav-item
|
<bit-nav-item
|
||||||
[text]="'eventLogs' | i18n"
|
[text]="'eventLogs' | i18n"
|
||||||
route="manage/events"
|
route="manage/events"
|
||||||
|
@ -2,10 +2,8 @@ import { NgModule } from "@angular/core";
|
|||||||
import { RouterModule, Routes } from "@angular/router";
|
import { RouterModule, Routes } from "@angular/router";
|
||||||
|
|
||||||
import { authGuard } from "@bitwarden/angular/auth/guards";
|
import { authGuard } from "@bitwarden/angular/auth/guards";
|
||||||
import { featureFlaggedRoute } from "@bitwarden/angular/platform/utils/feature-flagged-route";
|
|
||||||
import { AnonLayoutWrapperComponent } from "@bitwarden/auth/angular";
|
import { AnonLayoutWrapperComponent } from "@bitwarden/auth/angular";
|
||||||
import { Provider } from "@bitwarden/common/admin-console/models/domain/provider";
|
import { Provider } from "@bitwarden/common/admin-console/models/domain/provider";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
|
||||||
import { ProvidersComponent } from "@bitwarden/web-vault/app/admin-console/providers/providers.component";
|
import { ProvidersComponent } from "@bitwarden/web-vault/app/admin-console/providers/providers.component";
|
||||||
import { FrontendLayoutComponent } from "@bitwarden/web-vault/app/layouts/frontend-layout.component";
|
import { FrontendLayoutComponent } from "@bitwarden/web-vault/app/layouts/frontend-layout.component";
|
||||||
import { UserLayoutComponent } from "@bitwarden/web-vault/app/layouts/user-layout.component";
|
import { UserLayoutComponent } from "@bitwarden/web-vault/app/layouts/user-layout.component";
|
||||||
@ -23,7 +21,6 @@ import { providerPermissionsGuard } from "./guards/provider-permissions.guard";
|
|||||||
import { AcceptProviderComponent } from "./manage/accept-provider.component";
|
import { AcceptProviderComponent } from "./manage/accept-provider.component";
|
||||||
import { EventsComponent } from "./manage/events.component";
|
import { EventsComponent } from "./manage/events.component";
|
||||||
import { MembersComponent } from "./manage/members.component";
|
import { MembersComponent } from "./manage/members.component";
|
||||||
import { PeopleComponent } from "./manage/people.component";
|
|
||||||
import { ProvidersLayoutComponent } from "./providers-layout.component";
|
import { ProvidersLayoutComponent } from "./providers-layout.component";
|
||||||
import { AccountComponent } from "./settings/account.component";
|
import { AccountComponent } from "./settings/account.component";
|
||||||
import { SetupProviderComponent } from "./setup/setup-provider.component";
|
import { SetupProviderComponent } from "./setup/setup-provider.component";
|
||||||
@ -98,22 +95,18 @@ const routes: Routes = [
|
|||||||
{
|
{
|
||||||
path: "",
|
path: "",
|
||||||
pathMatch: "full",
|
pathMatch: "full",
|
||||||
redirectTo: "people",
|
redirectTo: "members",
|
||||||
},
|
},
|
||||||
...featureFlaggedRoute({
|
{
|
||||||
defaultComponent: PeopleComponent,
|
path: "members",
|
||||||
flaggedComponent: MembersComponent,
|
component: MembersComponent,
|
||||||
featureFlag: FeatureFlag.AC2828_ProviderPortalMembersPage,
|
canActivate: [
|
||||||
routeOptions: {
|
providerPermissionsGuard((provider: Provider) => provider.canManageUsers),
|
||||||
path: "people",
|
],
|
||||||
canActivate: [
|
data: {
|
||||||
providerPermissionsGuard((provider: Provider) => provider.canManageUsers),
|
titleId: "members",
|
||||||
],
|
|
||||||
data: {
|
|
||||||
titleId: "people",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
{
|
{
|
||||||
path: "events",
|
path: "events",
|
||||||
component: EventsComponent,
|
component: EventsComponent,
|
||||||
|
@ -24,14 +24,11 @@ import { AddOrganizationComponent } from "./clients/add-organization.component";
|
|||||||
import { ClientsComponent } from "./clients/clients.component";
|
import { ClientsComponent } from "./clients/clients.component";
|
||||||
import { CreateOrganizationComponent } from "./clients/create-organization.component";
|
import { CreateOrganizationComponent } from "./clients/create-organization.component";
|
||||||
import { AcceptProviderComponent } from "./manage/accept-provider.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 { AddEditMemberDialogComponent } from "./manage/dialogs/add-edit-member-dialog.component";
|
||||||
import { BulkConfirmDialogComponent } from "./manage/dialogs/bulk-confirm-dialog.component";
|
import { BulkConfirmDialogComponent } from "./manage/dialogs/bulk-confirm-dialog.component";
|
||||||
import { BulkRemoveDialogComponent } from "./manage/dialogs/bulk-remove-dialog.component";
|
import { BulkRemoveDialogComponent } from "./manage/dialogs/bulk-remove-dialog.component";
|
||||||
import { EventsComponent } from "./manage/events.component";
|
import { EventsComponent } from "./manage/events.component";
|
||||||
import { MembersComponent } from "./manage/members.component";
|
import { MembersComponent } from "./manage/members.component";
|
||||||
import { PeopleComponent } from "./manage/people.component";
|
|
||||||
import { UserAddEditComponent } from "./manage/user-add-edit.component";
|
import { UserAddEditComponent } from "./manage/user-add-edit.component";
|
||||||
import { ProvidersLayoutComponent } from "./providers-layout.component";
|
import { ProvidersLayoutComponent } from "./providers-layout.component";
|
||||||
import { ProvidersRoutingModule } from "./providers-routing.module";
|
import { ProvidersRoutingModule } from "./providers-routing.module";
|
||||||
@ -58,14 +55,11 @@ import { SetupComponent } from "./setup/setup.component";
|
|||||||
AcceptProviderComponent,
|
AcceptProviderComponent,
|
||||||
AccountComponent,
|
AccountComponent,
|
||||||
AddOrganizationComponent,
|
AddOrganizationComponent,
|
||||||
BulkConfirmComponent,
|
|
||||||
BulkConfirmDialogComponent,
|
BulkConfirmDialogComponent,
|
||||||
BulkRemoveComponent,
|
|
||||||
BulkRemoveDialogComponent,
|
BulkRemoveDialogComponent,
|
||||||
ClientsComponent,
|
ClientsComponent,
|
||||||
CreateOrganizationComponent,
|
CreateOrganizationComponent,
|
||||||
EventsComponent,
|
EventsComponent,
|
||||||
PeopleComponent,
|
|
||||||
MembersComponent,
|
MembersComponent,
|
||||||
SetupComponent,
|
SetupComponent,
|
||||||
SetupProviderComponent,
|
SetupProviderComponent,
|
||||||
|
@ -20,7 +20,7 @@ export enum FeatureFlag {
|
|||||||
EnableTimeThreshold = "PM-5864-dollar-threshold",
|
EnableTimeThreshold = "PM-5864-dollar-threshold",
|
||||||
InlineMenuPositioningImprovements = "inline-menu-positioning-improvements",
|
InlineMenuPositioningImprovements = "inline-menu-positioning-improvements",
|
||||||
ProviderClientVaultPrivacyBanner = "ac-2833-provider-client-vault-privacy-banner",
|
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",
|
IdpAutoSubmitLogin = "idp-auto-submit-login",
|
||||||
UnauthenticatedExtensionUIRefresh = "unauth-ui-refresh",
|
UnauthenticatedExtensionUIRefresh = "unauth-ui-refresh",
|
||||||
EnableUpgradePasswordManagerSub = "AC-2708-upgrade-password-manager-sub",
|
EnableUpgradePasswordManagerSub = "AC-2708-upgrade-password-manager-sub",
|
||||||
@ -67,7 +67,7 @@ export const DefaultFeatureFlagValue = {
|
|||||||
[FeatureFlag.EnableTimeThreshold]: FALSE,
|
[FeatureFlag.EnableTimeThreshold]: FALSE,
|
||||||
[FeatureFlag.InlineMenuPositioningImprovements]: FALSE,
|
[FeatureFlag.InlineMenuPositioningImprovements]: FALSE,
|
||||||
[FeatureFlag.ProviderClientVaultPrivacyBanner]: FALSE,
|
[FeatureFlag.ProviderClientVaultPrivacyBanner]: FALSE,
|
||||||
[FeatureFlag.AC2828_ProviderPortalMembersPage]: FALSE,
|
[FeatureFlag.VaultBulkManagementAction]: FALSE,
|
||||||
[FeatureFlag.IdpAutoSubmitLogin]: FALSE,
|
[FeatureFlag.IdpAutoSubmitLogin]: FALSE,
|
||||||
[FeatureFlag.UnauthenticatedExtensionUIRefresh]: FALSE,
|
[FeatureFlag.UnauthenticatedExtensionUIRefresh]: FALSE,
|
||||||
[FeatureFlag.EnableUpgradePasswordManagerSub]: FALSE,
|
[FeatureFlag.EnableUpgradePasswordManagerSub]: FALSE,
|
||||||
|
Loading…
Reference in New Issue
Block a user