mirror of
https://github.com/bitwarden/browser
synced 2025-12-24 04:04:24 +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:
@@ -2,6 +2,7 @@ import { Component, NgZone } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { LockComponent as BaseLockComponent } from "@bitwarden/angular/auth/components/lock.component";
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||
@@ -48,7 +49,8 @@ export class LockComponent extends BaseLockComponent {
|
||||
policyApiService: PolicyApiServiceAbstraction,
|
||||
policyService: InternalPolicyService,
|
||||
passwordGenerationService: PasswordGenerationServiceAbstraction,
|
||||
private authService: AuthService
|
||||
private authService: AuthService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(
|
||||
router,
|
||||
@@ -66,7 +68,8 @@ export class LockComponent extends BaseLockComponent {
|
||||
ngZone,
|
||||
policyApiService,
|
||||
policyService,
|
||||
passwordGenerationService
|
||||
passwordGenerationService,
|
||||
dialogService
|
||||
);
|
||||
this.successRoute = "/tabs/current";
|
||||
this.isInitialLockScreen = (window as any).previousPopupUrl == null;
|
||||
|
||||
@@ -3,6 +3,7 @@ import { UntypedFormBuilder } from "@angular/forms";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/components/register.component";
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||
@@ -36,7 +37,8 @@ export class RegisterComponent extends BaseRegisterComponent {
|
||||
passwordGenerationService: PasswordGenerationServiceAbstraction,
|
||||
environmentService: EnvironmentService,
|
||||
logService: LogService,
|
||||
auditService: AuditService
|
||||
auditService: AuditService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(
|
||||
formValidationErrorService,
|
||||
@@ -51,7 +53,8 @@ export class RegisterComponent extends BaseRegisterComponent {
|
||||
passwordGenerationService,
|
||||
environmentService,
|
||||
logService,
|
||||
auditService
|
||||
auditService,
|
||||
dialogService
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Component } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
||||
import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/components/set-password.component";
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
@@ -34,7 +35,8 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
|
||||
syncService: SyncService,
|
||||
route: ActivatedRoute,
|
||||
organizationApiService: OrganizationApiServiceAbstraction,
|
||||
organizationUserService: OrganizationUserService
|
||||
organizationUserService: OrganizationUserService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
@@ -50,7 +52,8 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
|
||||
route,
|
||||
stateService,
|
||||
organizationApiService,
|
||||
organizationUserService
|
||||
organizationUserService,
|
||||
dialogService
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component";
|
||||
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AppIdService } from "@bitwarden/common/abstractions/appId.service";
|
||||
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
|
||||
@@ -46,7 +47,8 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
logService: LogService,
|
||||
twoFactorService: TwoFactorService,
|
||||
appIdService: AppIdService,
|
||||
loginService: LoginService
|
||||
loginService: LoginService,
|
||||
private dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(
|
||||
authService,
|
||||
@@ -102,12 +104,11 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
this.selectedProviderType === TwoFactorProviderType.Email &&
|
||||
this.popupUtilsService.inPopup(window)
|
||||
) {
|
||||
const confirmed = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t("popup2faCloseMessage"),
|
||||
null,
|
||||
this.i18nService.t("yes"),
|
||||
this.i18nService.t("no")
|
||||
);
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "warning" },
|
||||
content: { key: "popup2faCloseMessage" },
|
||||
type: SimpleDialogType.WARNING,
|
||||
});
|
||||
if (confirmed) {
|
||||
this.popupUtilsService.popOut(window);
|
||||
}
|
||||
|
||||
@@ -153,10 +153,11 @@ export class NativeMessagingBackground {
|
||||
this.connected = false;
|
||||
|
||||
this.messagingService.send("showDialog", {
|
||||
text: this.i18nService.t("nativeMessagingInvalidEncryptionDesc"),
|
||||
title: this.i18nService.t("nativeMessagingInvalidEncryptionTitle"),
|
||||
confirmText: this.i18nService.t("ok"),
|
||||
type: "error",
|
||||
title: { key: "nativeMessagingInvalidEncryptionTitle" },
|
||||
content: { key: "nativeMessagingInvalidEncryptionDesc" },
|
||||
acceptButtonText: { key: "ok" },
|
||||
cancelButtonText: null,
|
||||
type: "danger",
|
||||
});
|
||||
break;
|
||||
case "verifyFingerprint": {
|
||||
@@ -199,10 +200,11 @@ export class NativeMessagingBackground {
|
||||
|
||||
showWrongUserDialog() {
|
||||
this.messagingService.send("showDialog", {
|
||||
text: this.i18nService.t("nativeMessagingWrongUserDesc"),
|
||||
title: this.i18nService.t("nativeMessagingWrongUserTitle"),
|
||||
confirmText: this.i18nService.t("ok"),
|
||||
type: "error",
|
||||
title: { key: "nativeMessagingWrongUserTitle" },
|
||||
content: { key: "nativeMessagingWrongUserDesc" },
|
||||
acceptButtonText: { key: "ok" },
|
||||
cancelButtonText: null,
|
||||
type: "danger",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -258,10 +260,11 @@ export class NativeMessagingBackground {
|
||||
this.connected = false;
|
||||
|
||||
this.messagingService.send("showDialog", {
|
||||
text: this.i18nService.t("nativeMessagingInvalidEncryptionDesc"),
|
||||
title: this.i18nService.t("nativeMessagingInvalidEncryptionTitle"),
|
||||
confirmText: this.i18nService.t("ok"),
|
||||
type: "error",
|
||||
title: { key: "nativeMessagingInvalidEncryptionTitle" },
|
||||
content: { key: "nativeMessagingInvalidEncryptionDesc" },
|
||||
acceptButtonText: { key: "ok" },
|
||||
cancelButtonText: null,
|
||||
type: "danger",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -285,18 +288,20 @@ export class NativeMessagingBackground {
|
||||
|
||||
if (message.response === "not enabled") {
|
||||
this.messagingService.send("showDialog", {
|
||||
text: this.i18nService.t("biometricsNotEnabledDesc"),
|
||||
title: this.i18nService.t("biometricsNotEnabledTitle"),
|
||||
confirmText: this.i18nService.t("ok"),
|
||||
type: "error",
|
||||
title: { key: "biometricsNotEnabledTitle" },
|
||||
content: { key: "biometricsNotEnabledDesc" },
|
||||
acceptButtonText: { key: "ok" },
|
||||
cancelButtonText: null,
|
||||
type: "danger",
|
||||
});
|
||||
break;
|
||||
} else if (message.response === "not supported") {
|
||||
this.messagingService.send("showDialog", {
|
||||
text: this.i18nService.t("biometricsNotSupportedDesc"),
|
||||
title: this.i18nService.t("biometricsNotSupportedTitle"),
|
||||
confirmText: this.i18nService.t("ok"),
|
||||
type: "error",
|
||||
title: { key: "biometricsNotSupportedTitle" },
|
||||
content: { key: "biometricsNotSupportedDesc" },
|
||||
acceptButtonText: { key: "ok" },
|
||||
cancelButtonText: null,
|
||||
type: "danger",
|
||||
});
|
||||
break;
|
||||
}
|
||||
@@ -377,13 +382,8 @@ export class NativeMessagingBackground {
|
||||
await this.cryptoService.getFingerprint(await this.stateService.getUserId(), this.publicKey)
|
||||
).join(" ");
|
||||
|
||||
this.messagingService.send("showDialog", {
|
||||
html: `${this.i18nService.t(
|
||||
"desktopIntegrationVerificationText"
|
||||
)}<br><br><strong>${fingerprint}</strong>`,
|
||||
title: this.i18nService.t("desktopSyncVerificationTitle"),
|
||||
confirmText: this.i18nService.t("ok"),
|
||||
type: "warning",
|
||||
this.messagingService.send("showNativeMessagingFinterprintDialog", {
|
||||
fingerprint: fingerprint,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,9 +119,6 @@ export default class RuntimeBackground {
|
||||
BrowserApi.closeBitwardenExtensionTab();
|
||||
}, msg.delay ?? 0);
|
||||
break;
|
||||
case "showDialogResolve":
|
||||
this.platformUtilsService.resolveDialogPromise(msg.dialogId, msg.confirmed);
|
||||
break;
|
||||
case "bgCollectPageDetails":
|
||||
await this.main.collectPageDetailsForContentScript(sender.tab, msg.sender, sender.frameId);
|
||||
break;
|
||||
@@ -204,10 +201,10 @@ export default class RuntimeBackground {
|
||||
break;
|
||||
case "emailVerificationRequired":
|
||||
this.messagingService.send("showDialog", {
|
||||
dialogId: "emailVerificationRequired",
|
||||
title: this.i18nService.t("emailVerificationRequired"),
|
||||
text: this.i18nService.t("emailVerificationRequiredDesc"),
|
||||
confirmText: this.i18nService.t("ok"),
|
||||
title: { key: "emailVerificationRequired" },
|
||||
content: { key: "emailVerificationRequiredDesc" },
|
||||
acceptButtonText: { key: "ok" },
|
||||
cancelButtonText: null,
|
||||
type: "info",
|
||||
});
|
||||
break;
|
||||
|
||||
@@ -10,8 +10,9 @@ import { DomSanitizer } from "@angular/platform-browser";
|
||||
import { NavigationEnd, Router, RouterOutlet } from "@angular/router";
|
||||
import { IndividualConfig, ToastrService } from "ngx-toastr";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
import Swal, { SweetAlertIcon } from "sweetalert2";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
import { DialogServiceAbstraction, SimpleDialogOptions } from "@bitwarden/angular/services/dialog";
|
||||
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
|
||||
@@ -48,7 +49,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private ngZone: NgZone,
|
||||
private sanitizer: DomSanitizer,
|
||||
private platformUtilsService: PlatformUtilsService
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private dialogService: DialogServiceAbstraction
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@@ -102,6 +104,9 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
} else if (msg.command === "showDialog") {
|
||||
await this.showDialog(msg);
|
||||
} else if (msg.command === "showNativeMessagingFinterprintDialog") {
|
||||
// TODO: Should be refactored to live in another service.
|
||||
await this.showNativeMessagingFingerprintDialog(msg);
|
||||
} else if (msg.command === "showToast") {
|
||||
this.ngZone.run(() => {
|
||||
this.showToast(msg);
|
||||
@@ -222,51 +227,24 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
this.toastrService.show(message, msg.title, options, "toast-" + msg.type);
|
||||
}
|
||||
|
||||
private async showDialog(msg: any) {
|
||||
let iconClasses: string = null;
|
||||
const type = msg.type;
|
||||
if (type != null) {
|
||||
// If you add custom types to this part, the type to SweetAlertIcon cast below needs to be changed.
|
||||
switch (type) {
|
||||
case "success":
|
||||
iconClasses = "bwi-check text-success";
|
||||
break;
|
||||
case "warning":
|
||||
iconClasses = "bwi-exclamation-triangle text-warning";
|
||||
break;
|
||||
case "error":
|
||||
iconClasses = "bwi-error text-danger";
|
||||
break;
|
||||
case "info":
|
||||
iconClasses = "bwi-info-circle text-info";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
private async showDialog(msg: SimpleDialogOptions) {
|
||||
await this.dialogService.openSimpleDialog(msg);
|
||||
}
|
||||
|
||||
const cancelText = msg.cancelText;
|
||||
const confirmText = msg.confirmText;
|
||||
const confirmed = await Swal.fire({
|
||||
private async showNativeMessagingFingerprintDialog(msg: any) {
|
||||
await Swal.fire({
|
||||
heightAuto: false,
|
||||
buttonsStyling: false,
|
||||
icon: type as SweetAlertIcon, // required to be any of the SweetAlertIcons to output the iconHtml.
|
||||
iconHtml:
|
||||
iconClasses != null ? `<i class="swal-custom-icon bwi ${iconClasses}"></i>` : undefined,
|
||||
text: msg.text,
|
||||
html: msg.html,
|
||||
titleText: msg.title,
|
||||
showCancelButton: cancelText != null,
|
||||
cancelButtonText: cancelText,
|
||||
icon: "warning",
|
||||
iconHtml: '<i class="swal-custom-icon bwi bwi-exclamation-triangle text-warning"></i>',
|
||||
html: `${this.i18nService.t("desktopIntegrationVerificationText")}<br><br><strong>${
|
||||
msg.fingerprint
|
||||
}</strong>`,
|
||||
titleText: this.i18nService.t("desktopSyncVerificationTitle"),
|
||||
showConfirmButton: true,
|
||||
confirmButtonText: confirmText == null ? this.i18nService.t("ok") : confirmText,
|
||||
confirmButtonText: this.i18nService.t("ok"),
|
||||
timer: 300000,
|
||||
});
|
||||
|
||||
this.messagingService.send("showDialogResolve", {
|
||||
dialogId: msg.dialogId,
|
||||
confirmed: confirmed.value,
|
||||
});
|
||||
}
|
||||
|
||||
private async clearComponentStates() {
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { A11yModule } from "@angular/cdk/a11y";
|
||||
import { DialogModule } from "@angular/cdk/dialog";
|
||||
import { DragDropModule } from "@angular/cdk/drag-drop";
|
||||
import { LayoutModule } from "@angular/cdk/layout";
|
||||
import { OverlayModule } from "@angular/cdk/overlay";
|
||||
import { ScrollingModule } from "@angular/cdk/scrolling";
|
||||
// eslint-disable-next-line import/order
|
||||
import { CurrencyPipe, DatePipe } from "@angular/common";
|
||||
|
||||
// Register the locales for the application
|
||||
import "./locales";
|
||||
|
||||
import { NgModule } from "@angular/core";
|
||||
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
import { BrowserModule } from "@angular/platform-browser";
|
||||
@@ -76,6 +72,9 @@ import { SyncComponent } from "./settings/sync.component";
|
||||
import { VaultTimeoutInputComponent } from "./settings/vault-timeout-input.component";
|
||||
import { TabsComponent } from "./tabs.component";
|
||||
|
||||
// Register the locales for the application
|
||||
import "./locales";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
A11yModule,
|
||||
@@ -96,6 +95,7 @@ import { TabsComponent } from "./tabs.component";
|
||||
ReactiveFormsModule,
|
||||
ScrollingModule,
|
||||
ServicesModule,
|
||||
DialogModule,
|
||||
],
|
||||
declarations: [
|
||||
ActionButtonsComponent,
|
||||
|
||||
79
apps/browser/src/popup/services/browser-dialog.service.ts
Normal file
79
apps/browser/src/popup/services/browser-dialog.service.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import Swal, { SweetAlertIcon } from "sweetalert2";
|
||||
|
||||
import {
|
||||
DialogService,
|
||||
SimpleDialogOptions,
|
||||
SimpleDialogType,
|
||||
} from "@bitwarden/angular/services/dialog";
|
||||
|
||||
@Injectable()
|
||||
export class BrowserDialogService extends DialogService {
|
||||
async openSimpleDialog(options: SimpleDialogOptions) {
|
||||
const defaultCancel =
|
||||
options.cancelButtonText === undefined
|
||||
? options.acceptButtonText == null
|
||||
? "no"
|
||||
: "cancel"
|
||||
: null;
|
||||
|
||||
return this.legacyShowDialog(
|
||||
this.translate(options.content),
|
||||
this.translate(options.title),
|
||||
this.translate(options.acceptButtonText, "yes"),
|
||||
this.translate(options.cancelButtonText, defaultCancel),
|
||||
options.type
|
||||
);
|
||||
}
|
||||
|
||||
private async legacyShowDialog(
|
||||
body: string,
|
||||
title?: string,
|
||||
confirmText?: string,
|
||||
cancelText?: string,
|
||||
type?: SimpleDialogType
|
||||
) {
|
||||
let iconClasses: string = null;
|
||||
let icon: SweetAlertIcon = null;
|
||||
if (type != null) {
|
||||
// If you add custom types to this part, the type to SweetAlertIcon cast below needs to be changed.
|
||||
switch (type) {
|
||||
case "success":
|
||||
iconClasses = "bwi-check text-success";
|
||||
icon = "success";
|
||||
break;
|
||||
case "warning":
|
||||
iconClasses = "bwi-exclamation-triangle text-warning";
|
||||
icon = "warning";
|
||||
break;
|
||||
case "danger":
|
||||
iconClasses = "bwi-error text-danger";
|
||||
icon = "error";
|
||||
break;
|
||||
case "info":
|
||||
iconClasses = "bwi-info-circle text-info";
|
||||
icon = "info";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const confirmed = await Swal.fire({
|
||||
heightAuto: false,
|
||||
buttonsStyling: false,
|
||||
icon: icon,
|
||||
iconHtml:
|
||||
iconClasses != null ? `<i class="swal-custom-icon bwi ${iconClasses}"></i>` : undefined,
|
||||
text: body,
|
||||
titleText: title,
|
||||
showCancelButton: cancelText != null,
|
||||
cancelButtonText: cancelText,
|
||||
showConfirmButton: true,
|
||||
confirmButtonText: confirmText == null ? this.i18nService.t("ok") : confirmText,
|
||||
timer: 300000,
|
||||
});
|
||||
|
||||
return confirmed.value;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { APP_INITIALIZER, LOCALE_ID, NgModule } from "@angular/core";
|
||||
|
||||
import { LockGuard as BaseLockGuardService } from "@bitwarden/angular/auth/guards/lock.guard";
|
||||
import { UnauthGuard as BaseUnauthGuardService } from "@bitwarden/angular/auth/guards/unauth.guard";
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { MEMORY_STORAGE, SECURE_STORAGE } from "@bitwarden/angular/services/injection-tokens";
|
||||
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
|
||||
import { ThemingService } from "@bitwarden/angular/services/theming/theming.service";
|
||||
@@ -101,6 +102,7 @@ import { PasswordRepromptService } from "../../vault/popup/services/password-rep
|
||||
import { BrowserFolderService } from "../../vault/services/browser-folder.service";
|
||||
import { VaultFilterService } from "../../vault/services/vault-filter.service";
|
||||
|
||||
import { BrowserDialogService } from "./browser-dialog.service";
|
||||
import { DebounceNavigationService } from "./debounceNavigationService";
|
||||
import { InitService } from "./init.service";
|
||||
import { PopupSearchService } from "./popup-search.service";
|
||||
@@ -489,6 +491,10 @@ function getBgService<T>(service: keyof MainBackground) {
|
||||
useClass: BrowserConfigService,
|
||||
deps: [StateServiceAbstraction, ConfigApiServiceAbstraction],
|
||||
},
|
||||
{
|
||||
provide: DialogServiceAbstraction,
|
||||
useClass: BrowserDialogService,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class ServicesModule {}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Component } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { FolderAddEditComponent as BaseFolderAddEditComponent } from "@bitwarden/angular/vault/components/folder-add-edit.component";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||
@@ -22,9 +23,17 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent {
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
logService: LogService
|
||||
logService: LogService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(folderService, folderApiService, i18nService, platformUtilsService, logService);
|
||||
super(
|
||||
folderService,
|
||||
folderApiService,
|
||||
i18nService,
|
||||
platformUtilsService,
|
||||
logService,
|
||||
dialogService
|
||||
);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { CurrencyPipe, Location } from "@angular/common";
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/vault/components/premium.component";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
@@ -22,9 +23,10 @@ export class PremiumComponent extends BasePremiumComponent {
|
||||
stateService: StateService,
|
||||
logService: LogService,
|
||||
private location: Location,
|
||||
private currencyPipe: CurrencyPipe
|
||||
private currencyPipe: CurrencyPipe,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(i18nService, platformUtilsService, apiService, logService, stateService);
|
||||
super(i18nService, platformUtilsService, apiService, logService, stateService, dialogService);
|
||||
|
||||
// Support old price string. Can be removed in future once all translations are properly updated.
|
||||
const thePrice = this.currencyPipe.transform(this.price, "$");
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Router } from "@angular/router";
|
||||
import { concatMap, debounceTime, filter, map, Observable, Subject, takeUntil, tap } from "rxjs";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||
@@ -82,7 +83,8 @@ export class SettingsComponent implements OnInit {
|
||||
private stateService: StateService,
|
||||
private popupUtilsService: PopupUtilsService,
|
||||
private modalService: ModalService,
|
||||
private keyConnectorService: KeyConnectorService
|
||||
private keyConnectorService: KeyConnectorService,
|
||||
private dialogService: DialogServiceAbstraction
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@@ -185,13 +187,12 @@ export class SettingsComponent implements OnInit {
|
||||
|
||||
async saveVaultTimeout(newValue: number) {
|
||||
if (newValue == null) {
|
||||
const confirmed = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t("neverLockWarning"),
|
||||
null,
|
||||
this.i18nService.t("yes"),
|
||||
this.i18nService.t("cancel"),
|
||||
"warning"
|
||||
);
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "warning" },
|
||||
content: { key: "neverLockWarning" },
|
||||
type: SimpleDialogType.WARNING,
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
this.form.controls.vaultTimeout.setValue(this.previousVaultTimeout);
|
||||
return;
|
||||
@@ -222,13 +223,12 @@ export class SettingsComponent implements OnInit {
|
||||
|
||||
async saveVaultTimeoutAction(newValue: VaultTimeoutAction) {
|
||||
if (newValue === VaultTimeoutAction.LogOut) {
|
||||
const confirmed = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t("vaultTimeoutLogOutConfirmation"),
|
||||
this.i18nService.t("vaultTimeoutLogOutConfirmationTitle"),
|
||||
this.i18nService.t("yes"),
|
||||
this.i18nService.t("cancel"),
|
||||
"warning"
|
||||
);
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "vaultTimeoutLogOutConfirmationTitle" },
|
||||
content: { key: "vaultTimeoutLogOutConfirmation" },
|
||||
type: SimpleDialogType.WARNING,
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
this.vaultTimeoutActionOptions.forEach((option: any, i) => {
|
||||
if (option.value === this.form.value.vaultTimeoutAction) {
|
||||
@@ -284,24 +284,28 @@ export class SettingsComponent implements OnInit {
|
||||
console.error(e);
|
||||
|
||||
if (this.platformUtilsService.isFirefox() && this.popupUtilsService.inSidebar(window)) {
|
||||
await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t("nativeMessaginPermissionSidebarDesc"),
|
||||
this.i18nService.t("nativeMessaginPermissionSidebarTitle"),
|
||||
this.i18nService.t("ok"),
|
||||
null
|
||||
);
|
||||
await this.dialogService.openSimpleDialog({
|
||||
title: { key: "nativeMessaginPermissionSidebarTitle" },
|
||||
content: { key: "nativeMessaginPermissionSidebarDesc" },
|
||||
acceptButtonText: { key: "ok" },
|
||||
cancelButtonText: null,
|
||||
type: SimpleDialogType.INFO,
|
||||
});
|
||||
|
||||
this.form.controls.biometric.setValue(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!granted) {
|
||||
await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t("nativeMessaginPermissionErrorDesc"),
|
||||
this.i18nService.t("nativeMessaginPermissionErrorTitle"),
|
||||
this.i18nService.t("ok"),
|
||||
null
|
||||
);
|
||||
await this.dialogService.openSimpleDialog({
|
||||
title: { key: "nativeMessaginPermissionErrorTitle" },
|
||||
content: { key: "nativeMessaginPermissionErrorDesc" },
|
||||
acceptButtonText: { key: "ok" },
|
||||
cancelButtonText: null,
|
||||
type: SimpleDialogType.DANGER,
|
||||
});
|
||||
|
||||
this.form.controls.biometric.setValue(false);
|
||||
return;
|
||||
}
|
||||
@@ -349,13 +353,13 @@ export class SettingsComponent implements OnInit {
|
||||
|
||||
const error = BiometricErrors[e as BiometricErrorTypes];
|
||||
|
||||
this.platformUtilsService.showDialog(
|
||||
this.i18nService.t(error.description),
|
||||
this.i18nService.t(error.title),
|
||||
this.i18nService.t("ok"),
|
||||
null,
|
||||
"error"
|
||||
);
|
||||
this.dialogService.openSimpleDialog({
|
||||
title: { key: error.title },
|
||||
content: { key: error.description },
|
||||
acceptButtonText: { key: "ok" },
|
||||
cancelButtonText: null,
|
||||
type: SimpleDialogType.DANGER,
|
||||
});
|
||||
}),
|
||||
]);
|
||||
} else {
|
||||
@@ -375,24 +379,23 @@ export class SettingsComponent implements OnInit {
|
||||
}
|
||||
|
||||
async logOut() {
|
||||
const confirmed = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t("logOutConfirmation"),
|
||||
this.i18nService.t(VaultTimeoutAction.LogOut),
|
||||
this.i18nService.t("yes"),
|
||||
this.i18nService.t("cancel")
|
||||
);
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "logOut" },
|
||||
content: { key: "logOutConfirmation" },
|
||||
type: SimpleDialogType.INFO,
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
this.messagingService.send("logout");
|
||||
}
|
||||
}
|
||||
|
||||
async changePassword() {
|
||||
const confirmed = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t("changeMasterPasswordConfirmation"),
|
||||
this.i18nService.t("changeMasterPassword"),
|
||||
this.i18nService.t("yes"),
|
||||
this.i18nService.t("cancel")
|
||||
);
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "changeMasterPassword" },
|
||||
content: { key: "changeMasterPasswordConfirmation" },
|
||||
type: SimpleDialogType.INFO,
|
||||
});
|
||||
if (confirmed) {
|
||||
BrowserApi.createNewTab(
|
||||
"https://bitwarden.com/help/master-password/#change-your-master-password"
|
||||
@@ -401,24 +404,22 @@ export class SettingsComponent implements OnInit {
|
||||
}
|
||||
|
||||
async twoStep() {
|
||||
const confirmed = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t("twoStepLoginConfirmation"),
|
||||
this.i18nService.t("twoStepLogin"),
|
||||
this.i18nService.t("yes"),
|
||||
this.i18nService.t("cancel")
|
||||
);
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "twoStepLogin" },
|
||||
content: { key: "twoStepLoginConfirmation" },
|
||||
type: SimpleDialogType.INFO,
|
||||
});
|
||||
if (confirmed) {
|
||||
BrowserApi.createNewTab("https://bitwarden.com/help/setup-two-step-login/");
|
||||
}
|
||||
}
|
||||
|
||||
async share() {
|
||||
const confirmed = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t("learnOrgConfirmation"),
|
||||
this.i18nService.t("learnOrg"),
|
||||
this.i18nService.t("yes"),
|
||||
this.i18nService.t("cancel")
|
||||
);
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "learnOrg" },
|
||||
content: { key: "learnOrgConfirmation" },
|
||||
type: SimpleDialogType.INFO,
|
||||
});
|
||||
if (confirmed) {
|
||||
BrowserApi.createNewTab("https://bitwarden.com/help/about-organizations/");
|
||||
}
|
||||
|
||||
@@ -5,14 +5,7 @@ import { ClientType, DeviceType } from "@bitwarden/common/enums";
|
||||
import { BrowserApi } from "../browser/browserApi";
|
||||
import { SafariApp } from "../browser/safariApp";
|
||||
|
||||
const DialogPromiseExpiration = 600000; // 10 minutes
|
||||
|
||||
export default class BrowserPlatformUtilsService implements PlatformUtilsService {
|
||||
private showDialogResolves = new Map<number, { resolve: (value: boolean) => void; date: Date }>();
|
||||
private passwordDialogResolves = new Map<
|
||||
number,
|
||||
{ tryResolve: (canceled: boolean, password: string) => Promise<boolean>; date: Date }
|
||||
>();
|
||||
private static deviceCache: DeviceType = null;
|
||||
|
||||
constructor(
|
||||
@@ -215,29 +208,6 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService
|
||||
});
|
||||
}
|
||||
|
||||
showDialog(
|
||||
body: string,
|
||||
title?: string,
|
||||
confirmText?: string,
|
||||
cancelText?: string,
|
||||
type?: string,
|
||||
bodyIsHtml = false
|
||||
) {
|
||||
const dialogId = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
||||
this.messagingService.send("showDialog", {
|
||||
text: bodyIsHtml ? null : body,
|
||||
html: bodyIsHtml ? body : null,
|
||||
title: title,
|
||||
confirmText: confirmText,
|
||||
cancelText: cancelText,
|
||||
type: type,
|
||||
dialogId: dialogId,
|
||||
});
|
||||
return new Promise<boolean>((resolve) => {
|
||||
this.showDialogResolves.set(dialogId, { resolve: resolve, date: new Date() });
|
||||
});
|
||||
}
|
||||
|
||||
isDev(): boolean {
|
||||
return process.env.ENV === "development";
|
||||
}
|
||||
@@ -339,47 +309,6 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService
|
||||
return null;
|
||||
}
|
||||
|
||||
resolveDialogPromise(dialogId: number, confirmed: boolean) {
|
||||
if (this.showDialogResolves.has(dialogId)) {
|
||||
const resolveObj = this.showDialogResolves.get(dialogId);
|
||||
resolveObj.resolve(confirmed);
|
||||
this.showDialogResolves.delete(dialogId);
|
||||
}
|
||||
|
||||
// Clean up old promises
|
||||
this.showDialogResolves.forEach((val, key) => {
|
||||
const age = new Date().getTime() - val.date.getTime();
|
||||
if (age > DialogPromiseExpiration) {
|
||||
this.showDialogResolves.delete(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async resolvePasswordDialogPromise(
|
||||
dialogId: number,
|
||||
canceled: boolean,
|
||||
password: string
|
||||
): Promise<boolean> {
|
||||
let result = false;
|
||||
if (this.passwordDialogResolves.has(dialogId)) {
|
||||
const resolveObj = this.passwordDialogResolves.get(dialogId);
|
||||
if (await resolveObj.tryResolve(canceled, password)) {
|
||||
this.passwordDialogResolves.delete(dialogId);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up old promises
|
||||
this.passwordDialogResolves.forEach((val, key) => {
|
||||
const age = new Date().getTime() - val.date.getTime();
|
||||
if (age > DialogPromiseExpiration) {
|
||||
this.passwordDialogResolves.delete(key);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async supportsBiometric() {
|
||||
const platformInfo = await BrowserApi.getPlatformInfo();
|
||||
if (platformInfo.os === "android") {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Component } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component";
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
@@ -45,7 +46,8 @@ export class SendAddEditComponent extends BaseAddEditComponent {
|
||||
private location: Location,
|
||||
private popupUtilsService: PopupUtilsService,
|
||||
logService: LogService,
|
||||
sendApiService: SendApiService
|
||||
sendApiService: SendApiService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
@@ -57,7 +59,8 @@ export class SendAddEditComponent extends BaseAddEditComponent {
|
||||
policyService,
|
||||
logService,
|
||||
stateService,
|
||||
sendApiService
|
||||
sendApiService,
|
||||
dialogService
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ChangeDetectorRef, Component, NgZone } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component";
|
||||
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||
@@ -49,7 +50,8 @@ export class SendGroupingsComponent extends BaseSendComponent {
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private broadcasterService: BroadcasterService,
|
||||
logService: LogService,
|
||||
sendApiService: SendApiService
|
||||
sendApiService: SendApiService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(
|
||||
sendService,
|
||||
@@ -60,7 +62,8 @@ export class SendGroupingsComponent extends BaseSendComponent {
|
||||
searchService,
|
||||
policyService,
|
||||
logService,
|
||||
sendApiService
|
||||
sendApiService,
|
||||
dialogService
|
||||
);
|
||||
super.onSuccessfulLoad = async () => {
|
||||
this.calculateTypeCounts();
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ChangeDetectorRef, Component, NgZone } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component";
|
||||
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||
@@ -49,7 +50,8 @@ export class SendTypeComponent extends BaseSendComponent {
|
||||
private broadcasterService: BroadcasterService,
|
||||
private router: Router,
|
||||
logService: LogService,
|
||||
sendApiService: SendApiService
|
||||
sendApiService: SendApiService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(
|
||||
sendService,
|
||||
@@ -60,7 +62,8 @@ export class SendTypeComponent extends BaseSendComponent {
|
||||
searchService,
|
||||
policyService,
|
||||
logService,
|
||||
sendApiService
|
||||
sendApiService,
|
||||
dialogService
|
||||
);
|
||||
super.onSuccessfulLoad = async () => {
|
||||
this.selectType(this.type);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Component } from "@angular/core";
|
||||
import { UntypedFormBuilder } from "@angular/forms";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/tools/export/components/export.component";
|
||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
@@ -29,7 +30,8 @@ export class ExportComponent extends BaseExportComponent {
|
||||
logService: LogService,
|
||||
userVerificationService: UserVerificationService,
|
||||
formBuilder: UntypedFormBuilder,
|
||||
fileDownloadService: FileDownloadService
|
||||
fileDownloadService: FileDownloadService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(
|
||||
cryptoService,
|
||||
@@ -42,7 +44,8 @@ export class ExportComponent extends BaseExportComponent {
|
||||
logService,
|
||||
userVerificationService,
|
||||
formBuilder,
|
||||
fileDownloadService
|
||||
fileDownloadService,
|
||||
dialogService
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Component } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vault/components/add-edit.component";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
@@ -53,7 +54,8 @@ export class AddEditComponent extends BaseAddEditComponent {
|
||||
organizationService: OrganizationService,
|
||||
passwordRepromptService: PasswordRepromptService,
|
||||
logService: LogService,
|
||||
sendApiService: SendApiService
|
||||
sendApiService: SendApiService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(
|
||||
cipherService,
|
||||
@@ -69,7 +71,8 @@ export class AddEditComponent extends BaseAddEditComponent {
|
||||
logService,
|
||||
passwordRepromptService,
|
||||
organizationService,
|
||||
sendApiService
|
||||
sendApiService,
|
||||
dialogService
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Component } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { AttachmentsComponent as BaseAttachmentsComponent } from "@bitwarden/angular/vault/components/attachments.component";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||
@@ -31,7 +32,8 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
|
||||
private route: ActivatedRoute,
|
||||
stateService: StateService,
|
||||
logService: LogService,
|
||||
fileDownloadService: FileDownloadService
|
||||
fileDownloadService: FileDownloadService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(
|
||||
cipherService,
|
||||
@@ -42,7 +44,8 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
|
||||
window,
|
||||
logService,
|
||||
stateService,
|
||||
fileDownloadService
|
||||
fileDownloadService,
|
||||
dialogService
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ChangeDetectorRef, Component, NgZone } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ViewComponent as BaseViewComponent } from "@bitwarden/angular/vault/components/view.component";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
@@ -65,7 +66,8 @@ export class ViewComponent extends BaseViewComponent {
|
||||
apiService: ApiService,
|
||||
passwordRepromptService: PasswordRepromptService,
|
||||
logService: LogService,
|
||||
fileDownloadService: FileDownloadService
|
||||
fileDownloadService: FileDownloadService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(
|
||||
cipherService,
|
||||
@@ -85,7 +87,8 @@ export class ViewComponent extends BaseViewComponent {
|
||||
passwordRepromptService,
|
||||
logService,
|
||||
stateService,
|
||||
fileDownloadService
|
||||
fileDownloadService,
|
||||
dialogService
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user