1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +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:
Kyle Spearrin
2024-12-27 08:51:17 -05:00
committed by GitHub
parent b3155d19dd
commit f434334a88
12 changed files with 110 additions and 7 deletions

View File

@@ -1004,6 +1004,9 @@
"showIdentitiesCurrentTabDesc": {
"message": "List identity items on the Tab page for easy autofill."
},
"clickToAutofillOnVault": {
"message": "Click items to autofill on Vault view"
},
"clearClipboard": {
"message": "Clear clipboard",
"description": "Clipboard is the operating system thing where you copy/paste data to on your device."

View File

@@ -120,7 +120,7 @@
/>
<bit-label for="showCardsSuggestions">{{ "showCardsInVaultView" | i18n }}</bit-label>
</bit-form-control>
<bit-form-control disableMargin>
<bit-form-control>
<input
bitCheckbox
id="showIdentitiesSuggestions"
@@ -132,6 +132,18 @@
{{ "showIdentitiesInVaultView" | i18n }}
</bit-label>
</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-section>
<bit-section>

View File

@@ -110,6 +110,7 @@ export class AutofillComponent implements OnInit {
uriMatchOptions: { name: string; value: UriMatchStrategySetting }[];
showCardsCurrentTab: boolean = true;
showIdentitiesCurrentTab: boolean = true;
clickItemsVaultView: boolean = false;
autofillKeyboardHelperText: string;
accountSwitcherEnabled: boolean = false;
@@ -207,6 +208,10 @@ export class AutofillComponent implements OnInit {
this.showIdentitiesCurrentTab = await firstValueFrom(
this.vaultSettingsService.showIdentitiesCurrentTab$,
);
this.clickItemsVaultView = await firstValueFrom(
this.vaultSettingsService.clickItemsToAutofillVaultView$,
);
}
async updateInlineMenuVisibility() {
@@ -413,4 +418,8 @@ export class AutofillComponent implements OnInit {
async updateShowInlineMenuIdentities() {
await this.autofillSettingsService.setShowInlineMenuIdentities(this.showInlineMenuIdentities);
}
async updateClickItemsVaultView() {
await this.vaultSettingsService.setClickItemsToAutofillVaultView(this.clickItemsVaultView);
}
}

View File

@@ -6,4 +6,5 @@
(onRefresh)="refreshCurrentTab()"
[description]="(showEmptyAutofillTip$ | async) ? ('autofillSuggestionsTip' | i18n) : null"
showAutofillButton
[primaryActionAutofill]="clickItemsToAutofillVaultView"
></app-vault-list-items-container>

View File

@@ -1,8 +1,9 @@
import { CommonModule } from "@angular/common";
import { Component } from "@angular/core";
import { combineLatest, map, Observable } from "rxjs";
import { Component, OnInit } from "@angular/core";
import { combineLatest, firstValueFrom, map, Observable } from "rxjs";
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 {
IconButtonModule,
@@ -31,7 +32,7 @@ import { VaultListItemsContainerComponent } from "../vault-list-items-container/
selector: "app-autofill-vault-list-items",
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.
* @protected
@@ -45,6 +46,8 @@ export class AutofillVaultListItemsComponent {
*/
protected showRefresh: boolean = BrowserPopupUtils.inSidebar(window);
clickItemsToAutofillVaultView = false;
/**
* 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
@@ -65,10 +68,17 @@ export class AutofillVaultListItemsComponent {
constructor(
private vaultPopupItemsService: VaultPopupItemsService,
private vaultPopupAutofillService: VaultPopupAutofillService,
private vaultSettingsService: VaultSettingsService,
) {
// 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.
* @protected

View File

@@ -18,6 +18,11 @@
</button>
</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()">
{{ favoriteText | i18n }}
</button>

View File

@@ -46,6 +46,13 @@ export class ItemMoreOptionsComponent implements OnInit {
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
* already in the autofill list suggestion.
@@ -111,6 +118,16 @@ export class ItemMoreOptionsComponent implements OnInit {
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.
*/

View File

@@ -27,9 +27,11 @@
<button
bit-item-content
type="button"
(click)="onViewCipher(cipher)"
(click)="primaryActionAutofill ? doAutofill(cipher) : onViewCipher(cipher)"
(dblclick)="launchCipher(cipher)"
[appA11yTitle]="'viewItemTitle' | i18n: cipher.name"
[appA11yTitle]="
(primaryActionAutofill ? 'autofillTitle' : 'viewItemTitle') | i18n: cipher.name
"
class="{{ itemHeightClass }}"
>
<app-vault-icon slot="start" [cipher]="cipher"></app-vault-icon>
@@ -49,7 +51,7 @@
<span slot="secondary">{{ cipher.subTitle }}</span>
</button>
<ng-container slot="end">
<bit-item-action *ngIf="showAutofillButton">
<bit-item-action *ngIf="showAutofillButton && !primaryActionAutofill">
<button
type="button"
bitBadge
@@ -75,6 +77,7 @@
<app-item-more-options
[cipher]="cipher"
[hideAutofillOptions]="showAutofillButton"
[showViewOption]="primaryActionAutofill"
></app-item-more-options>
</ng-container>
</bit-item>

View File

@@ -124,6 +124,12 @@ export class VaultListItemsContainerComponent implements AfterViewInit {
@Input({ transform: booleanAttribute })
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
* (used for containers at the end of the page where bottom margin is not needed)

View File

@@ -19,6 +19,12 @@ export abstract class VaultSettingsService {
*/
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.
@@ -35,4 +41,10 @@ export abstract class VaultSettingsService {
* @param value The new value for the show identities on tab page setting.
*/
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>;
}

View File

@@ -25,3 +25,12 @@ export const SHOW_IDENTITIES_CURRENT_TAB = new UserKeyDefinition<boolean>(
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
},
);

View File

@@ -6,6 +6,7 @@ import {
SHOW_CARDS_CURRENT_TAB,
SHOW_IDENTITIES_CURRENT_TAB,
USER_ENABLE_PASSKEYS,
CLICK_ITEMS_AUTOFILL_VAULT_VIEW,
} from "../key-state/vault-settings.state";
/**
@@ -39,6 +40,14 @@ export class VaultSettingsService implements VaultSettingsServiceAbstraction {
readonly showIdentitiesCurrentTab$: Observable<boolean> =
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) {}
/**
@@ -55,6 +64,13 @@ export class VaultSettingsService implements VaultSettingsServiceAbstraction {
await this.showIdentitiesCurrentTabState.update(() => value);
}
/**
* {@link VaultSettingsServiceAbstraction.setClickItemsToAutofillVaultView}
*/
async setClickItemsToAutofillVaultView(value: boolean): Promise<void> {
await this.clickItemsToAutofillVaultViewState.update(() => value);
}
/**
* {@link VaultSettingsServiceAbstraction.setEnablePasskeys}
*/