1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-22 11:13:46 +00:00

[PM-1504] Migrate Dialogs to DialogService (#5013)

This PR introduces a generic `DialogService` which can be used by all the clients. This allows us to decouple dialogs from the `PlatformUtilsHelper`.

The `DialogService` provides a new method, `openSimpleDialog` which is the new interface for that type of dialogs.

This gives us 3 different implementations: 
- Web: DialogService modern dialogs
- Browser: SweetAlert
- Desktop: Native electron based
This commit is contained in:
Oscar Hinton
2023-05-02 18:46:03 +02:00
committed by GitHub
parent 7c4b2c04b9
commit 4e1867682f
144 changed files with 1514 additions and 1212 deletions

View File

@@ -1,9 +1,8 @@
import { Injectable } from "@angular/core";
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from "@angular/router";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
@Injectable({
@@ -13,9 +12,8 @@ export class IsPaidOrgGuard implements CanActivate {
constructor(
private router: Router,
private organizationService: OrganizationService,
private platformUtilsService: PlatformUtilsService,
private messagingService: MessagingService,
private i18nService: I18nService
private dialogService: DialogServiceAbstraction
) {}
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
@@ -28,11 +26,13 @@ export class IsPaidOrgGuard implements CanActivate {
if (org.isFreeOrg) {
// Users without billing permission can't access billing
if (!org.canEditSubscription) {
await this.platformUtilsService.showDialog(
this.i18nService.t("notAvailableForFreeOrganization"),
this.i18nService.t("upgradeOrganization"),
this.i18nService.t("ok")
);
await this.dialogService.openSimpleDialog({
title: { key: "upgradeOrganization" },
content: { key: "notAvailableForFreeOrganization" },
acceptButtonText: { key: "ok" },
cancelButtonText: null,
type: SimpleDialogType.INFO,
});
return false;
} else {
this.messagingService.send("upgradeOrganization", { organizationId: org.id });

View File

@@ -3,6 +3,7 @@ import { ChangeDetectorRef, Component, Inject, OnDestroy, OnInit } from "@angula
import { FormBuilder, Validators } from "@angular/forms";
import { catchError, combineLatest, from, map, of, Subject, switchMap, takeUntil } from "rxjs";
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
@@ -13,7 +14,6 @@ import { CollectionData } from "@bitwarden/common/admin-console/models/data/coll
import { Collection } from "@bitwarden/common/admin-console/models/domain/collection";
import { CollectionDetailsResponse } from "@bitwarden/common/admin-console/models/response/collection.response";
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
import { DialogService } from "@bitwarden/components";
import { GroupService, GroupView } from "../core";
import {
@@ -64,7 +64,7 @@ export enum GroupAddEditDialogResultType {
* @param config Configuration for the dialog
*/
export const openGroupAddEditDialog = (
dialogService: DialogService,
dialogService: DialogServiceAbstraction,
config: DialogConfig<GroupAddEditDialogParams>
) => {
return dialogService.open<GroupAddEditDialogResultType, GroupAddEditDialogParams>(
@@ -180,7 +180,8 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
private platformUtilsService: PlatformUtilsService,
private logService: LogService,
private formBuilder: FormBuilder,
private changeDetectorRef: ChangeDetectorRef
private changeDetectorRef: ChangeDetectorRef,
private dialogService: DialogServiceAbstraction
) {
this.tabIndex = params.initialTab ?? GroupAddEditTabType.Info;
}
@@ -269,15 +270,11 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
return;
}
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("deleteGroupConfirmation"),
this.group.name,
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning",
false,
"app-group-add-edit .modal-content"
);
const confirmed = await this.dialogService.openSimpleDialog({
title: this.group.name,
content: { key: "deleteGroupConfirmation" },
type: SimpleDialogType.WARNING,
});
if (!confirmed) {
return false;
}

View File

@@ -15,6 +15,7 @@ import {
import { first } from "rxjs/operators";
import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe";
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
import { ModalService } from "@bitwarden/angular/services/modal.service";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
@@ -31,7 +32,6 @@ import {
import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view";
import { Utils } from "@bitwarden/common/misc/utils";
import { ListResponse } from "@bitwarden/common/models/response/list.response";
import { DialogService } from "@bitwarden/components";
import { GroupService, GroupView } from "../core";
@@ -127,7 +127,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
private route: ActivatedRoute,
private i18nService: I18nService,
private modalService: ModalService,
private dialogService: DialogService,
private dialogService: DialogServiceAbstraction,
private platformUtilsService: PlatformUtilsService,
private searchService: SearchService,
private logService: LogService,
@@ -233,13 +233,11 @@ export class GroupsComponent implements OnInit, OnDestroy {
}
async delete(groupRow: GroupDetailsRow) {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("deleteGroupConfirmation"),
groupRow.details.name,
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
const confirmed = await this.dialogService.openSimpleDialog({
title: groupRow.details.name,
content: { key: "deleteGroupConfirmation" },
type: SimpleDialogType.WARNING,
});
if (!confirmed) {
return false;
}
@@ -265,13 +263,14 @@ export class GroupsComponent implements OnInit, OnDestroy {
}
const deleteMessage = groupsToDelete.map((g) => g.details.name).join(", ");
const confirmed = await this.platformUtilsService.showDialog(
deleteMessage,
this.i18nService.t("deleteMultipleGroupsConfirmation", groupsToDelete.length.toString()),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
const confirmed = await this.dialogService.openSimpleDialog({
title: {
key: "deleteMultipleGroupsConfirmation",
placeholders: [groupsToDelete.length.toString()],
},
content: deleteMessage,
type: SimpleDialogType.WARNING,
});
if (!confirmed) {
return false;
}

View File

@@ -3,6 +3,7 @@ import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
import { FormBuilder, Validators } from "@angular/forms";
import { combineLatest, of, shareReplay, Subject, switchMap, takeUntil } from "rxjs";
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
@@ -14,7 +15,6 @@ import {
import { PermissionsApi } from "@bitwarden/common/admin-console/models/api/permissions.api";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view";
import { DialogService } from "@bitwarden/components";
import { flagEnabled } from "../../../../../../utils/flags";
import {
@@ -130,7 +130,8 @@ export class MemberDialogComponent implements OnInit, OnDestroy {
private collectionAdminService: CollectionAdminService,
private groupService: GroupService,
private userService: UserAdminService,
private organizationUserService: OrganizationUserService
private organizationUserService: OrganizationUserService,
private dialogService: DialogServiceAbstraction
) {}
async ngOnInit() {
@@ -364,15 +365,13 @@ export class MemberDialogComponent implements OnInit, OnDestroy {
const message = this.params.usesKeyConnector
? "removeUserConfirmationKeyConnector"
: "removeOrgUserConfirmation";
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t(message),
this.i18nService.t("removeUserIdAccess", this.params.name),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning",
false,
"app-user-add-edit .modal-content"
);
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "removeUserIdAccess", placeholders: [this.params.name] },
content: { key: message },
type: SimpleDialogType.WARNING,
});
if (!confirmed) {
return false;
}
@@ -395,15 +394,13 @@ export class MemberDialogComponent implements OnInit, OnDestroy {
return;
}
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("revokeUserConfirmation"),
this.i18nService.t("revokeUserId", this.params.name),
this.i18nService.t("revokeAccess"),
this.i18nService.t("cancel"),
"warning",
false,
"app-user-add-edit .modal-content"
);
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "revokeUserId", placeholders: [this.params.name] },
content: { key: "revokeUserConfirmation" },
acceptButtonText: { key: "revokeAccess" },
type: SimpleDialogType.WARNING,
});
if (!confirmed) {
return false;
}
@@ -511,7 +508,7 @@ function mapToGroupAccessSelections(groups: string[]): AccessItemValue[] {
* @param config Configuration for the dialog
*/
export function openUserAddEditDialog(
dialogService: DialogService,
dialogService: DialogServiceAbstraction,
config: DialogConfig<MemberDialogParams>
) {
return dialogService.open<MemberDialogResult, MemberDialogParams>(MemberDialogComponent, config);

View File

@@ -10,6 +10,7 @@ import {
import { Subject, takeUntil } from "rxjs";
import zxcvbn from "zxcvbn";
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
import { PasswordStrengthComponent } from "@bitwarden/angular/shared/components/password-strength/password-strength.component";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
@@ -52,7 +53,8 @@ export class ResetPasswordComponent implements OnInit, OnDestroy {
private policyService: PolicyService,
private cryptoService: CryptoService,
private logService: LogService,
private organizationUserService: OrganizationUserService
private organizationUserService: OrganizationUserService,
private dialogService: DialogServiceAbstraction
) {}
async ngOnInit() {
@@ -135,13 +137,12 @@ export class ResetPasswordComponent implements OnInit, OnDestroy {
}
if (this.passwordStrengthResult.score < 3) {
const result = await this.platformUtilsService.showDialog(
this.i18nService.t("weakMasterPasswordDesc"),
this.i18nService.t("weakMasterPassword"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
const result = await this.dialogService.openSimpleDialog({
title: { key: "weakMasterPassword" },
content: { key: "weakMasterPasswordDesc" },
type: SimpleDialogType.WARNING,
});
if (!result) {
return false;
}

View File

@@ -15,6 +15,12 @@ import {
import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe";
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
import {
SimpleDialogType,
DialogServiceAbstraction,
SimpleDialogCloseType,
SimpleDialogOptions,
} from "@bitwarden/angular/services/dialog";
import { ModalService } from "@bitwarden/angular/services/modal.service";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
@@ -48,12 +54,6 @@ import { CollectionDetailsResponse } from "@bitwarden/common/admin-console/model
import { ProductType } from "@bitwarden/common/enums";
import { ListResponse } from "@bitwarden/common/models/response/list.response";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import {
DialogService,
SimpleDialogCloseType,
SimpleDialogOptions,
SimpleDialogType,
} from "@bitwarden/components";
import { EntityEventsComponent } from "../../../admin-console/organizations/manage/entity-events.component";
import { BasePeopleComponent } from "../../../common/base.people.component";
@@ -123,7 +123,7 @@ export class PeopleComponent
private organizationService: OrganizationService,
private organizationApiService: OrganizationApiServiceAbstraction,
private organizationUserService: OrganizationUserService,
private dialogService: DialogService,
dialogService: DialogServiceAbstraction,
private router: Router,
private groupService: GroupService,
private collectionService: CollectionService
@@ -139,7 +139,8 @@ export class PeopleComponent
logService,
searchPipe,
userNamePipe,
stateService
stateService,
dialogService
);
}
@@ -362,7 +363,7 @@ export class PeopleComponent
orgUpgradeSimpleDialogOpts.cancelButtonText = null; // hide secondary btn
}
const simpleDialog = this.dialogService.openSimpleDialog(orgUpgradeSimpleDialogOpts);
const simpleDialog = this.dialogService.openSimpleDialogRef(orgUpgradeSimpleDialogOpts);
firstValueFrom(simpleDialog.closed).then((result: SimpleDialogCloseType | undefined) => {
if (!result) {
@@ -541,17 +542,18 @@ export class PeopleComponent
}
protected async removeUserConfirmationDialog(user: OrganizationUserView) {
const warningMessage = user.usesKeyConnector
? this.i18nService.t("removeUserConfirmationKeyConnector")
: this.i18nService.t("removeOrgUserConfirmation");
const content = user.usesKeyConnector
? "removeUserConfirmationKeyConnector"
: "removeOrgUserConfirmation";
return this.platformUtilsService.showDialog(
warningMessage,
this.i18nService.t("removeUserIdAccess", this.userNamePipe.transform(user)),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
return await this.dialogService.openSimpleDialog({
title: {
key: "removeUserIdAccess",
placeholders: [this.userNamePipe.transform(user)],
},
content: { key: content },
type: SimpleDialogType.WARNING,
});
}
private async showBulkStatus(

View File

@@ -3,6 +3,7 @@ import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
import { FormBuilder, Validators } from "@angular/forms";
import { combineLatest, of, shareReplay, Subject, switchMap, takeUntil } from "rxjs";
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service";
import { OrganizationUserUserDetailsResponse } from "@bitwarden/common/abstractions/organization-user/responses";
@@ -10,7 +11,7 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view";
import { BitValidators, DialogService } from "@bitwarden/components";
import { BitValidators } from "@bitwarden/components";
import {
CollectionAdminService,
@@ -75,7 +76,8 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
private collectionService: CollectionAdminService,
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService,
private organizationUserService: OrganizationUserService
private organizationUserService: OrganizationUserService,
private dialogService: DialogServiceAbstraction
) {
this.tabIndex = params.initialTab ?? CollectionDialogTabType.Info;
}
@@ -200,13 +202,11 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
};
protected delete = async () => {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("deleteCollectionConfirmation"),
this.collection?.name,
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
const confirmed = await this.dialogService.openSimpleDialog({
title: this.collection?.name,
content: { key: "deleteCollectionConfirmation" },
type: SimpleDialogType.WARNING,
});
if (!confirmed && this.params.collectionId) {
return false;
@@ -291,7 +291,7 @@ function mapToAccessSelections(collectionDetails: CollectionAdminView): AccessIt
* @param config Configuration for the dialog
*/
export function openCollectionDialog(
dialogService: DialogService,
dialogService: DialogServiceAbstraction,
config: DialogConfig<CollectionDialogParams>
) {
return dialogService.open<CollectionDialogResult, CollectionDialogParams>(

View File

@@ -2,6 +2,7 @@ import { Component } from "@angular/core";
import { UntypedFormBuilder } from "@angular/forms";
import { ActivatedRoute } from "@angular/router";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { ModalService } from "@bitwarden/angular/services/modal.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
@@ -34,7 +35,8 @@ export class OrganizationExportComponent extends ExportComponent {
userVerificationService: UserVerificationService,
formBuilder: UntypedFormBuilder,
fileDownloadService: FileDownloadService,
modalService: ModalService
modalService: ModalService,
dialogService: DialogServiceAbstraction
) {
super(
cryptoService,
@@ -47,7 +49,8 @@ export class OrganizationExportComponent extends ExportComponent {
userVerificationService,
formBuilder,
fileDownloadService,
modalService
modalService,
dialogService
);
}

View File

@@ -1,6 +1,7 @@
import { Component } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
import { ModalService } from "@bitwarden/angular/services/modal.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
@@ -8,7 +9,6 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { DialogService } from "@bitwarden/components";
import { ImportServiceAbstraction } from "@bitwarden/importer";
import { ImportComponent } from "../../../../tools/import-export/import.component";
@@ -32,7 +32,7 @@ export class OrganizationImportComponent extends ImportComponent {
logService: LogService,
modalService: ModalService,
syncService: SyncService,
dialogService: DialogService
dialogService: DialogServiceAbstraction
) {
super(
i18nService,
@@ -59,13 +59,12 @@ export class OrganizationImportComponent extends ImportComponent {
}
async submit() {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("importWarning", this.organizationName),
this.i18nService.t("warning"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "warning" },
content: { key: "importWarning", placeholders: [this.organizationName] },
type: SimpleDialogType.WARNING,
});
if (!confirmed) {
return;
}

View File

@@ -2,6 +2,7 @@ import { formatDate } from "@angular/common";
import { Component, EventEmitter, Input, Output, OnInit } from "@angular/core";
import { firstValueFrom } from "rxjs";
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
@@ -30,7 +31,8 @@ export class SponsoringOrgRowComponent implements OnInit {
private apiService: ApiService,
private i18nService: I18nService,
private logService: LogService,
private platformUtilsService: PlatformUtilsService
private platformUtilsService: PlatformUtilsService,
private dialogService: DialogServiceAbstraction
) {}
async ngOnInit() {
@@ -67,15 +69,14 @@ export class SponsoringOrgRowComponent implements OnInit {
}
private async doRevokeSponsorship() {
const isConfirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("revokeSponsorshipConfirmation"),
`${this.i18nService.t("remove")} ${this.sponsoringOrg.familySponsorshipFriendlyName}?`,
this.i18nService.t("remove"),
this.i18nService.t("cancel"),
"warning"
);
const confirmed = await this.dialogService.openSimpleDialog({
title: `${this.i18nService.t("remove")} ${this.sponsoringOrg.familySponsorshipFriendlyName}?`,
content: { key: "revokeSponsorshipConfirmation" },
acceptButtonText: { key: "remove" },
type: SimpleDialogType.WARNING,
});
if (!isConfirmed) {
if (!confirmed) {
return;
}