mirror of
https://github.com/bitwarden/browser
synced 2025-12-19 09:43:23 +00:00
[PM-13989] - Extension Vault screen - allow copy icon to copy data directly if only 1 piece of data is available (#13520)
* wip - copy button overhaul * finalize item copy actions single item copy
This commit is contained in:
@@ -4236,6 +4236,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"copyFieldValue": {
|
||||||
|
"message": "Copy $FIELD$, $VALUE$",
|
||||||
|
"description": "Title for a button that copies a field value to the clipboard.",
|
||||||
|
"placeholders": {
|
||||||
|
"field": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Username"
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": "Foo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"noValuesToCopy": {
|
"noValuesToCopy": {
|
||||||
"message": "No values to copy"
|
"message": "No values to copy"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -35,6 +35,19 @@
|
|||||||
|
|
||||||
<ng-template #loginCopyMenu>
|
<ng-template #loginCopyMenu>
|
||||||
<bit-item-action>
|
<bit-item-action>
|
||||||
|
<button
|
||||||
|
*ngIf="singleCopiableLogin"
|
||||||
|
type="button"
|
||||||
|
bitIconButton="bwi-clone"
|
||||||
|
size="small"
|
||||||
|
[appA11yTitle]="
|
||||||
|
'copyFieldValue' | i18n: singleCopiableLogin.key : singleCopiableLogin.value
|
||||||
|
"
|
||||||
|
[appCopyClick]="singleCopiableLogin.value"
|
||||||
|
[valueLabel]="singleCopiableLogin.key"
|
||||||
|
showToast
|
||||||
|
></button>
|
||||||
|
<ng-container *ngIf="!singleCopiableLogin">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
bitIconButton="bwi-clone"
|
bitIconButton="bwi-clone"
|
||||||
@@ -62,6 +75,7 @@
|
|||||||
{{ "copyVerificationCode" | i18n }}
|
{{ "copyVerificationCode" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
</bit-menu>
|
</bit-menu>
|
||||||
|
</ng-container>
|
||||||
</bit-item-action>
|
</bit-item-action>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@@ -91,6 +105,17 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-template #cardCopyMenu>
|
<ng-template #cardCopyMenu>
|
||||||
<bit-item-action>
|
<bit-item-action>
|
||||||
|
<button
|
||||||
|
*ngIf="singleCopiableCard"
|
||||||
|
type="button"
|
||||||
|
bitIconButton="bwi-clone"
|
||||||
|
size="small"
|
||||||
|
[appA11yTitle]="'copyFieldValue' | i18n: singleCopiableCard.key : singleCopiableCard.value"
|
||||||
|
[appCopyClick]="singleCopiableCard.value"
|
||||||
|
[valueLabel]="singleCopiableCard.key"
|
||||||
|
showToast
|
||||||
|
></button>
|
||||||
|
<ng-container *ngIf="!singleCopiableCard">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
bitIconButton="bwi-clone"
|
bitIconButton="bwi-clone"
|
||||||
@@ -109,11 +134,25 @@
|
|||||||
{{ "copySecurityCode" | i18n }}
|
{{ "copySecurityCode" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
</bit-menu>
|
</bit-menu>
|
||||||
|
</ng-container>
|
||||||
</bit-item-action>
|
</bit-item-action>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<bit-item-action *ngIf="cipher.type === CipherType.Identity">
|
<bit-item-action *ngIf="cipher.type === CipherType.Identity">
|
||||||
|
<button
|
||||||
|
*ngIf="singleCopiableIdentity"
|
||||||
|
type="button"
|
||||||
|
bitIconButton="bwi-clone"
|
||||||
|
size="small"
|
||||||
|
[appA11yTitle]="
|
||||||
|
'copyFieldValue' | i18n: singleCopiableIdentity.key : singleCopiableIdentity.value
|
||||||
|
"
|
||||||
|
[appCopyClick]="singleCopiableIdentity.value"
|
||||||
|
[valueLabel]="singleCopiableIdentity.key"
|
||||||
|
showToast
|
||||||
|
></button>
|
||||||
|
<ng-container *ngIf="!singleCopiableIdentity">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
bitIconButton="bwi-clone"
|
bitIconButton="bwi-clone"
|
||||||
@@ -138,6 +177,7 @@
|
|||||||
{{ "copyAddress" | i18n }}
|
{{ "copyAddress" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
</bit-menu>
|
</bit-menu>
|
||||||
|
</ng-container>
|
||||||
</bit-item-action>
|
</bit-item-action>
|
||||||
|
|
||||||
<bit-item-action *ngIf="cipher.type === CipherType.SecureNote">
|
<bit-item-action *ngIf="cipher.type === CipherType.SecureNote">
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { CommonModule } from "@angular/common";
|
|||||||
import { Component, Input, inject } from "@angular/core";
|
import { Component, Input, inject } from "@angular/core";
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { IconButtonModule, ItemModule, MenuModule } from "@bitwarden/components";
|
import { IconButtonModule, ItemModule, MenuModule } from "@bitwarden/components";
|
||||||
@@ -11,6 +12,11 @@ import { CopyCipherFieldDirective } from "@bitwarden/vault";
|
|||||||
|
|
||||||
import { VaultPopupCopyButtonsService } from "../../../services/vault-popup-copy-buttons.service";
|
import { VaultPopupCopyButtonsService } from "../../../services/vault-popup-copy-buttons.service";
|
||||||
|
|
||||||
|
type CipherItem = {
|
||||||
|
value: string;
|
||||||
|
key: string;
|
||||||
|
};
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
standalone: true,
|
standalone: true,
|
||||||
selector: "app-item-copy-actions",
|
selector: "app-item-copy-actions",
|
||||||
@@ -37,6 +43,50 @@ export class ItemCopyActionsComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get singleCopiableLogin() {
|
||||||
|
const loginItems: CipherItem[] = [
|
||||||
|
{ value: this.cipher.login.username, key: "username" },
|
||||||
|
{ value: this.cipher.login.password, key: "password" },
|
||||||
|
{ value: this.cipher.login.totp, key: "totp" },
|
||||||
|
];
|
||||||
|
// If both the password and username are visible but the password is hidden, return the username
|
||||||
|
if (!this.cipher.viewPassword && this.cipher.login.username && this.cipher.login.password) {
|
||||||
|
return { value: this.cipher.login.username, key: this.i18nService.t("username") };
|
||||||
|
}
|
||||||
|
return this.findSingleCopiableItem(loginItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
get singleCopiableCard() {
|
||||||
|
const cardItems: CipherItem[] = [
|
||||||
|
{ value: this.cipher.card.code, key: "code" },
|
||||||
|
{ value: this.cipher.card.number, key: "number" },
|
||||||
|
];
|
||||||
|
return this.findSingleCopiableItem(cardItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
get singleCopiableIdentity() {
|
||||||
|
const identityItems: CipherItem[] = [
|
||||||
|
{ value: this.cipher.identity.fullAddressForCopy, key: "address" },
|
||||||
|
{ value: this.cipher.identity.email, key: "email" },
|
||||||
|
{ value: this.cipher.identity.username, key: "username" },
|
||||||
|
{ value: this.cipher.identity.phone, key: "phone" },
|
||||||
|
];
|
||||||
|
return this.findSingleCopiableItem(identityItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a list of CipherItems, if there is only one item with a value,
|
||||||
|
* return it with the translated key. Otherwise return null
|
||||||
|
*/
|
||||||
|
findSingleCopiableItem(items: { value: string; key: string }[]): CipherItem | null {
|
||||||
|
const singleItemWithValue = items.find(
|
||||||
|
(key) => key.value && items.every((f) => f === key || !f.value),
|
||||||
|
);
|
||||||
|
return singleItemWithValue
|
||||||
|
? { value: singleItemWithValue.value, key: this.i18nService.t(singleItemWithValue.key) }
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
get hasCardValues() {
|
get hasCardValues() {
|
||||||
return !!this.cipher.card.code || !!this.cipher.card.number;
|
return !!this.cipher.card.code || !!this.cipher.card.number;
|
||||||
}
|
}
|
||||||
@@ -62,5 +112,5 @@ export class ItemCopyActionsComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {}
|
constructor(private i18nService: I18nService) {}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user