bitwarden-estensione-browser/apps/web/src/app/organizations/manage/people.component.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

460 lines
16 KiB
TypeScript
Raw Normal View History

import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
2022-02-24 12:10:07 +01:00
import { first } from "rxjs/operators";
2018-07-06 21:01:23 +02:00
2022-06-14 17:10:53 +02:00
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 { ValidationService } from "@bitwarden/angular/services/validation.service";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyService } from "@bitwarden/common/abstractions/policy.service";
import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { StateService } from "@bitwarden/common/abstractions/state.service";
import { SyncService } from "@bitwarden/common/abstractions/sync.service";
import { OrganizationUserStatusType } from "@bitwarden/common/enums/organizationUserStatusType";
import { OrganizationUserType } from "@bitwarden/common/enums/organizationUserType";
import { PolicyType } from "@bitwarden/common/enums/policyType";
import { OrganizationKeysRequest } from "@bitwarden/common/models/request/organizationKeysRequest";
import { OrganizationUserBulkRequest } from "@bitwarden/common/models/request/organizationUserBulkRequest";
import { OrganizationUserConfirmRequest } from "@bitwarden/common/models/request/organizationUserConfirmRequest";
import { ListResponse } from "@bitwarden/common/models/response/listResponse";
import { OrganizationUserBulkResponse } from "@bitwarden/common/models/response/organizationUserBulkResponse";
import { OrganizationUserUserDetailsResponse } from "@bitwarden/common/models/response/organizationUserResponse";
2018-07-09 23:07:13 +02:00
import { BasePeopleComponent } from "../../common/base.people.component";
2022-02-24 12:10:07 +01:00
import { BulkConfirmComponent } from "./bulk/bulk-confirm.component";
import { BulkDeactivateComponent } from "./bulk/bulk-deactivate.component";
import { BulkRemoveComponent } from "./bulk/bulk-remove.component";
import { BulkStatusComponent } from "./bulk/bulk-status.component";
import { EntityEventsComponent } from "./entity-events.component";
import { ResetPasswordComponent } from "./reset-password.component";
import { UserAddEditComponent } from "./user-add-edit.component";
import { UserGroupsComponent } from "./user-groups.component";
@Component({
selector: "app-org-people",
2018-07-06 16:21:08 +02:00
templateUrl: "people.component.html",
})
export class PeopleComponent
extends BasePeopleComponent<OrganizationUserUserDetailsResponse>
implements OnInit
2021-12-17 15:57:11 +01:00
{
@ViewChild("addEdit", { read: ViewContainerRef, static: true }) addEditModalRef: ViewContainerRef;
@ViewChild("groupsTemplate", { read: ViewContainerRef, static: true })
groupsModalRef: ViewContainerRef;
@ViewChild("eventsTemplate", { read: ViewContainerRef, static: true })
eventsModalRef: ViewContainerRef;
@ViewChild("confirmTemplate", { read: ViewContainerRef, static: true })
confirmModalRef: ViewContainerRef;
@ViewChild("resetPasswordTemplate", { read: ViewContainerRef, static: true })
resetPasswordModalRef: 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;
2021-12-17 15:57:11 +01:00
userType = OrganizationUserType;
userStatusType = OrganizationUserStatusType;
2021-12-17 15:57:11 +01:00
2018-07-06 21:01:23 +02:00
organizationId: string;
2018-07-11 22:40:32 +02:00
status: OrganizationUserStatusType = null;
2018-07-11 20:43:00 +02:00
accessEvents = false;
accessGroups = false;
canResetPassword = false; // User permission (admin/custom)
orgUseResetPassword = false; // Org plan ability
orgHasKeys = false; // Org public/private keys
orgResetPasswordPolicyEnabled = false;
callingUserType: OrganizationUserType = null;
2021-12-17 15:57:11 +01:00
constructor(
apiService: ApiService,
[Account Switching] [Refactor] Implement new account centric services (#1220) * [chore] updated services.module to use account services * [refactor] sorted services provided by services.module * [chore] removed references to deleted jslib services * [chore] used activeAccount over storageService for account level storage items * [chore] resolved linter warnings * Refactor activeAccountService to stateService * [bug] Remove uneeded calls to state service on logout This was causing console erros on logout. Clearing of data is handled fully in dedicated services, clearing them in state afterwards is essentially a redundant call. * [bug] Add back null locked callback to VaultTimeoutService * Move call to get showUpdateKey * [bug] Ensure HtmlStorageService does not override StateService options and locations * [bug] Adjust theme logic to pull from the new storage locations * [bug] Correct theme not sticking on refresh * [bug] Add enableFullWidth to the account model * [bug] fix theme option empty when light is selected * [bug] init state on application start * [bug] Reinit state when coming back from a lock * [style] Fix lint complaints * [bug] Clean state on logout * [chore] Resolved merge issues * [bug] Correct default for enableGravitars * Bump angular to 12. * Remove angular.json * Bump rxjs * Fix build errors, remove file-loader with asset/resource * Use contenthash * Bump jslib * Bump ngx-toastr * [chore] resolve issues from merge * [chore] resolve issues from merge * [bug] Add missing bracket * Use newer import syntax * [bug] Correct service orge * [style] Fix lint complaints * [chore] update jslib * [review] Address code review * [review] Address code review * [review] Rename providerService to webProviderService Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com> Co-authored-by: Hinton <oscar@oscarhinton.com>
2021-12-14 17:10:26 +01:00
private route: ActivatedRoute,
i18nService: I18nService,
modalService: ModalService,
platformUtilsService: PlatformUtilsService,
cryptoService: CryptoService,
private router: Router,
[Account Switching] [Refactor] Implement new account centric services (#1220) * [chore] updated services.module to use account services * [refactor] sorted services provided by services.module * [chore] removed references to deleted jslib services * [chore] used activeAccount over storageService for account level storage items * [chore] resolved linter warnings * Refactor activeAccountService to stateService * [bug] Remove uneeded calls to state service on logout This was causing console erros on logout. Clearing of data is handled fully in dedicated services, clearing them in state afterwards is essentially a redundant call. * [bug] Add back null locked callback to VaultTimeoutService * Move call to get showUpdateKey * [bug] Ensure HtmlStorageService does not override StateService options and locations * [bug] Adjust theme logic to pull from the new storage locations * [bug] Correct theme not sticking on refresh * [bug] Add enableFullWidth to the account model * [bug] fix theme option empty when light is selected * [bug] init state on application start * [bug] Reinit state when coming back from a lock * [style] Fix lint complaints * [bug] Clean state on logout * [chore] Resolved merge issues * [bug] Correct default for enableGravitars * Bump angular to 12. * Remove angular.json * Bump rxjs * Fix build errors, remove file-loader with asset/resource * Use contenthash * Bump jslib * Bump ngx-toastr * [chore] resolve issues from merge * [chore] resolve issues from merge * [bug] Add missing bracket * Use newer import syntax * [bug] Correct service orge * [style] Fix lint complaints * [chore] update jslib * [review] Address code review * [review] Address code review * [review] Rename providerService to webProviderService Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com> Co-authored-by: Hinton <oscar@oscarhinton.com>
2021-12-14 17:10:26 +01:00
searchService: SearchService,
validationService: ValidationService,
[Account Switching] [Refactor] Implement new account centric services (#1220) * [chore] updated services.module to use account services * [refactor] sorted services provided by services.module * [chore] removed references to deleted jslib services * [chore] used activeAccount over storageService for account level storage items * [chore] resolved linter warnings * Refactor activeAccountService to stateService * [bug] Remove uneeded calls to state service on logout This was causing console erros on logout. Clearing of data is handled fully in dedicated services, clearing them in state afterwards is essentially a redundant call. * [bug] Add back null locked callback to VaultTimeoutService * Move call to get showUpdateKey * [bug] Ensure HtmlStorageService does not override StateService options and locations * [bug] Adjust theme logic to pull from the new storage locations * [bug] Correct theme not sticking on refresh * [bug] Add enableFullWidth to the account model * [bug] fix theme option empty when light is selected * [bug] init state on application start * [bug] Reinit state when coming back from a lock * [style] Fix lint complaints * [bug] Clean state on logout * [chore] Resolved merge issues * [bug] Correct default for enableGravitars * Bump angular to 12. * Remove angular.json * Bump rxjs * Fix build errors, remove file-loader with asset/resource * Use contenthash * Bump jslib * Bump ngx-toastr * [chore] resolve issues from merge * [chore] resolve issues from merge * [bug] Add missing bracket * Use newer import syntax * [bug] Correct service orge * [style] Fix lint complaints * [chore] update jslib * [review] Address code review * [review] Address code review * [review] Rename providerService to webProviderService Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com> Co-authored-by: Hinton <oscar@oscarhinton.com>
2021-12-14 17:10:26 +01:00
private policyService: PolicyService,
logService: LogService,
searchPipe: SearchPipe,
userNamePipe: UserNamePipe,
[Account Switching] [Refactor] Implement new account centric services (#1220) * [chore] updated services.module to use account services * [refactor] sorted services provided by services.module * [chore] removed references to deleted jslib services * [chore] used activeAccount over storageService for account level storage items * [chore] resolved linter warnings * Refactor activeAccountService to stateService * [bug] Remove uneeded calls to state service on logout This was causing console erros on logout. Clearing of data is handled fully in dedicated services, clearing them in state afterwards is essentially a redundant call. * [bug] Add back null locked callback to VaultTimeoutService * Move call to get showUpdateKey * [bug] Ensure HtmlStorageService does not override StateService options and locations * [bug] Adjust theme logic to pull from the new storage locations * [bug] Correct theme not sticking on refresh * [bug] Add enableFullWidth to the account model * [bug] fix theme option empty when light is selected * [bug] init state on application start * [bug] Reinit state when coming back from a lock * [style] Fix lint complaints * [bug] Clean state on logout * [chore] Resolved merge issues * [bug] Correct default for enableGravitars * Bump angular to 12. * Remove angular.json * Bump rxjs * Fix build errors, remove file-loader with asset/resource * Use contenthash * Bump jslib * Bump ngx-toastr * [chore] resolve issues from merge * [chore] resolve issues from merge * [bug] Add missing bracket * Use newer import syntax * [bug] Correct service orge * [style] Fix lint complaints * [chore] update jslib * [review] Address code review * [review] Address code review * [review] Rename providerService to webProviderService Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com> Co-authored-by: Hinton <oscar@oscarhinton.com>
2021-12-14 17:10:26 +01:00
private syncService: SyncService,
stateService: StateService,
private organizationService: OrganizationService
2021-12-17 15:57:11 +01:00
) {
super(
[Account Switching] [Refactor] Implement new account centric services (#1220) * [chore] updated services.module to use account services * [refactor] sorted services provided by services.module * [chore] removed references to deleted jslib services * [chore] used activeAccount over storageService for account level storage items * [chore] resolved linter warnings * Refactor activeAccountService to stateService * [bug] Remove uneeded calls to state service on logout This was causing console erros on logout. Clearing of data is handled fully in dedicated services, clearing them in state afterwards is essentially a redundant call. * [bug] Add back null locked callback to VaultTimeoutService * Move call to get showUpdateKey * [bug] Ensure HtmlStorageService does not override StateService options and locations * [bug] Adjust theme logic to pull from the new storage locations * [bug] Correct theme not sticking on refresh * [bug] Add enableFullWidth to the account model * [bug] fix theme option empty when light is selected * [bug] init state on application start * [bug] Reinit state when coming back from a lock * [style] Fix lint complaints * [bug] Clean state on logout * [chore] Resolved merge issues * [bug] Correct default for enableGravitars * Bump angular to 12. * Remove angular.json * Bump rxjs * Fix build errors, remove file-loader with asset/resource * Use contenthash * Bump jslib * Bump ngx-toastr * [chore] resolve issues from merge * [chore] resolve issues from merge * [bug] Add missing bracket * Use newer import syntax * [bug] Correct service orge * [style] Fix lint complaints * [chore] update jslib * [review] Address code review * [review] Address code review * [review] Rename providerService to webProviderService Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com> Co-authored-by: Hinton <oscar@oscarhinton.com>
2021-12-14 17:10:26 +01:00
apiService,
searchService,
i18nService,
platformUtilsService,
cryptoService,
validationService,
modalService,
logService,
searchPipe,
userNamePipe,
stateService
);
2021-12-17 15:57:11 +01:00
}
2018-07-06 21:01:23 +02:00
async ngOnInit() {
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
const organization = await this.organizationService.get(this.organizationId);
if (!organization.canManageUsers) {
this.router.navigate(["../collections"], { relativeTo: this.route });
2021-12-17 15:57:11 +01:00
return;
}
2018-07-11 20:43:00 +02:00
this.accessEvents = organization.useEvents;
this.accessGroups = organization.useGroups;
this.canResetPassword = organization.canManageUsersPassword;
this.orgUseResetPassword = organization.useResetPassword;
this.callingUserType = organization.type;
this.orgHasKeys = organization.hasPublicAndPrivateKeys;
2021-12-17 15:57:11 +01:00
// Backfill pub/priv key if necessary
if (this.canResetPassword && !this.orgHasKeys) {
const orgShareKey = await this.cryptoService.getOrgKey(this.organizationId);
const orgKeys = await this.cryptoService.makeKeyPair(orgShareKey);
const request = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);
const response = await this.apiService.postOrganizationKeys(this.organizationId, request);
if (response != null) {
this.orgHasKeys = response.publicKey != null && response.privateKey != null;
await this.syncService.fullSync(true); // Replace oganizations with new data
} else {
throw new Error(this.i18nService.t("resetPasswordOrgKeysError"));
2018-07-09 23:07:13 +02:00
}
2021-12-17 15:57:11 +01:00
}
2018-07-09 23:07:13 +02:00
await this.load();
2018-07-10 21:03:13 +02:00
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
this.searchText = qParams.search;
if (qParams.viewEvents != null) {
const user = this.users.filter((u) => u.id === qParams.viewEvents);
if (user.length > 0 && user[0].status === OrganizationUserStatusType.Confirmed) {
this.events(user[0]);
2021-12-17 15:57:11 +01:00
}
}
2021-12-17 15:57:11 +01:00
});
});
}
2018-07-06 21:01:23 +02:00
async load() {
const resetPasswordPolicy = await this.policyService.getPolicyForOrganization(
PolicyType.ResetPassword,
2018-07-06 21:01:23 +02:00
this.organizationId
2021-12-17 15:57:11 +01:00
);
this.orgResetPasswordPolicyEnabled = resetPasswordPolicy?.enabled;
super.load();
2021-12-17 15:57:11 +01:00
}
getUsers(): Promise<ListResponse<OrganizationUserUserDetailsResponse>> {
return this.apiService.getOrganizationUsers(this.organizationId);
2021-12-17 15:57:11 +01:00
}
deleteUser(id: string): Promise<any> {
return this.apiService.deleteOrganizationUser(this.organizationId, id);
2021-12-17 15:57:11 +01:00
}
deactivateUser(id: string): Promise<any> {
return this.apiService.deactivateOrganizationUser(this.organizationId, id);
}
activateUser(id: string): Promise<any> {
return this.apiService.activateOrganizationUser(this.organizationId, id);
}
reinviteUser(id: string): Promise<any> {
return this.apiService.postOrganizationUserReinvite(this.organizationId, id);
2021-12-17 15:57:11 +01:00
}
async confirmUser(
user: OrganizationUserUserDetailsResponse,
publicKey: Uint8Array
): Promise<any> {
const orgKey = await this.cryptoService.getOrgKey(this.organizationId);
const key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey.buffer);
const request = new OrganizationUserConfirmRequest();
request.key = key.encryptedString;
await this.apiService.postOrganizationUserConfirm(this.organizationId, user.id, request);
2021-12-17 15:57:11 +01:00
}
allowResetPassword(orgUser: OrganizationUserUserDetailsResponse): boolean {
// Hierarchy check
let callingUserHasPermission = false;
2021-12-17 15:57:11 +01:00
switch (this.callingUserType) {
case OrganizationUserType.Owner:
callingUserHasPermission = true;
2021-12-17 15:57:11 +01:00
break;
case OrganizationUserType.Admin:
callingUserHasPermission = orgUser.type !== OrganizationUserType.Owner;
2021-12-17 15:57:11 +01:00
break;
case OrganizationUserType.Custom:
callingUserHasPermission =
orgUser.type !== OrganizationUserType.Owner &&
orgUser.type !== OrganizationUserType.Admin;
2021-12-17 15:57:11 +01:00
break;
}
2021-12-17 15:57:11 +01:00
// Final
return (
this.canResetPassword &&
callingUserHasPermission &&
this.orgUseResetPassword &&
this.orgHasKeys &&
orgUser.resetPasswordEnrolled &&
this.orgResetPasswordPolicyEnabled &&
orgUser.status === OrganizationUserStatusType.Confirmed
2021-12-17 15:57:11 +01:00
);
}
showEnrolledStatus(orgUser: OrganizationUserUserDetailsResponse): boolean {
2021-12-17 15:57:11 +01:00
return (
this.orgUseResetPassword &&
orgUser.resetPasswordEnrolled &&
this.orgResetPasswordPolicyEnabled
2021-12-17 15:57:11 +01:00
);
}
2018-07-11 19:30:17 +02:00
async edit(user: OrganizationUserUserDetailsResponse) {
const [modal] = await this.modalService.openViewRef(
UserAddEditComponent,
this.addEditModalRef,
(comp) => {
comp.name = this.userNamePipe.transform(user);
comp.organizationId = this.organizationId;
comp.organizationUserId = user != null ? user.id : null;
comp.usesKeyConnector = user?.usesKeyConnector;
comp.onSavedUser.subscribe(() => {
modal.close();
this.load();
});
comp.onDeletedUser.subscribe(() => {
modal.close();
this.removeUser(user);
2021-12-17 15:57:11 +01:00
});
comp.onDeactivatedUser.subscribe(() => {
modal.close();
this.load();
});
comp.onActivatedUser.subscribe(() => {
modal.close();
this.load();
});
2021-12-17 15:57:11 +01:00
}
);
}
async groups(user: OrganizationUserUserDetailsResponse) {
const [modal] = await this.modalService.openViewRef(
UserGroupsComponent,
this.groupsModalRef,
2021-12-17 15:57:11 +01:00
(comp) => {
comp.name = this.userNamePipe.transform(user);
comp.organizationId = this.organizationId;
comp.organizationUserId = user != null ? user.id : null;
comp.onSavedUser.subscribe(() => {
modal.close();
2021-12-17 15:57:11 +01:00
});
}
);
}
async bulkRemove() {
if (this.actionPromise != null) {
return;
}
const [modal] = await this.modalService.openViewRef(
BulkRemoveComponent,
2021-12-07 20:41:45 +01:00
this.bulkRemoveModalRef,
(comp) => {
comp.organizationId = this.organizationId;
comp.users = this.getCheckedUsers();
2021-12-17 15:57:11 +01:00
}
);
await modal.onClosedPromise();
await this.load();
2021-12-17 15:57:11 +01:00
}
async bulkDeactivate() {
await this.bulkActivateOrDeactivate(true);
}
async bulkActivate() {
await this.bulkActivateOrDeactivate(false);
}
async bulkActivateOrDeactivate(isDeactivating: boolean) {
if (this.actionPromise != null) {
return;
}
const ref = this.modalService.open(BulkDeactivateComponent, {
allowMultipleModals: true,
data: {
organizationId: this.organizationId,
users: this.getCheckedUsers(),
isDeactivating: isDeactivating,
},
});
await ref.onClosedPromise();
await this.load();
}
async bulkReinvite() {
if (this.actionPromise != null) {
return;
}
const users = this.getCheckedUsers();
const filteredUsers = users.filter((u) => u.status === OrganizationUserStatusType.Invited);
if (filteredUsers.length <= 0) {
this.platformUtilsService.showToast(
2021-12-17 15:57:11 +01:00
"error",
2021-12-07 20:41:45 +01:00
this.i18nService.t("errorOccurred"),
this.i18nService.t("noSelectedUsersApplicable")
);
2021-12-17 15:57:11 +01:00
return;
}
2018-07-11 19:30:17 +02:00
try {
const request = new OrganizationUserBulkRequest(filteredUsers.map((user) => user.id));
const response = this.apiService.postManyOrganizationUserReinvite(
this.organizationId,
2021-12-17 15:57:11 +01:00
request
);
this.showBulkStatus(
users,
filteredUsers,
2021-12-17 15:57:11 +01:00
response,
this.i18nService.t("bulkReinviteMessage")
);
} catch (e) {
this.validationService.showError(e);
2018-07-11 19:30:17 +02:00
}
this.actionPromise = null;
2021-12-17 15:57:11 +01:00
}
2018-07-11 19:30:17 +02:00
async bulkConfirm() {
if (this.actionPromise != null) {
return;
}
const [modal] = await this.modalService.openViewRef(
BulkConfirmComponent,
this.bulkConfirmModalRef,
2021-12-17 15:57:11 +01:00
(comp) => {
comp.organizationId = this.organizationId;
comp.users = this.getCheckedUsers();
2021-12-17 15:57:11 +01:00
}
);
await modal.onClosedPromise();
2018-07-07 05:08:10 +02:00
await this.load();
2021-12-17 15:57:11 +01:00
}
async events(user: OrganizationUserUserDetailsResponse) {
2022-02-24 12:10:07 +01:00
await this.modalService.openViewRef(EntityEventsComponent, this.eventsModalRef, (comp) => {
comp.name = this.userNamePipe.transform(user);
comp.organizationId = this.organizationId;
comp.entityId = user.id;
comp.showUser = false;
comp.entity = "user";
});
2021-12-17 15:57:11 +01:00
}
async resetPassword(user: OrganizationUserUserDetailsResponse) {
const [modal] = await this.modalService.openViewRef(
ResetPasswordComponent,
this.resetPasswordModalRef,
2021-12-17 15:57:11 +01:00
(comp) => {
comp.name = this.userNamePipe.transform(user);
comp.email = user != null ? user.email : null;
comp.organizationId = this.organizationId;
comp.id = user != null ? user.id : null;
2021-12-17 15:57:11 +01:00
comp.onPasswordReset.subscribe(() => {
modal.close();
this.load();
2021-12-17 15:57:11 +01:00
});
}
2021-12-17 15:57:11 +01:00
);
}
protected deleteWarningMessage(user: OrganizationUserUserDetailsResponse): string {
if (user.usesKeyConnector) {
return this.i18nService.t("removeUserConfirmationKeyConnector");
}
return super.deleteWarningMessage(user);
2021-12-17 15:57:11 +01:00
}
private async showBulkStatus(
users: OrganizationUserUserDetailsResponse[],
filteredUsers: OrganizationUserUserDetailsResponse[],
request: Promise<ListResponse<OrganizationUserBulkResponse>>,
successfullMessage: string
) {
const [modal, childComponent] = await this.modalService.openViewRef(
BulkStatusComponent,
this.bulkStatusModalRef,
(comp) => {
comp.loading = true;
}
);
2021-12-17 15:57:11 +01:00
// Workaround to handle closing the modal shortly after it has been opened
let close = false;
modal.onShown.subscribe(() => {
if (close) {
modal.close();
2021-12-17 15:57:11 +01:00
}
});
try {
const response = await request;
2021-12-17 15:57:11 +01:00
if (modal) {
const keyedErrors: any = response.data
.filter((r) => r.error !== "")
.reduce((a, x) => ({ ...a, [x.id]: x.error }), {});
const keyedFilteredUsers: any = filteredUsers.reduce((a, x) => ({ ...a, [x.id]: x }), {});
2021-12-17 15:57:11 +01:00
childComponent.users = users.map((user) => {
let message = keyedErrors[user.id] ?? successfullMessage;
2022-02-24 12:10:07 +01:00
// eslint-disable-next-line
if (!keyedFilteredUsers.hasOwnProperty(user.id)) {
message = this.i18nService.t("bulkFilteredMessage");
}
2021-12-17 15:57:11 +01:00
return {
user: user,
2022-02-24 12:10:07 +01:00
error: keyedErrors.hasOwnProperty(user.id), // eslint-disable-line
message: message,
2021-12-17 15:57:11 +01:00
};
});
childComponent.loading = false;
}
} catch {
close = true;
modal.close();
}
2021-12-17 15:57:11 +01:00
}
2018-07-06 21:01:23 +02:00
}