mirror of
https://github.com/bitwarden/browser
synced 2025-12-14 23:33:31 +00:00
Use bit-select (+ReactiveForms) in Autofill on page load settings. (#13593)
* Use bit-select (+ReactiveForms) in Autofill on page load settings. * Use ReactiveForms for Additional options. * Disable margin reinclude from rebase.
This commit is contained in:
@@ -154,121 +154,115 @@
|
||||
</bit-item>
|
||||
</bit-section>
|
||||
<bit-section>
|
||||
<bit-section-header>
|
||||
<h2 bitTypography="h6">{{ "enableAutoFillOnPageLoadSectionTitle" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
<bit-card>
|
||||
<bit-hint class="tw-mb-6 tw-text-sm">
|
||||
{{ "enableAutoFillOnPageLoadDesc" | i18n }}
|
||||
<span
|
||||
><b>{{ "warningCapitalized" | i18n }}</b
|
||||
>: {{ "experimentalFeature" | i18n }}</span
|
||||
>
|
||||
<a
|
||||
bitLink
|
||||
class="tw-no-underline"
|
||||
href="https://bitwarden.com/help/auto-fill-browser/"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{{ "learnMoreAboutAutofillOnPageLoadLinkText" | i18n }}
|
||||
</a>
|
||||
</bit-hint>
|
||||
<bit-form-control>
|
||||
<input
|
||||
bitCheckbox
|
||||
id="autofillOnPageLoad"
|
||||
type="checkbox"
|
||||
(change)="updateAutofillOnPageLoad()"
|
||||
[(ngModel)]="enableAutofillOnPageLoad"
|
||||
[disabled]="autofillOnPageLoadFromPolicy$ | async"
|
||||
/>
|
||||
<bit-label for="autofillOnPageLoad">{{ "enableAutoFillOnPageLoad" | i18n }}</bit-label>
|
||||
<bit-hint class="tw-text-sm" *ngIf="autofillOnPageLoadFromPolicy$ | async">{{
|
||||
"enterprisePolicyRequirementsApplied" | i18n
|
||||
}}</bit-hint>
|
||||
</bit-form-control>
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label for="defaultAutofill">{{ "defaultAutoFillOnPageLoad" | i18n }}</bit-label>
|
||||
<select
|
||||
bitInput
|
||||
id="defaultAutofill"
|
||||
(change)="updateAutofillOnPageLoadDefault()"
|
||||
[(ngModel)]="autofillOnPageLoadDefault"
|
||||
[disabled]="!enableAutofillOnPageLoad"
|
||||
>
|
||||
<option
|
||||
*ngFor="let o of autofillOnPageLoadOptions"
|
||||
[ngValue]="o.value"
|
||||
[label]="o.name"
|
||||
></option>
|
||||
</select>
|
||||
<bit-hint class="tw-text-sm">
|
||||
{{ "defaultAutoFillOnPageLoadDesc" | i18n }}
|
||||
<form [formGroup]="autofillOnPageLoadForm">
|
||||
<bit-section-header>
|
||||
<legend>
|
||||
<h2 bitTypography="h6">{{ "enableAutoFillOnPageLoadSectionTitle" | i18n }}</h2>
|
||||
</legend>
|
||||
</bit-section-header>
|
||||
<bit-card>
|
||||
<bit-hint class="tw-mb-6 tw-text-sm">
|
||||
{{ "enableAutoFillOnPageLoadDesc" | i18n }}
|
||||
<span
|
||||
><b>{{ "warningCapitalized" | i18n }}</b
|
||||
>: {{ "experimentalFeature" | i18n }}</span
|
||||
>
|
||||
<a
|
||||
bitLink
|
||||
class="tw-no-underline"
|
||||
href="https://bitwarden.com/help/auto-fill-browser/"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{{ "learnMoreAboutAutofillOnPageLoadLinkText" | i18n }}
|
||||
</a>
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
</bit-card>
|
||||
<bit-form-control>
|
||||
<input
|
||||
formControlName="autofillOnPageLoad"
|
||||
bitCheckbox
|
||||
id="autofillOnPageLoad"
|
||||
type="checkbox"
|
||||
/>
|
||||
<bit-label for="autofillOnPageLoad">{{ "enableAutoFillOnPageLoad" | i18n }}</bit-label>
|
||||
<bit-hint class="tw-text-sm" *ngIf="autofillOnPageLoadFromPolicy$ | async">{{
|
||||
"enterprisePolicyRequirementsApplied" | i18n
|
||||
}}</bit-hint>
|
||||
</bit-form-control>
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label for="defaultAutofill">{{ "defaultAutoFillOnPageLoad" | i18n }}</bit-label>
|
||||
<bit-select formControlName="defaultAutofill" bitInput id="defaultAutofill">
|
||||
<bit-option
|
||||
*ngFor="let option of autofillOnPageLoadOptions"
|
||||
[label]="option.name"
|
||||
[value]="option.value"
|
||||
>
|
||||
</bit-option>
|
||||
</bit-select>
|
||||
<bit-hint class="tw-text-sm">
|
||||
{{ "defaultAutoFillOnPageLoadDesc" | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
</bit-card>
|
||||
</form>
|
||||
</bit-section>
|
||||
<bit-section [disableMargin]="!blockBrowserInjectionsByDomainEnabled">
|
||||
<bit-section-header>
|
||||
<h2 bitTypography="h6">{{ "additionalOptions" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
<bit-card>
|
||||
<bit-form-control>
|
||||
<input
|
||||
bitCheckbox
|
||||
id="context-menu"
|
||||
type="checkbox"
|
||||
(change)="updateContextMenuItem()"
|
||||
[(ngModel)]="enableContextMenuItem"
|
||||
/>
|
||||
<bit-label for="context-menu">{{ "enableContextMenuItem" | i18n }}</bit-label>
|
||||
</bit-form-control>
|
||||
<bit-form-control>
|
||||
<input
|
||||
bitCheckbox
|
||||
id="totp"
|
||||
type="checkbox"
|
||||
(change)="updateAutoTotpCopy()"
|
||||
[(ngModel)]="enableAutoTotpCopy"
|
||||
/>
|
||||
<bit-label for="totp">{{ "enableAutoTotpCopy" | i18n }}</bit-label>
|
||||
</bit-form-control>
|
||||
<bit-form-field>
|
||||
<bit-label for="clearClipboard">{{ "clearClipboard" | i18n }}</bit-label>
|
||||
<select
|
||||
aria-describedby="clearClipboardHelp"
|
||||
bitInput
|
||||
id="clearClipboard"
|
||||
(change)="saveClearClipboard()"
|
||||
[(ngModel)]="clearClipboard"
|
||||
>
|
||||
<option
|
||||
*ngFor="let o of clearClipboardOptions"
|
||||
[label]="o.name"
|
||||
[ngValue]="o.value"
|
||||
></option>
|
||||
</select>
|
||||
<bit-hint class="tw-text-sm" id="clearClipboardHelp">
|
||||
{{ "clearClipboardDesc" | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label for="defaultUriMatch">{{ "defaultUriMatchDetection" | i18n }}</bit-label>
|
||||
<select
|
||||
aria-describedby="defaultUriMatchHelp"
|
||||
bitInput
|
||||
id="defaultUriMatch"
|
||||
(change)="saveDefaultUriMatch()"
|
||||
[(ngModel)]="defaultUriMatch"
|
||||
>
|
||||
<option *ngFor="let o of uriMatchOptions" [label]="o.name" [ngValue]="o.value"></option>
|
||||
</select>
|
||||
<bit-hint class="tw-text-sm" id="defaultUriMatchHelp">
|
||||
{{ "defaultUriMatchDetectionDesc" | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
</bit-card>
|
||||
<form [formGroup]="additionalOptionsForm">
|
||||
<bit-section-header>
|
||||
<h2 bitTypography="h6">{{ "additionalOptions" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
<bit-card>
|
||||
<bit-form-control>
|
||||
<input
|
||||
formControlName="enableContextMenuItem"
|
||||
bitCheckbox
|
||||
id="context-menu"
|
||||
type="checkbox"
|
||||
/>
|
||||
<bit-label for="context-menu">{{ "enableContextMenuItem" | i18n }}</bit-label>
|
||||
</bit-form-control>
|
||||
<bit-form-control>
|
||||
<input formControlName="enableAutoTotpCopy" bitCheckbox id="totp" type="checkbox" />
|
||||
<bit-label for="totp">{{ "enableAutoTotpCopy" | i18n }}</bit-label>
|
||||
</bit-form-control>
|
||||
<bit-form-field>
|
||||
<bit-label for="clearClipboard">{{ "clearClipboard" | i18n }}</bit-label>
|
||||
<bit-select
|
||||
formControlName="clearClipboard"
|
||||
aria-describedby="clearClipboardHelp"
|
||||
bitInput
|
||||
id="clearClipboard"
|
||||
>
|
||||
<bit-option
|
||||
*ngFor="let option of clearClipboardOptions"
|
||||
[label]="option.name"
|
||||
[value]="option.value"
|
||||
></bit-option>
|
||||
</bit-select>
|
||||
<bit-hint class="tw-text-sm" id="clearClipboardHelp">
|
||||
{{ "clearClipboardDesc" | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label for="defaultUriMatch">{{ "defaultUriMatchDetection" | i18n }}</bit-label>
|
||||
<bit-select
|
||||
formControlName="defaultUriMatch"
|
||||
aria-describedby="defaultUriMatchHelp"
|
||||
bitInput
|
||||
id="defaultUriMatch"
|
||||
>
|
||||
<bit-option
|
||||
*ngFor="let option of uriMatchOptions"
|
||||
[label]="option.name"
|
||||
[value]="option.value"
|
||||
></bit-option>
|
||||
</bit-select>
|
||||
<bit-hint class="tw-text-sm" id="defaultUriMatchHelp">
|
||||
{{ "defaultUriMatchDetectionDesc" | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
</bit-card>
|
||||
</form>
|
||||
</bit-section>
|
||||
<bit-section *ngIf="blockBrowserInjectionsByDomainEnabled" disableMargin>
|
||||
<bit-item>
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { FormsModule } from "@angular/forms";
|
||||
import { Component, DestroyRef, OnInit } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import {
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
FormBuilder,
|
||||
FormGroup,
|
||||
FormControl,
|
||||
} from "@angular/forms";
|
||||
import { RouterModule } from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
@@ -73,6 +80,7 @@ import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.co
|
||||
SectionHeaderComponent,
|
||||
SelectModule,
|
||||
TypographyModule,
|
||||
ReactiveFormsModule,
|
||||
],
|
||||
})
|
||||
export class AutofillComponent implements OnInit {
|
||||
@@ -94,6 +102,18 @@ export class AutofillComponent implements OnInit {
|
||||
protected autofillOnPageLoadFromPolicy$ =
|
||||
this.autofillSettingsService.activateAutofillOnPageLoadFromPolicy$;
|
||||
|
||||
protected autofillOnPageLoadForm = new FormGroup({
|
||||
autofillOnPageLoad: new FormControl(),
|
||||
defaultAutofill: new FormControl(),
|
||||
});
|
||||
|
||||
protected additionalOptionsForm = new FormGroup({
|
||||
enableContextMenuItem: new FormControl(),
|
||||
enableAutoTotpCopy: new FormControl(),
|
||||
clearClipboard: new FormControl(),
|
||||
defaultUriMatch: new FormControl(),
|
||||
});
|
||||
|
||||
enableAutofillOnPageLoad: boolean = false;
|
||||
enableInlineMenu: boolean = false;
|
||||
enableInlineMenuOnIconSelect: boolean = false;
|
||||
@@ -121,10 +141,12 @@ export class AutofillComponent implements OnInit {
|
||||
private messagingService: MessagingService,
|
||||
private vaultSettingsService: VaultSettingsService,
|
||||
private configService: ConfigService,
|
||||
private formBuilder: FormBuilder,
|
||||
private destroyRef: DestroyRef,
|
||||
) {
|
||||
this.autofillOnPageLoadOptions = [
|
||||
{ name: i18nService.t("autoFillOnPageLoadYes"), value: true },
|
||||
{ name: i18nService.t("autoFillOnPageLoadNo"), value: false },
|
||||
{ name: this.i18nService.t("autoFillOnPageLoadYes"), value: true },
|
||||
{ name: this.i18nService.t("autoFillOnPageLoadNo"), value: false },
|
||||
];
|
||||
this.clearClipboardOptions = [
|
||||
{ name: i18nService.t("never"), value: ClearClipboardDelay.Never },
|
||||
@@ -181,27 +203,106 @@ export class AutofillComponent implements OnInit {
|
||||
this.inlineMenuVisibility === AutofillOverlayVisibility.OnFieldFocus ||
|
||||
this.enableInlineMenuOnIconSelect;
|
||||
|
||||
this.autofillSettingsService.activateAutofillOnPageLoadFromPolicy$
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((value) => {
|
||||
value
|
||||
? this.autofillOnPageLoadForm.controls.autofillOnPageLoad.disable({ emitEvent: false })
|
||||
: this.autofillOnPageLoadForm.controls.autofillOnPageLoad.enable({ emitEvent: false });
|
||||
});
|
||||
|
||||
this.enableAutofillOnPageLoad = await firstValueFrom(
|
||||
this.autofillSettingsService.autofillOnPageLoad$,
|
||||
);
|
||||
|
||||
this.autofillOnPageLoadForm.controls.autofillOnPageLoad.patchValue(
|
||||
this.enableAutofillOnPageLoad,
|
||||
{ emitEvent: false },
|
||||
);
|
||||
|
||||
this.autofillOnPageLoadDefault = await firstValueFrom(
|
||||
this.autofillSettingsService.autofillOnPageLoadDefault$,
|
||||
);
|
||||
|
||||
if (this.enableAutofillOnPageLoad === false) {
|
||||
this.autofillOnPageLoadForm.controls.defaultAutofill.disable();
|
||||
}
|
||||
|
||||
this.autofillOnPageLoadForm.controls.defaultAutofill.patchValue(
|
||||
this.autofillOnPageLoadDefault,
|
||||
{ emitEvent: false },
|
||||
);
|
||||
|
||||
this.autofillOnPageLoadForm.controls.autofillOnPageLoad.valueChanges
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((value) => {
|
||||
void this.autofillSettingsService.setAutofillOnPageLoad(value);
|
||||
this.enableDefaultAutofillControl(value);
|
||||
});
|
||||
|
||||
this.autofillOnPageLoadForm.controls.defaultAutofill.valueChanges
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((value) => {
|
||||
void this.autofillSettingsService.setAutofillOnPageLoadDefault(value);
|
||||
});
|
||||
|
||||
/** Additional options form */
|
||||
|
||||
this.enableContextMenuItem = await firstValueFrom(
|
||||
this.autofillSettingsService.enableContextMenu$,
|
||||
);
|
||||
|
||||
this.additionalOptionsForm.controls.enableContextMenuItem.patchValue(
|
||||
this.enableContextMenuItem,
|
||||
{ emitEvent: false },
|
||||
);
|
||||
|
||||
this.enableAutoTotpCopy = await firstValueFrom(this.autofillSettingsService.autoCopyTotp$);
|
||||
|
||||
this.additionalOptionsForm.controls.enableAutoTotpCopy.patchValue(this.enableAutoTotpCopy, {
|
||||
emitEvent: false,
|
||||
});
|
||||
|
||||
this.clearClipboard = await firstValueFrom(this.autofillSettingsService.clearClipboardDelay$);
|
||||
|
||||
this.additionalOptionsForm.controls.clearClipboard.patchValue(this.clearClipboard, {
|
||||
emitEvent: false,
|
||||
});
|
||||
|
||||
const defaultUriMatch = await firstValueFrom(
|
||||
this.domainSettingsService.defaultUriMatchStrategy$,
|
||||
);
|
||||
this.defaultUriMatch = defaultUriMatch == null ? UriMatchStrategy.Domain : defaultUriMatch;
|
||||
|
||||
this.additionalOptionsForm.controls.defaultUriMatch.patchValue(this.defaultUriMatch, {
|
||||
emitEvent: false,
|
||||
});
|
||||
|
||||
this.additionalOptionsForm.controls.enableContextMenuItem.valueChanges
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((value) => {
|
||||
void this.autofillSettingsService.setEnableContextMenu(value);
|
||||
this.messagingService.send("bgUpdateContextMenu");
|
||||
});
|
||||
|
||||
this.additionalOptionsForm.controls.enableAutoTotpCopy.valueChanges
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((value) => {
|
||||
void this.autofillSettingsService.setAutoCopyTotp(value);
|
||||
});
|
||||
|
||||
this.additionalOptionsForm.controls.clearClipboard.valueChanges
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((value) => {
|
||||
void this.autofillSettingsService.setClearClipboardDelay(value);
|
||||
});
|
||||
|
||||
this.additionalOptionsForm.controls.defaultUriMatch.valueChanges
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((value) => {
|
||||
void this.domainSettingsService.setDefaultUriMatchStrategy(value);
|
||||
});
|
||||
|
||||
const command = await this.platformUtilsService.getAutofillKeyboardShortcut();
|
||||
await this.setAutofillKeyboardHelperText(command);
|
||||
|
||||
@@ -230,17 +331,16 @@ export class AutofillComponent implements OnInit {
|
||||
await this.requestPrivacyPermission();
|
||||
}
|
||||
}
|
||||
|
||||
async updateAutofillOnPageLoad() {
|
||||
await this.autofillSettingsService.setAutofillOnPageLoad(this.enableAutofillOnPageLoad);
|
||||
async getAutofillOnPageLoadFromPolicy() {
|
||||
await firstValueFrom(this.autofillOnPageLoadFromPolicy$);
|
||||
}
|
||||
|
||||
async updateAutofillOnPageLoadDefault() {
|
||||
await this.autofillSettingsService.setAutofillOnPageLoadDefault(this.autofillOnPageLoadDefault);
|
||||
}
|
||||
|
||||
async saveDefaultUriMatch() {
|
||||
await this.domainSettingsService.setDefaultUriMatchStrategy(this.defaultUriMatch);
|
||||
enableDefaultAutofillControl(enable: boolean = true) {
|
||||
if (enable) {
|
||||
this.autofillOnPageLoadForm.controls.defaultAutofill.enable();
|
||||
} else {
|
||||
this.autofillOnPageLoadForm.controls.defaultAutofill.disable();
|
||||
}
|
||||
}
|
||||
|
||||
private async setAutofillKeyboardHelperText(command: string) {
|
||||
@@ -388,19 +488,6 @@ export class AutofillComponent implements OnInit {
|
||||
return await BrowserApi.permissionsGranted(["privacy"]);
|
||||
}
|
||||
|
||||
async updateContextMenuItem() {
|
||||
await this.autofillSettingsService.setEnableContextMenu(this.enableContextMenuItem);
|
||||
this.messagingService.send("bgUpdateContextMenu");
|
||||
}
|
||||
|
||||
async updateAutoTotpCopy() {
|
||||
await this.autofillSettingsService.setAutoCopyTotp(this.enableAutoTotpCopy);
|
||||
}
|
||||
|
||||
async saveClearClipboard() {
|
||||
await this.autofillSettingsService.setClearClipboardDelay(this.clearClipboard);
|
||||
}
|
||||
|
||||
async updateShowCardsCurrentTab() {
|
||||
await this.vaultSettingsService.setShowCardsCurrentTab(this.showCardsCurrentTab);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user