1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-12 10:14:10 +01:00

[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
This commit is contained in:
Nick Krantz 2024-09-23 08:55:23 -05:00 committed by GitHub
parent 69bf91a15e
commit 17c9b26336
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 64 additions and 18 deletions

View File

@ -7,6 +7,8 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherType } from "@bitwarden/common/vault/enums";
import { ButtonModule, DialogService, MenuModule } from "@bitwarden/components"; 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 { AddEditQueryParams } from "../add-edit/add-edit-v2.component";
import { AddEditFolderDialogComponent } from "../add-edit-folder-dialog/add-edit-folder-dialog.component"; import { AddEditFolderDialogComponent } from "../add-edit-folder-dialog/add-edit-folder-dialog.component";
@ -18,6 +20,10 @@ describe("NewItemDropdownV2Component", () => {
const open = jest.fn(); const open = jest.fn();
const navigate = jest.fn(); const navigate = jest.fn();
jest
.spyOn(BrowserApi, "getTabFromCurrentWindow")
.mockResolvedValue({ url: "https://example.com" } as chrome.tabs.Tab);
beforeEach(async () => { beforeEach(async () => {
open.mockClear(); open.mockClear();
navigate.mockClear(); navigate.mockClear();
@ -54,46 +60,74 @@ describe("NewItemDropdownV2Component", () => {
jest.spyOn(component, "newItemNavigate"); jest.spyOn(component, "newItemNavigate");
}); });
it("navigates to new login", () => { it("navigates to new login", async () => {
component.newItemNavigate(CipherType.Login); await component.newItemNavigate(CipherType.Login);
expect(navigate).toHaveBeenCalledWith(["/add-cipher"], { 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", () => { it("navigates to new card", async () => {
component.newItemNavigate(CipherType.Card); await component.newItemNavigate(CipherType.Card);
expect(navigate).toHaveBeenCalledWith(["/add-cipher"], { expect(navigate).toHaveBeenCalledWith(["/add-cipher"], {
queryParams: { type: CipherType.Card.toString(), ...emptyParams }, queryParams: { type: CipherType.Card.toString(), ...emptyParams },
}); });
}); });
it("navigates to new identity", () => { it("navigates to new identity", async () => {
component.newItemNavigate(CipherType.Identity); await component.newItemNavigate(CipherType.Identity);
expect(navigate).toHaveBeenCalledWith(["/add-cipher"], { expect(navigate).toHaveBeenCalledWith(["/add-cipher"], {
queryParams: { type: CipherType.Identity.toString(), ...emptyParams }, queryParams: { type: CipherType.Identity.toString(), ...emptyParams },
}); });
}); });
it("navigates to new note", () => { it("navigates to new note", async () => {
component.newItemNavigate(CipherType.SecureNote); await component.newItemNavigate(CipherType.SecureNote);
expect(navigate).toHaveBeenCalledWith(["/add-cipher"], { expect(navigate).toHaveBeenCalledWith(["/add-cipher"], {
queryParams: { type: CipherType.SecureNote.toString(), ...emptyParams }, queryParams: { type: CipherType.SecureNote.toString(), ...emptyParams },
}); });
}); });
it("includes initial values", () => { it("includes initial values", async () => {
component.initialValues = { component.initialValues = {
folderId: "222-333-444", folderId: "222-333-444",
organizationId: "444-555-666", organizationId: "444-555-666",
collectionId: "777-888-999", collectionId: "777-888-999",
} as NewItemInitialValues; } 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"], { expect(navigate).toHaveBeenCalledWith(["/add-cipher"], {
queryParams: { queryParams: {

View File

@ -3,10 +3,13 @@ import { Component, Input } from "@angular/core";
import { Router, RouterLink } from "@angular/router"; import { Router, RouterLink } from "@angular/router";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid"; import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid";
import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherType } from "@bitwarden/common/vault/enums";
import { ButtonModule, DialogService, MenuModule, NoItemsModule } from "@bitwarden/components"; 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 { AddEditQueryParams } from "../add-edit/add-edit-v2.component";
import { AddEditFolderDialogComponent } from "../add-edit-folder-dialog/add-edit-folder-dialog.component"; import { AddEditFolderDialogComponent } from "../add-edit-folder-dialog/add-edit-folder-dialog.component";
@ -14,7 +17,6 @@ export interface NewItemInitialValues {
folderId?: string; folderId?: string;
organizationId?: OrganizationId; organizationId?: OrganizationId;
collectionId?: CollectionId; collectionId?: CollectionId;
uri?: string;
} }
@Component({ @Component({
@ -37,18 +39,30 @@ export class NewItemDropdownV2Component {
private dialogService: DialogService, private dialogService: DialogService,
) {} ) {}
private buildQueryParams(type: CipherType): AddEditQueryParams { private async buildQueryParams(type: CipherType): Promise<AddEditQueryParams> {
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 { return {
type: type.toString(), type: type.toString(),
collectionId: this.initialValues?.collectionId, collectionId: this.initialValues?.collectionId,
organizationId: this.initialValues?.organizationId, organizationId: this.initialValues?.organizationId,
folderId: this.initialValues?.folderId, folderId: this.initialValues?.folderId,
uri: this.initialValues?.uri, ...loginDetails,
}; };
} }
newItemNavigate(type: CipherType) { async newItemNavigate(type: CipherType) {
void this.router.navigate(["/add-cipher"], { queryParams: this.buildQueryParams(type) }); await this.router.navigate(["/add-cipher"], { queryParams: await this.buildQueryParams(type) });
} }
openFolderDialog() { openFolderDialog() {

View File

@ -12,7 +12,6 @@ import { ButtonModule, Icons, NoItemsModule } from "@bitwarden/components";
import { VaultIcons } from "@bitwarden/vault"; import { VaultIcons } from "@bitwarden/vault";
import { CurrentAccountComponent } from "../../../../auth/popup/account-switching/current-account.component"; 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 { PopOutComponent } from "../../../../platform/popup/components/pop-out.component";
import { PopupHeaderComponent } from "../../../../platform/popup/layout/popup-header.component"; import { PopupHeaderComponent } from "../../../../platform/popup/layout/popup-header.component";
import { PopupPageComponent } from "../../../../platform/popup/layout/popup-page.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, filter.collection?.organizationId) as OrganizationId,
collectionId: filter.collection?.id as CollectionId, collectionId: filter.collection?.id as CollectionId,
folderId: filter.folder?.id, folderId: filter.folder?.id,
uri: (await BrowserApi.getTabFromCurrentWindow())?.url,
}) as NewItemInitialValues, }) as NewItemInitialValues,
), ),
shareReplay({ refCount: true, bufferSize: 1 }), shareReplay({ refCount: true, bufferSize: 1 }),