1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-06-26 10:35:48 +02:00

[PM-7172] Create account security settings component (navigational changes) (#8817)

* Move about.component into tools ownership

* Split out account security settings

Move settings.component.ts to auth/popup/settings and rename to account-security.component.ts
Move controls from settings.component.html and create account-security.component.html
Move settings.component.html to tools/popup/settings.component.html
Create settings.component.ts under tools/popup/settings
Fixup module imports and routing
Add new strings to en/message.json

* Move vault-timeout-input.component to auth

* Move await-desktop-dialog.component to auth

* Add transition for account-security

---------

Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
This commit is contained in:
Daniel James Smith 2024-05-07 22:23:03 +02:00 committed by GitHub
parent 3a71322510
commit 29bd03e64e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 300 additions and 205 deletions

View File

@ -374,12 +374,21 @@
"other": {
"message": "Other"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the extension"
},
@ -3023,6 +3032,9 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -0,0 +1,140 @@
<app-header>
<div class="left">
<button type="button" routerLink="/tabs/settings">
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
<span>{{ "back" | i18n }}</span>
</button>
</div>
<h1 class="center">
<span class="title">{{ "accountSecurity" | i18n }}</span>
</h1>
<div class="right">
<app-pop-out></app-pop-out>
</div>
</app-header>
<main tabindex="-1" [formGroup]="form">
<div class="box list">
<h2 class="box-header">{{ "unlockMethods" | i18n }}</h2>
<div class="box-content single-line">
<div class="box-content-row box-content-row-checkbox" appBoxRow *ngIf="supportsBiometric">
<label for="biometric">{{ "unlockWithBiometrics" | i18n }}</label>
<input id="biometric" type="checkbox" formControlName="biometric" />
</div>
<div
class="box-content-row box-content-row-checkbox"
appBoxRow
*ngIf="supportsBiometric && this.form.value.biometric"
>
<label for="autoBiometricsPrompt">{{ "enableAutoBiometricsPrompt" | i18n }}</label>
<input
id="autoBiometricsPrompt"
type="checkbox"
(change)="updateAutoBiometricsPrompt()"
formControlName="enableAutoBiometricsPrompt"
/>
</div>
<div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="pin">{{ "unlockWithPin" | i18n }}</label>
<input id="pin" type="checkbox" formControlName="pin" />
</div>
</div>
</div>
<div class="box list">
<h2 class="box-header">{{ "sessionTimeoutHeader" | i18n }}</h2>
<div class="box-content single-line">
<app-callout type="info" *ngIf="vaultTimeoutPolicyCallout | async as policy">
<span *ngIf="policy.timeout && policy.action">
{{
"vaultTimeoutPolicyWithActionInEffect"
| i18n: policy.timeout.hours : policy.timeout.minutes : (policy.action | i18n)
}}
</span>
<span *ngIf="policy.timeout && !policy.action">
{{ "vaultTimeoutPolicyInEffect" | i18n: policy.timeout.hours : policy.timeout.minutes }}
</span>
<span *ngIf="!policy.timeout && policy.action">
{{ "vaultTimeoutActionPolicyInEffect" | i18n: (policy.action | i18n) }}
</span>
</app-callout>
<app-vault-timeout-input
[vaultTimeoutOptions]="vaultTimeoutOptions"
[formControl]="form.controls.vaultTimeout"
ngDefaultControl
>
</app-vault-timeout-input>
<div class="box-content-row display-block" appBoxRow>
<label for="vaultTimeoutAction">{{ "vaultTimeoutAction" | i18n }}</label>
<select
id="vaultTimeoutAction"
name="VaultTimeoutActions"
formControlName="vaultTimeoutAction"
>
<option *ngFor="let action of availableVaultTimeoutActions" [ngValue]="action">
{{ action | i18n }}
</option>
</select>
</div>
<div
*ngIf="!availableVaultTimeoutActions.includes(VaultTimeoutAction.Lock)"
id="unlockMethodHelp"
class="box-footer"
>
{{ "unlockMethodNeededToChangeTimeoutActionDesc" | i18n }}
</div>
</div>
</div>
<div class="box list">
<h2 class="box-header">{{ "otherOptions" | i18n }}</h2>
<div class="box-content single-line">
<button
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
(click)="fingerprint()"
>
<div class="row-main">{{ "fingerprintPhrase" | i18n }}</div>
</button>
<button
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
(click)="twoStep()"
>
<div class="row-main">{{ "twoStepLogin" | i18n }}</div>
<i class="bwi bwi-external-link bwi-lg row-sub-icon" aria-hidden="true"></i>
</button>
<button
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
(click)="changePassword()"
*ngIf="showChangeMasterPass"
>
<div class="row-main">{{ "changeMasterPassword" | i18n }}</div>
<i class="bwi bwi-external-link bwi-lg row-sub-icon" aria-hidden="true"></i>
</button>
<button
*ngIf="
!accountSwitcherEnabled && availableVaultTimeoutActions.includes(VaultTimeoutAction.Lock)
"
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
(click)="lock()"
>
<div class="row-main">{{ "lockNow" | i18n }}</div>
<i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
</button>
<button
*ngIf="!accountSwitcherEnabled"
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
(click)="logOut()"
>
<div class="row-main">{{ "logOut" | i18n }}</div>
<i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
</button>
</div>
</div>
</main>

View File

@ -1,6 +1,5 @@
import { ChangeDetectorRef, Component, OnInit } from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { Router } from "@angular/router";
import {
BehaviorSubject,
combineLatest,
@ -23,7 +22,6 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
import { DeviceType } from "@bitwarden/common/enums";
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
@ -34,35 +32,20 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv
import { BiometricStateService } from "@bitwarden/common/platform/biometrics/biometric-state.service";
import { DialogService } from "@bitwarden/components";
import { SetPinComponent } from "../../auth/popup/components/set-pin.component";
import { BiometricErrors, BiometricErrorTypes } from "../../models/biometricErrors";
import { BrowserApi } from "../../platform/browser/browser-api";
import { enableAccountSwitching } from "../../platform/flags";
import BrowserPopupUtils from "../../platform/popup/browser-popup-utils";
import { BiometricErrors, BiometricErrorTypes } from "../../../models/biometricErrors";
import { BrowserApi } from "../../../platform/browser/browser-api";
import { enableAccountSwitching } from "../../../platform/flags";
import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils";
import { SetPinComponent } from "../components/set-pin.component";
import { AboutComponent } from "./about.component";
import { AwaitDesktopDialogComponent } from "./await-desktop-dialog.component";
const RateUrls = {
[DeviceType.ChromeExtension]:
"https://chromewebstore.google.com/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb/reviews",
[DeviceType.FirefoxExtension]:
"https://addons.mozilla.org/en-US/firefox/addon/bitwarden-password-manager/#reviews",
[DeviceType.OperaExtension]:
"https://addons.opera.com/en/extensions/details/bitwarden-free-password-manager/#feedback-container",
[DeviceType.EdgeExtension]:
"https://microsoftedge.microsoft.com/addons/detail/jbkfoedolllekgbhcbcoahefnbanhhlh",
[DeviceType.VivaldiExtension]:
"https://chromewebstore.google.com/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb/reviews",
[DeviceType.SafariExtension]: "https://apps.apple.com/app/bitwarden/id1352778147",
};
@Component({
selector: "app-settings",
templateUrl: "settings.component.html",
selector: "auth-account-security",
templateUrl: "account-security.component.html",
})
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class SettingsComponent implements OnInit {
export class AccountSecurityComponent implements OnInit {
protected readonly VaultTimeoutAction = VaultTimeoutAction;
availableVaultTimeoutActions: VaultTimeoutAction[] = [];
@ -95,7 +78,6 @@ export class SettingsComponent implements OnInit {
private vaultTimeoutService: VaultTimeoutService,
private vaultTimeoutSettingsService: VaultTimeoutSettingsService,
public messagingService: MessagingService,
private router: Router,
private environmentService: EnvironmentService,
private cryptoService: CryptoService,
private stateService: StateService,
@ -425,23 +407,6 @@ export class SettingsComponent implements OnInit {
);
}
async lock() {
await this.vaultTimeoutService.lock();
}
async logOut() {
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "logOut" },
content: { key: "logOutConfirmation" },
type: "info",
});
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
if (confirmed) {
this.messagingService.send("logout", { userId: userId });
}
}
async changePassword() {
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "continueToWebApp" },
@ -468,44 +433,6 @@ export class SettingsComponent implements OnInit {
}
}
async share() {
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "learnOrg" },
content: { key: "learnOrgConfirmation" },
type: "info",
});
if (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
BrowserApi.createNewTab("https://bitwarden.com/help/about-organizations/");
}
}
async webVault() {
const env = await firstValueFrom(this.environmentService.environment$);
const url = env.getWebVaultUrl();
await BrowserApi.createNewTab(url);
}
async import() {
await this.router.navigate(["/import"]);
if (await BrowserApi.isPopupOpen()) {
// 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
BrowserPopupUtils.openCurrentPagePopout(window);
}
}
export() {
// 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(["/export"]);
}
about() {
this.dialogService.open(AboutComponent);
}
async fingerprint() {
const fingerprint = await this.cryptoService.getFingerprint(
await this.stateService.getUserId(),
@ -518,11 +445,21 @@ export class SettingsComponent implements OnInit {
return firstValueFrom(dialogRef.closed);
}
rate() {
const deviceType = this.platformUtilsService.getDevice();
// 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
BrowserApi.createNewTab((RateUrls as any)[deviceType]);
async lock() {
await this.vaultTimeoutService.lock();
}
async logOut() {
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "logOut" },
content: { key: "logOutConfirmation" },
type: "info",
});
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
if (confirmed) {
this.messagingService.send("logout", { userId: userId });
}
}
ngOnDestroy() {

View File

@ -174,6 +174,9 @@ export const routerTransition = trigger("routerTransition", [
transition("clone-cipher => attachments, clone-cipher => collections", inSlideLeft),
transition("attachments => clone-cipher, collections => clone-cipher", outSlideRight),
transition("tabs => account-security", inSlideLeft),
transition("account-security => tabs", outSlideRight),
transition("tabs => import", inSlideLeft),
transition("import => tabs", outSlideRight),

View File

@ -21,6 +21,7 @@ import { LoginComponent } from "../auth/popup/login.component";
import { RegisterComponent } from "../auth/popup/register.component";
import { RemovePasswordComponent } from "../auth/popup/remove-password.component";
import { SetPasswordComponent } from "../auth/popup/set-password.component";
import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component";
import { SsoComponent } from "../auth/popup/sso.component";
import { TwoFactorOptionsComponent } from "../auth/popup/two-factor-options.component";
import { TwoFactorComponent } from "../auth/popup/two-factor.component";
@ -35,6 +36,7 @@ import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.compo
import { SendTypeComponent } from "../tools/popup/send/send-type.component";
import { ExportComponent } from "../tools/popup/settings/export.component";
import { ImportBrowserComponent } from "../tools/popup/settings/import/import-browser.component";
import { SettingsComponent } from "../tools/popup/settings/settings.component";
import { Fido2Component } from "../vault/popup/components/fido2/fido2.component";
import { AddEditComponent } from "../vault/popup/components/vault/add-edit.component";
import { AttachmentsComponent } from "../vault/popup/components/vault/attachments.component";
@ -53,7 +55,6 @@ import { ExcludedDomainsComponent } from "./settings/excluded-domains.component"
import { FoldersComponent } from "./settings/folders.component";
import { HelpAndFeedbackComponent } from "./settings/help-and-feedback.component";
import { OptionsComponent } from "./settings/options.component";
import { SettingsComponent } from "./settings/settings.component";
import { SyncComponent } from "./settings/sync.component";
import { TabsV2Component } from "./tabs-v2.component";
import { TabsComponent } from "./tabs.component";
@ -246,6 +247,12 @@ const routes: Routes = [
canActivate: [AuthGuard],
data: { state: "autofill" },
},
{
path: "account-security",
component: AccountSecurityComponent,
canActivate: [AuthGuard],
data: { state: "account-security" },
},
{
path: "folders",
component: FoldersComponent,

View File

@ -30,6 +30,8 @@ import { LoginComponent } from "../auth/popup/login.component";
import { RegisterComponent } from "../auth/popup/register.component";
import { RemovePasswordComponent } from "../auth/popup/remove-password.component";
import { SetPasswordComponent } from "../auth/popup/set-password.component";
import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component";
import { VaultTimeoutInputComponent } from "../auth/popup/settings/vault-timeout-input.component";
import { SsoComponent } from "../auth/popup/sso.component";
import { TwoFactorOptionsComponent } from "../auth/popup/two-factor-options.component";
import { TwoFactorComponent } from "../auth/popup/two-factor.component";
@ -49,6 +51,7 @@ import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.componen
import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component";
import { SendTypeComponent } from "../tools/popup/send/send-type.component";
import { ExportComponent } from "../tools/popup/settings/export.component";
import { SettingsComponent } from "../tools/popup/settings/settings.component";
import { ActionButtonsComponent } from "../vault/popup/components/action-buttons.component";
import { CipherRowComponent } from "../vault/popup/components/cipher-row.component";
import { Fido2CipherRowComponent } from "../vault/popup/components/fido2/fido2-cipher-row.component";
@ -77,9 +80,7 @@ import { ExcludedDomainsComponent } from "./settings/excluded-domains.component"
import { FoldersComponent } from "./settings/folders.component";
import { HelpAndFeedbackComponent } from "./settings/help-and-feedback.component";
import { OptionsComponent } from "./settings/options.component";
import { SettingsComponent } from "./settings/settings.component";
import { SyncComponent } from "./settings/sync.component";
import { VaultTimeoutInputComponent } from "./settings/vault-timeout-input.component";
import { TabsV2Component } from "./tabs-v2.component";
import { TabsComponent } from "./tabs.component";
@ -156,6 +157,7 @@ import "../platform/popup/locales";
SendListComponent,
SendTypeComponent,
SetPasswordComponent,
AccountSecurityComponent,
SettingsComponent,
ShareComponent,
SsoComponent,

View File

@ -7,10 +7,18 @@
</h1>
<div class="right"></div>
</app-header>
<main tabindex="-1" [formGroup]="form">
<main tabindex="-1">
<div class="box list">
<h2 class="box-header">{{ "manage" | i18n }}</h2>
<div class="box-content single-line">
<button
type="button"
class="box-content-row box-content-row-flex text-default"
routerLink="/account-security"
>
<div class="row-main">{{ "accountSecurity" | i18n }}</div>
<i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
</button>
<button
type="button"
class="box-content-row box-content-row-flex text-default"
@ -45,92 +53,6 @@
</button>
</div>
</div>
<div class="box list">
<h2 class="box-header">{{ "security" | i18n }}</h2>
<div class="box-content single-line">
<app-callout type="info" *ngIf="vaultTimeoutPolicyCallout | async as policy">
<span *ngIf="policy.timeout && policy.action">
{{
"vaultTimeoutPolicyWithActionInEffect"
| i18n: policy.timeout.hours : policy.timeout.minutes : (policy.action | i18n)
}}
</span>
<span *ngIf="policy.timeout && !policy.action">
{{ "vaultTimeoutPolicyInEffect" | i18n: policy.timeout.hours : policy.timeout.minutes }}
</span>
<span *ngIf="!policy.timeout && policy.action">
{{ "vaultTimeoutActionPolicyInEffect" | i18n: (policy.action | i18n) }}
</span>
</app-callout>
<app-vault-timeout-input
[vaultTimeoutOptions]="vaultTimeoutOptions"
[formControl]="form.controls.vaultTimeout"
ngDefaultControl
>
</app-vault-timeout-input>
<div class="box-content-row display-block" appBoxRow>
<label for="vaultTimeoutAction">{{ "vaultTimeoutAction" | i18n }}</label>
<select
id="vaultTimeoutAction"
name="VaultTimeoutActions"
formControlName="vaultTimeoutAction"
>
<option *ngFor="let action of availableVaultTimeoutActions" [ngValue]="action">
{{ action | i18n }}
</option>
</select>
</div>
<div
*ngIf="!availableVaultTimeoutActions.includes(VaultTimeoutAction.Lock)"
id="unlockMethodHelp"
class="box-footer"
>
{{ "unlockMethodNeededToChangeTimeoutActionDesc" | i18n }}
</div>
<div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="pin">{{ "unlockWithPin" | i18n }}</label>
<input id="pin" type="checkbox" formControlName="pin" />
</div>
<div class="box-content-row box-content-row-checkbox" appBoxRow *ngIf="supportsBiometric">
<label for="biometric">{{ "unlockWithBiometrics" | i18n }}</label>
<input id="biometric" type="checkbox" formControlName="biometric" />
</div>
<div
class="box-content-row box-content-row-checkbox"
appBoxRow
*ngIf="supportsBiometric && this.form.value.biometric"
>
<label for="autoBiometricsPrompt">{{ "enableAutoBiometricsPrompt" | i18n }}</label>
<input
id="autoBiometricsPrompt"
type="checkbox"
(change)="updateAutoBiometricsPrompt()"
formControlName="enableAutoBiometricsPrompt"
/>
</div>
<button
*ngIf="
!accountSwitcherEnabled && availableVaultTimeoutActions.includes(VaultTimeoutAction.Lock)
"
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
(click)="lock()"
>
<div class="row-main">{{ "lockNow" | i18n }}</div>
<i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
</button>
<button
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
(click)="twoStep()"
>
<div class="row-main">{{ "twoStepLogin" | i18n }}</div>
<i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
</button>
</div>
</div>
<div class="box list">
<h2 class="box-header">{{ "account" | i18n }}</h2>
<div class="box-content single-line">
@ -145,35 +67,6 @@
</div>
<span><i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i></span>
</button>
<button
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
(click)="changePassword()"
*ngIf="showChangeMasterPass"
>
<div class="row-main">{{ "changeMasterPassword" | i18n }}</div>
<i class="bwi bwi-external-link bwi-lg row-sub-icon" aria-hidden="true"></i>
</button>
<button
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
(click)="fingerprint()"
>
<div class="row-main">{{ "fingerprintPhrase" | i18n }}</div>
<i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
</button>
<button
*ngIf="!accountSwitcherEnabled"
type="button"
class="box-content-row box-content-row-flex text-default"
appStopClick
(click)="logOut()"
>
<div class="row-main">{{ "logOut" | i18n }}</div>
<i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
</button>
</div>
</div>
<div class="box list">

View File

@ -0,0 +1,101 @@
import { Component, OnInit } from "@angular/core";
import { Router } from "@angular/router";
import { firstValueFrom, Subject } from "rxjs";
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
import { DeviceType } from "@bitwarden/common/enums";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { DialogService } from "@bitwarden/components";
import { BrowserApi } from "../../../platform/browser/browser-api";
import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils";
import { AboutComponent } from "./about/about.component";
const RateUrls = {
[DeviceType.ChromeExtension]:
"https://chromewebstore.google.com/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb/reviews",
[DeviceType.FirefoxExtension]:
"https://addons.mozilla.org/en-US/firefox/addon/bitwarden-password-manager/#reviews",
[DeviceType.OperaExtension]:
"https://addons.opera.com/en/extensions/details/bitwarden-free-password-manager/#feedback-container",
[DeviceType.EdgeExtension]:
"https://microsoftedge.microsoft.com/addons/detail/jbkfoedolllekgbhcbcoahefnbanhhlh",
[DeviceType.VivaldiExtension]:
"https://chromewebstore.google.com/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb/reviews",
[DeviceType.SafariExtension]: "https://apps.apple.com/app/bitwarden/id1352778147",
};
@Component({
selector: "tools-settings",
templateUrl: "settings.component.html",
})
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class SettingsComponent implements OnInit {
private destroy$ = new Subject<void>();
constructor(
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private vaultTimeoutService: VaultTimeoutService,
public messagingService: MessagingService,
private router: Router,
private environmentService: EnvironmentService,
private dialogService: DialogService,
) {}
async ngOnInit() {}
async share() {
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "learnOrg" },
content: { key: "learnOrgConfirmation" },
type: "info",
});
if (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
BrowserApi.createNewTab("https://bitwarden.com/help/about-organizations/");
}
}
async webVault() {
const env = await firstValueFrom(this.environmentService.environment$);
const url = env.getWebVaultUrl();
await BrowserApi.createNewTab(url);
}
async import() {
await this.router.navigate(["/import"]);
if (await BrowserApi.isPopupOpen()) {
// 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
BrowserPopupUtils.openCurrentPagePopout(window);
}
}
export() {
// 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(["/export"]);
}
about() {
this.dialogService.open(AboutComponent);
}
rate() {
const deviceType = this.platformUtilsService.getDevice();
// 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
BrowserApi.createNewTab((RateUrls as any)[deviceType]);
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}