diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json
index a3ac0cda882..99c5960ab2d 100644
--- a/apps/browser/src/_locales/en/messages.json
+++ b/apps/browser/src/_locales/en/messages.json
@@ -4175,6 +4175,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": {
"message": "No values to copy"
},
diff --git a/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.html b/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.html
index fbfebe8efff..fbdc0b4b4b7 100644
--- a/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.html
+++ b/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.html
@@ -40,28 +40,41 @@
bitIconButton="bwi-clone"
size="small"
[appA11yTitle]="
- hasLoginValues ? ('copyInfoTitle' | i18n: cipher.name) : ('noValuesToCopy' | i18n)
+ 'copyFieldValue' | i18n: singleCopiableLogin.field : singleCopiableLogin.value
"
- [disabled]="!hasLoginValues"
- [bitMenuTriggerFor]="loginOptions"
+ [appCopyClick]="singleCopiableLogin.value"
+ [valueLabel]="singleCopiableLogin.field"
+ *ngIf="singleCopiableLogin"
>
-
-
+
-
-
+ bitIconButton="bwi-clone"
+ size="small"
+ [appA11yTitle]="
+ hasLoginValues ? ('copyInfoTitle' | i18n: cipher.name) : ('noValuesToCopy' | i18n)
+ "
+ [disabled]="!hasLoginValues"
+ [bitMenuTriggerFor]="loginOptions"
+ >
+
+
+
+
+
+
diff --git a/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.ts b/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.ts
index 53439dc4abd..d14675cc11c 100644
--- a/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.ts
+++ b/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.ts
@@ -37,6 +37,64 @@ export class ItemCopyActionsComponent {
);
}
+ get singleCopiableLogin() {
+ const { username, password, hasTotp, totp } = this.cipher.login;
+ // If there is both a username and password but the password is not viewable, then the username is the only copiable value
+ if (username && password && !this.cipher.viewPassword) {
+ return {
+ value: username,
+ field: "username",
+ };
+ }
+ if (username && !password && !hasTotp) {
+ return {
+ value: username,
+ field: "username",
+ };
+ }
+ if (!username && password && !hasTotp) {
+ return {
+ value: password,
+ field: "password",
+ };
+ }
+ if (!username && !password && hasTotp) {
+ return {
+ value: totp,
+ field: "totp",
+ };
+ }
+ return null;
+ }
+
+ get singleCopiableCardValue() {
+ const { code, number } = this.cipher.card;
+ if (code && !number) {
+ return code;
+ }
+ if (!code && number) {
+ return number;
+ }
+ return null;
+ }
+
+ get singleCopiableIdentityValue() {
+ const { fullAddressForCopy, email, username, phone } = this.cipher.identity;
+ if (fullAddressForCopy && !email && !username && !phone) {
+ return fullAddressForCopy;
+ }
+ if (!fullAddressForCopy && email && !username && !phone) {
+ return email;
+ }
+ if (!fullAddressForCopy && !email && username && !phone) {
+ return username;
+ }
+ if (!fullAddressForCopy && !email && !username && phone) {
+ return phone;
+ }
+ return null;
+ }
+
get hasCardValues() {
return !!this.cipher.card.code || !!this.cipher.card.number;
}