mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 22:33:35 +00:00
[PM-16428] Option for primary click action to autofill on Vault view (#12557)
* add option for primary click action to autofill * setting option string * autofill setting for click items to autofill * fix showQuickCopyActions * apply setting
This commit is contained in:
@@ -1004,6 +1004,9 @@
|
|||||||
"showIdentitiesCurrentTabDesc": {
|
"showIdentitiesCurrentTabDesc": {
|
||||||
"message": "List identity items on the Tab page for easy autofill."
|
"message": "List identity items on the Tab page for easy autofill."
|
||||||
},
|
},
|
||||||
|
"clickToAutofillOnVault": {
|
||||||
|
"message": "Click items to autofill on Vault view"
|
||||||
|
},
|
||||||
"clearClipboard": {
|
"clearClipboard": {
|
||||||
"message": "Clear clipboard",
|
"message": "Clear clipboard",
|
||||||
"description": "Clipboard is the operating system thing where you copy/paste data to on your device."
|
"description": "Clipboard is the operating system thing where you copy/paste data to on your device."
|
||||||
|
|||||||
@@ -120,7 +120,7 @@
|
|||||||
/>
|
/>
|
||||||
<bit-label for="showCardsSuggestions">{{ "showCardsInVaultView" | i18n }}</bit-label>
|
<bit-label for="showCardsSuggestions">{{ "showCardsInVaultView" | i18n }}</bit-label>
|
||||||
</bit-form-control>
|
</bit-form-control>
|
||||||
<bit-form-control disableMargin>
|
<bit-form-control>
|
||||||
<input
|
<input
|
||||||
bitCheckbox
|
bitCheckbox
|
||||||
id="showIdentitiesSuggestions"
|
id="showIdentitiesSuggestions"
|
||||||
@@ -132,6 +132,18 @@
|
|||||||
{{ "showIdentitiesInVaultView" | i18n }}
|
{{ "showIdentitiesInVaultView" | i18n }}
|
||||||
</bit-label>
|
</bit-label>
|
||||||
</bit-form-control>
|
</bit-form-control>
|
||||||
|
<bit-form-control disableMargin>
|
||||||
|
<input
|
||||||
|
bitCheckbox
|
||||||
|
id="clickToAutofill"
|
||||||
|
type="checkbox"
|
||||||
|
(change)="updateClickItemsVaultView()"
|
||||||
|
[(ngModel)]="clickItemsVaultView"
|
||||||
|
/>
|
||||||
|
<bit-label for="clickToAutofill" class="tw-whitespace-normal">
|
||||||
|
{{ "clickToAutofillOnVault" | i18n }}
|
||||||
|
</bit-label>
|
||||||
|
</bit-form-control>
|
||||||
</bit-card>
|
</bit-card>
|
||||||
</bit-section>
|
</bit-section>
|
||||||
<bit-section>
|
<bit-section>
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ export class AutofillComponent implements OnInit {
|
|||||||
uriMatchOptions: { name: string; value: UriMatchStrategySetting }[];
|
uriMatchOptions: { name: string; value: UriMatchStrategySetting }[];
|
||||||
showCardsCurrentTab: boolean = true;
|
showCardsCurrentTab: boolean = true;
|
||||||
showIdentitiesCurrentTab: boolean = true;
|
showIdentitiesCurrentTab: boolean = true;
|
||||||
|
clickItemsVaultView: boolean = false;
|
||||||
autofillKeyboardHelperText: string;
|
autofillKeyboardHelperText: string;
|
||||||
accountSwitcherEnabled: boolean = false;
|
accountSwitcherEnabled: boolean = false;
|
||||||
|
|
||||||
@@ -207,6 +208,10 @@ export class AutofillComponent implements OnInit {
|
|||||||
this.showIdentitiesCurrentTab = await firstValueFrom(
|
this.showIdentitiesCurrentTab = await firstValueFrom(
|
||||||
this.vaultSettingsService.showIdentitiesCurrentTab$,
|
this.vaultSettingsService.showIdentitiesCurrentTab$,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.clickItemsVaultView = await firstValueFrom(
|
||||||
|
this.vaultSettingsService.clickItemsToAutofillVaultView$,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateInlineMenuVisibility() {
|
async updateInlineMenuVisibility() {
|
||||||
@@ -413,4 +418,8 @@ export class AutofillComponent implements OnInit {
|
|||||||
async updateShowInlineMenuIdentities() {
|
async updateShowInlineMenuIdentities() {
|
||||||
await this.autofillSettingsService.setShowInlineMenuIdentities(this.showInlineMenuIdentities);
|
await this.autofillSettingsService.setShowInlineMenuIdentities(this.showInlineMenuIdentities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateClickItemsVaultView() {
|
||||||
|
await this.vaultSettingsService.setClickItemsToAutofillVaultView(this.clickItemsVaultView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,4 +6,5 @@
|
|||||||
(onRefresh)="refreshCurrentTab()"
|
(onRefresh)="refreshCurrentTab()"
|
||||||
[description]="(showEmptyAutofillTip$ | async) ? ('autofillSuggestionsTip' | i18n) : null"
|
[description]="(showEmptyAutofillTip$ | async) ? ('autofillSuggestionsTip' | i18n) : null"
|
||||||
showAutofillButton
|
showAutofillButton
|
||||||
|
[primaryActionAutofill]="clickItemsToAutofillVaultView"
|
||||||
></app-vault-list-items-container>
|
></app-vault-list-items-container>
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from "@angular/common";
|
||||||
import { Component } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { combineLatest, map, Observable } from "rxjs";
|
import { combineLatest, firstValueFrom, map, Observable } from "rxjs";
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
|
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import {
|
import {
|
||||||
IconButtonModule,
|
IconButtonModule,
|
||||||
@@ -31,7 +32,7 @@ import { VaultListItemsContainerComponent } from "../vault-list-items-container/
|
|||||||
selector: "app-autofill-vault-list-items",
|
selector: "app-autofill-vault-list-items",
|
||||||
templateUrl: "autofill-vault-list-items.component.html",
|
templateUrl: "autofill-vault-list-items.component.html",
|
||||||
})
|
})
|
||||||
export class AutofillVaultListItemsComponent {
|
export class AutofillVaultListItemsComponent implements OnInit {
|
||||||
/**
|
/**
|
||||||
* The list of ciphers that can be used to autofill the current page.
|
* The list of ciphers that can be used to autofill the current page.
|
||||||
* @protected
|
* @protected
|
||||||
@@ -45,6 +46,8 @@ export class AutofillVaultListItemsComponent {
|
|||||||
*/
|
*/
|
||||||
protected showRefresh: boolean = BrowserPopupUtils.inSidebar(window);
|
protected showRefresh: boolean = BrowserPopupUtils.inSidebar(window);
|
||||||
|
|
||||||
|
clickItemsToAutofillVaultView = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observable that determines whether the empty autofill tip should be shown.
|
* Observable that determines whether the empty autofill tip should be shown.
|
||||||
* The tip is shown when there are no login ciphers to autofill, no filter is applied, and autofill is allowed in
|
* The tip is shown when there are no login ciphers to autofill, no filter is applied, and autofill is allowed in
|
||||||
@@ -65,10 +68,17 @@ export class AutofillVaultListItemsComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
private vaultPopupItemsService: VaultPopupItemsService,
|
private vaultPopupItemsService: VaultPopupItemsService,
|
||||||
private vaultPopupAutofillService: VaultPopupAutofillService,
|
private vaultPopupAutofillService: VaultPopupAutofillService,
|
||||||
|
private vaultSettingsService: VaultSettingsService,
|
||||||
) {
|
) {
|
||||||
// TODO: Migrate logic to show Autofill policy toast PM-8144
|
// TODO: Migrate logic to show Autofill policy toast PM-8144
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async ngOnInit() {
|
||||||
|
this.clickItemsToAutofillVaultView = await firstValueFrom(
|
||||||
|
this.vaultSettingsService.clickItemsToAutofillVaultView$,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refreshes the current tab to re-populate the autofill ciphers.
|
* Refreshes the current tab to re-populate the autofill ciphers.
|
||||||
* @protected
|
* @protected
|
||||||
|
|||||||
@@ -18,6 +18,11 @@
|
|||||||
</button>
|
</button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
<ng-container *ngIf="showViewOption">
|
||||||
|
<button type="button" bitMenuItem (click)="onView()">
|
||||||
|
{{ "view" | i18n }}
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
||||||
<button type="button" bitMenuItem (click)="toggleFavorite()">
|
<button type="button" bitMenuItem (click)="toggleFavorite()">
|
||||||
{{ favoriteText | i18n }}
|
{{ favoriteText | i18n }}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ export class ItemMoreOptionsComponent implements OnInit {
|
|||||||
return this._cipher$.value;
|
return this._cipher$.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag to show view item menu option. Used when something else is
|
||||||
|
* assigned as the primary action for the item, such as autofill.
|
||||||
|
*/
|
||||||
|
@Input({ transform: booleanAttribute })
|
||||||
|
showViewOption: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag to hide the autofill menu options. Used for items that are
|
* Flag to hide the autofill menu options. Used for items that are
|
||||||
* already in the autofill list suggestion.
|
* already in the autofill list suggestion.
|
||||||
@@ -111,6 +118,16 @@ export class ItemMoreOptionsComponent implements OnInit {
|
|||||||
await this.vaultPopupAutofillService.doAutofillAndSave(this.cipher, false);
|
await this.vaultPopupAutofillService.doAutofillAndSave(this.cipher, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async onView() {
|
||||||
|
const repromptPassed = await this.passwordRepromptService.passwordRepromptCheck(this.cipher);
|
||||||
|
if (!repromptPassed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.router.navigate(["/view-cipher"], {
|
||||||
|
queryParams: { cipherId: this.cipher.id, type: this.cipher.type },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles the favorite status of the cipher and updates it on the server.
|
* Toggles the favorite status of the cipher and updates it on the server.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -27,9 +27,11 @@
|
|||||||
<button
|
<button
|
||||||
bit-item-content
|
bit-item-content
|
||||||
type="button"
|
type="button"
|
||||||
(click)="onViewCipher(cipher)"
|
(click)="primaryActionAutofill ? doAutofill(cipher) : onViewCipher(cipher)"
|
||||||
(dblclick)="launchCipher(cipher)"
|
(dblclick)="launchCipher(cipher)"
|
||||||
[appA11yTitle]="'viewItemTitle' | i18n: cipher.name"
|
[appA11yTitle]="
|
||||||
|
(primaryActionAutofill ? 'autofillTitle' : 'viewItemTitle') | i18n: cipher.name
|
||||||
|
"
|
||||||
class="{{ itemHeightClass }}"
|
class="{{ itemHeightClass }}"
|
||||||
>
|
>
|
||||||
<app-vault-icon slot="start" [cipher]="cipher"></app-vault-icon>
|
<app-vault-icon slot="start" [cipher]="cipher"></app-vault-icon>
|
||||||
@@ -49,7 +51,7 @@
|
|||||||
<span slot="secondary">{{ cipher.subTitle }}</span>
|
<span slot="secondary">{{ cipher.subTitle }}</span>
|
||||||
</button>
|
</button>
|
||||||
<ng-container slot="end">
|
<ng-container slot="end">
|
||||||
<bit-item-action *ngIf="showAutofillButton">
|
<bit-item-action *ngIf="showAutofillButton && !primaryActionAutofill">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
bitBadge
|
bitBadge
|
||||||
@@ -75,6 +77,7 @@
|
|||||||
<app-item-more-options
|
<app-item-more-options
|
||||||
[cipher]="cipher"
|
[cipher]="cipher"
|
||||||
[hideAutofillOptions]="showAutofillButton"
|
[hideAutofillOptions]="showAutofillButton"
|
||||||
|
[showViewOption]="primaryActionAutofill"
|
||||||
></app-item-more-options>
|
></app-item-more-options>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</bit-item>
|
</bit-item>
|
||||||
|
|||||||
@@ -124,6 +124,12 @@ export class VaultListItemsContainerComponent implements AfterViewInit {
|
|||||||
@Input({ transform: booleanAttribute })
|
@Input({ transform: booleanAttribute })
|
||||||
showAutofillButton: boolean;
|
showAutofillButton: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Option to perform autofill operation as the primary action for autofill suggestions.
|
||||||
|
*/
|
||||||
|
@Input({ transform: booleanAttribute })
|
||||||
|
primaryActionAutofill: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the bottom margin from the bit-section in this component
|
* Remove the bottom margin from the bit-section in this component
|
||||||
* (used for containers at the end of the page where bottom margin is not needed)
|
* (used for containers at the end of the page where bottom margin is not needed)
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ export abstract class VaultSettingsService {
|
|||||||
*/
|
*/
|
||||||
showIdentitiesCurrentTab$: Observable<boolean>;
|
showIdentitiesCurrentTab$: Observable<boolean>;
|
||||||
/**
|
/**
|
||||||
|
/**
|
||||||
|
* An observable monitoring the state of the click items on the Vault view
|
||||||
|
* for Autofill suggestions.
|
||||||
|
*/
|
||||||
|
clickItemsToAutofillVaultView$: Observable<boolean>;
|
||||||
|
/**
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the enable passkeys setting to disk.
|
* Saves the enable passkeys setting to disk.
|
||||||
@@ -35,4 +41,10 @@ export abstract class VaultSettingsService {
|
|||||||
* @param value The new value for the show identities on tab page setting.
|
* @param value The new value for the show identities on tab page setting.
|
||||||
*/
|
*/
|
||||||
setShowIdentitiesCurrentTab: (value: boolean) => Promise<void>;
|
setShowIdentitiesCurrentTab: (value: boolean) => Promise<void>;
|
||||||
|
/**
|
||||||
|
* Saves the click items on vault View for Autofill suggestions to disk.
|
||||||
|
* @param value The new value for the click items on vault View for
|
||||||
|
* Autofill suggestions setting.
|
||||||
|
*/
|
||||||
|
setClickItemsToAutofillVaultView: (value: boolean) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,3 +25,12 @@ export const SHOW_IDENTITIES_CURRENT_TAB = new UserKeyDefinition<boolean>(
|
|||||||
clearOn: [], // do not clear user settings
|
clearOn: [], // do not clear user settings
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const CLICK_ITEMS_AUTOFILL_VAULT_VIEW = new UserKeyDefinition<boolean>(
|
||||||
|
VAULT_SETTINGS_DISK,
|
||||||
|
"clickItemsToAutofillOnVaultView",
|
||||||
|
{
|
||||||
|
deserializer: (obj) => obj,
|
||||||
|
clearOn: [], // do not clear user settings
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
SHOW_CARDS_CURRENT_TAB,
|
SHOW_CARDS_CURRENT_TAB,
|
||||||
SHOW_IDENTITIES_CURRENT_TAB,
|
SHOW_IDENTITIES_CURRENT_TAB,
|
||||||
USER_ENABLE_PASSKEYS,
|
USER_ENABLE_PASSKEYS,
|
||||||
|
CLICK_ITEMS_AUTOFILL_VAULT_VIEW,
|
||||||
} from "../key-state/vault-settings.state";
|
} from "../key-state/vault-settings.state";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,6 +40,14 @@ export class VaultSettingsService implements VaultSettingsServiceAbstraction {
|
|||||||
readonly showIdentitiesCurrentTab$: Observable<boolean> =
|
readonly showIdentitiesCurrentTab$: Observable<boolean> =
|
||||||
this.showIdentitiesCurrentTabState.state$.pipe(map((x) => x ?? true));
|
this.showIdentitiesCurrentTabState.state$.pipe(map((x) => x ?? true));
|
||||||
|
|
||||||
|
private clickItemsToAutofillVaultViewState: ActiveUserState<boolean> =
|
||||||
|
this.stateProvider.getActive(CLICK_ITEMS_AUTOFILL_VAULT_VIEW);
|
||||||
|
/**
|
||||||
|
* {@link VaultSettingsServiceAbstraction.clickItemsToAutofillVaultView$$}
|
||||||
|
*/
|
||||||
|
readonly clickItemsToAutofillVaultView$: Observable<boolean> =
|
||||||
|
this.clickItemsToAutofillVaultViewState.state$.pipe(map((x) => x ?? false));
|
||||||
|
|
||||||
constructor(private stateProvider: StateProvider) {}
|
constructor(private stateProvider: StateProvider) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,6 +64,13 @@ export class VaultSettingsService implements VaultSettingsServiceAbstraction {
|
|||||||
await this.showIdentitiesCurrentTabState.update(() => value);
|
await this.showIdentitiesCurrentTabState.update(() => value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link VaultSettingsServiceAbstraction.setClickItemsToAutofillVaultView}
|
||||||
|
*/
|
||||||
|
async setClickItemsToAutofillVaultView(value: boolean): Promise<void> {
|
||||||
|
await this.clickItemsToAutofillVaultViewState.update(() => value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link VaultSettingsServiceAbstraction.setEnablePasskeys}
|
* {@link VaultSettingsServiceAbstraction.setEnablePasskeys}
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user