From 17c9b26336c5fe03d9c248851d281817e72b19b6 Mon Sep 17 00:00:00 2001 From: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> Date: Mon, 23 Sep 2024 08:55:23 -0500 Subject: [PATCH] [PM-12252] Autofill name of new ciphers (#11127) * autofill name for new ciphers * only include name and uri when the extension is not popped out * only populate name and uri for login ciphers * source the URL directly from the new item dropdown component * fix new item dropdown tests --- .../new-item-dropdown-v2.component.spec.ts | 56 +++++++++++++++---- .../new-item-dropdown-v2.component.ts | 24 ++++++-- .../components/vault/vault-v2.component.ts | 2 - 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.spec.ts b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.spec.ts index 868cb242aa..6842f35ea6 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.spec.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.spec.ts @@ -7,6 +7,8 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { CipherType } from "@bitwarden/common/vault/enums"; import { ButtonModule, DialogService, MenuModule } from "@bitwarden/components"; +import { BrowserApi } from "../../../../../platform/browser/browser-api"; +import BrowserPopupUtils from "../../../../../platform/popup/browser-popup-utils"; import { AddEditQueryParams } from "../add-edit/add-edit-v2.component"; import { AddEditFolderDialogComponent } from "../add-edit-folder-dialog/add-edit-folder-dialog.component"; @@ -18,6 +20,10 @@ describe("NewItemDropdownV2Component", () => { const open = jest.fn(); const navigate = jest.fn(); + jest + .spyOn(BrowserApi, "getTabFromCurrentWindow") + .mockResolvedValue({ url: "https://example.com" } as chrome.tabs.Tab); + beforeEach(async () => { open.mockClear(); navigate.mockClear(); @@ -54,46 +60,74 @@ describe("NewItemDropdownV2Component", () => { jest.spyOn(component, "newItemNavigate"); }); - it("navigates to new login", () => { - component.newItemNavigate(CipherType.Login); + it("navigates to new login", async () => { + await component.newItemNavigate(CipherType.Login); expect(navigate).toHaveBeenCalledWith(["/add-cipher"], { - queryParams: { type: CipherType.Login.toString(), ...emptyParams }, + queryParams: { + type: CipherType.Login.toString(), + name: "example.com", + uri: "https://example.com", + ...emptyParams, + }, }); }); - it("navigates to new card", () => { - component.newItemNavigate(CipherType.Card); + it("navigates to new card", async () => { + await component.newItemNavigate(CipherType.Card); expect(navigate).toHaveBeenCalledWith(["/add-cipher"], { queryParams: { type: CipherType.Card.toString(), ...emptyParams }, }); }); - it("navigates to new identity", () => { - component.newItemNavigate(CipherType.Identity); + it("navigates to new identity", async () => { + await component.newItemNavigate(CipherType.Identity); expect(navigate).toHaveBeenCalledWith(["/add-cipher"], { queryParams: { type: CipherType.Identity.toString(), ...emptyParams }, }); }); - it("navigates to new note", () => { - component.newItemNavigate(CipherType.SecureNote); + it("navigates to new note", async () => { + await component.newItemNavigate(CipherType.SecureNote); expect(navigate).toHaveBeenCalledWith(["/add-cipher"], { queryParams: { type: CipherType.SecureNote.toString(), ...emptyParams }, }); }); - it("includes initial values", () => { + it("includes initial values", async () => { component.initialValues = { folderId: "222-333-444", organizationId: "444-555-666", collectionId: "777-888-999", } as NewItemInitialValues; - component.newItemNavigate(CipherType.Login); + await component.newItemNavigate(CipherType.Login); + + expect(navigate).toHaveBeenCalledWith(["/add-cipher"], { + queryParams: { + type: CipherType.Login.toString(), + folderId: "222-333-444", + organizationId: "444-555-666", + collectionId: "777-888-999", + uri: "https://example.com", + name: "example.com", + }, + }); + }); + + it("does not include name or uri when the extension is popped out", async () => { + jest.spyOn(BrowserPopupUtils, "inPopout").mockReturnValue(true); + + component.initialValues = { + folderId: "222-333-444", + organizationId: "444-555-666", + collectionId: "777-888-999", + } as NewItemInitialValues; + + await component.newItemNavigate(CipherType.Login); expect(navigate).toHaveBeenCalledWith(["/add-cipher"], { queryParams: { diff --git a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts index daa0f3d795..a1d5cbd332 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts @@ -3,10 +3,13 @@ import { Component, Input } from "@angular/core"; import { Router, RouterLink } from "@angular/router"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid"; import { CipherType } from "@bitwarden/common/vault/enums"; import { ButtonModule, DialogService, MenuModule, NoItemsModule } from "@bitwarden/components"; +import { BrowserApi } from "../../../../../platform/browser/browser-api"; +import BrowserPopupUtils from "../../../../../platform/popup/browser-popup-utils"; import { AddEditQueryParams } from "../add-edit/add-edit-v2.component"; import { AddEditFolderDialogComponent } from "../add-edit-folder-dialog/add-edit-folder-dialog.component"; @@ -14,7 +17,6 @@ export interface NewItemInitialValues { folderId?: string; organizationId?: OrganizationId; collectionId?: CollectionId; - uri?: string; } @Component({ @@ -37,18 +39,30 @@ export class NewItemDropdownV2Component { private dialogService: DialogService, ) {} - private buildQueryParams(type: CipherType): AddEditQueryParams { + private async buildQueryParams(type: CipherType): Promise { + const tab = await BrowserApi.getTabFromCurrentWindow(); + const poppedOut = BrowserPopupUtils.inPopout(window); + + const loginDetails: { uri?: string; name?: string } = {}; + + // When a Login Cipher is created and the extension is not popped out, + // pass along the uri and name + if (!poppedOut && type === CipherType.Login && tab) { + loginDetails.uri = tab.url; + loginDetails.name = Utils.getHostname(tab.url); + } + return { type: type.toString(), collectionId: this.initialValues?.collectionId, organizationId: this.initialValues?.organizationId, folderId: this.initialValues?.folderId, - uri: this.initialValues?.uri, + ...loginDetails, }; } - newItemNavigate(type: CipherType) { - void this.router.navigate(["/add-cipher"], { queryParams: this.buildQueryParams(type) }); + async newItemNavigate(type: CipherType) { + await this.router.navigate(["/add-cipher"], { queryParams: await this.buildQueryParams(type) }); } openFolderDialog() { diff --git a/apps/browser/src/vault/popup/components/vault/vault-v2.component.ts b/apps/browser/src/vault/popup/components/vault/vault-v2.component.ts index c088626487..21c7133299 100644 --- a/apps/browser/src/vault/popup/components/vault/vault-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault/vault-v2.component.ts @@ -12,7 +12,6 @@ import { ButtonModule, Icons, NoItemsModule } from "@bitwarden/components"; import { VaultIcons } from "@bitwarden/vault"; import { CurrentAccountComponent } from "../../../../auth/popup/account-switching/current-account.component"; -import { BrowserApi } from "../../../../platform/browser/browser-api"; import { PopOutComponent } from "../../../../platform/popup/components/pop-out.component"; import { PopupHeaderComponent } from "../../../../platform/popup/layout/popup-header.component"; import { PopupPageComponent } from "../../../../platform/popup/layout/popup-page.component"; @@ -72,7 +71,6 @@ export class VaultV2Component implements OnInit, OnDestroy { filter.collection?.organizationId) as OrganizationId, collectionId: filter.collection?.id as CollectionId, folderId: filter.folder?.id, - uri: (await BrowserApi.getTabFromCurrentWindow())?.url, }) as NewItemInitialValues, ), shareReplay({ refCount: true, bufferSize: 1 }),