From cc06e1eff3dd615f2bac27b57e20332e051ca0e5 Mon Sep 17 00:00:00 2001 From: Daniel Riera Date: Fri, 20 Dec 2024 11:33:43 -0500 Subject: [PATCH] enhancement: UI for multiple totp elements (#12404) * enhancement: UI for multiple totp elements * add tests * update snapshots * update obsolete snapshots * Update apps/browser/src/autofill/overlay/inline-menu/pages/list/autofill-inline-menu-list.ts Co-authored-by: Jonathan Prusik --------- Co-authored-by: Jonathan Prusik --- .../autofill-inline-menu-list.spec.ts.snap | 248 ++++++++++++++++++ .../list/autofill-inline-menu-list.spec.ts | 41 +++ .../pages/list/autofill-inline-menu-list.ts | 32 ++- 3 files changed, 313 insertions(+), 8 deletions(-) diff --git a/apps/browser/src/autofill/overlay/inline-menu/pages/list/__snapshots__/autofill-inline-menu-list.spec.ts.snap b/apps/browser/src/autofill/overlay/inline-menu/pages/list/__snapshots__/autofill-inline-menu-list.spec.ts.snap index 785cadb5510..3b8458ec2ab 100644 --- a/apps/browser/src/autofill/overlay/inline-menu/pages/list/__snapshots__/autofill-inline-menu-list.spec.ts.snap +++ b/apps/browser/src/autofill/overlay/inline-menu/pages/list/__snapshots__/autofill-inline-menu-list.spec.ts.snap @@ -2813,6 +2813,254 @@ exports[`AutofillInlineMenuList initAutofillInlineMenuList the list of ciphers f `; +exports[`AutofillInlineMenuList initAutofillInlineMenuList the list of ciphers for an authenticated user renders correctly when there are multiple TOTP elements with username displayed 1`] = ` +
+
    +
  • +
    + + +
    +
  • +
  • +
    + + +
    +
  • +
+
+`; + exports[`AutofillInlineMenuList initAutofillInlineMenuList the locked inline menu for an unauthenticated user creates the views for the locked inline menu 1`] = `
{ expect(autofillInlineMenuList["inlineMenuListContainer"]).toMatchSnapshot(); }); + it("renders correctly when there are multiple TOTP elements with username displayed", async () => { + const totpCipher1 = createAutofillOverlayCipherDataMock(1, { + type: CipherType.Login, + login: { + totp: "123456", + totpField: true, + username: "user1", + }, + }); + + const totpCipher2 = createAutofillOverlayCipherDataMock(2, { + type: CipherType.Login, + login: { + totp: "654321", + totpField: true, + username: "user2", + }, + }); + + postWindowMessage( + createInitAutofillInlineMenuListMessageMock({ + inlineMenuFillType: CipherType.Login, + ciphers: [totpCipher1, totpCipher2], + }), + ); + + await flushPromises(); + const checkSubtitleElement = (username: string) => { + const subtitleElement = autofillInlineMenuList["inlineMenuListContainer"].querySelector( + `span.cipher-subtitle[title="${username}"]`, + ); + expect(subtitleElement).not.toBeNull(); + expect(subtitleElement.textContent).toBe(username); + }; + + checkSubtitleElement("user1"); + checkSubtitleElement("user2"); + + expect(autofillInlineMenuList["inlineMenuListContainer"]).toMatchSnapshot(); + }); + it("creates the view for a totp field", () => { postWindowMessage( createInitAutofillInlineMenuListMessageMock({ diff --git a/apps/browser/src/autofill/overlay/inline-menu/pages/list/autofill-inline-menu-list.ts b/apps/browser/src/autofill/overlay/inline-menu/pages/list/autofill-inline-menu-list.ts index 6cf390d0a29..b7837505d41 100644 --- a/apps/browser/src/autofill/overlay/inline-menu/pages/list/autofill-inline-menu-list.ts +++ b/apps/browser/src/autofill/overlay/inline-menu/pages/list/autofill-inline-menu-list.ts @@ -1163,7 +1163,7 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement { } if (cipher.login?.totpField && cipher.login?.totp) { - return this.buildTotpElement(cipher.login?.totp); + return this.buildTotpElement(cipher.login?.totp, cipher.login?.username); } const subTitleText = this.getSubTitleText(cipher); const cipherSubtitleElement = this.buildCipherSubtitleElement(subTitleText); @@ -1174,13 +1174,24 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement { return cipherDetailsElement; } + /** + * Checks if there is more than one TOTP element being displayed. + * + * @returns {boolean} - Returns true if more than one TOTP element is displayed, otherwise false. + */ + private multipleTotpElements(): boolean { + return ( + this.ciphers.filter((cipher) => cipher.login?.totpField && cipher.login?.totp).length > 1 + ); + } + /** * Builds a TOTP element for a given TOTP code. * * @param totp - The TOTP code to display. */ - private buildTotpElement(totpCode: string): HTMLDivElement | null { + private buildTotpElement(totpCode: string, username?: string): HTMLDivElement | null { if (!totpCode) { return null; } @@ -1196,12 +1207,17 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement { containerElement.appendChild(totpHeading); - const subtitleElement = document.createElement("span"); - subtitleElement.classList.add("cipher-subtitle"); - subtitleElement.textContent = formattedTotpCode; - subtitleElement.setAttribute("aria-label", this.getTranslation("totpCodeAria")); - subtitleElement.setAttribute("data-testid", "totp-code"); - containerElement.appendChild(subtitleElement); + if (this.multipleTotpElements() && username) { + const usernameSubtitle = this.buildCipherSubtitleElement(username); + containerElement.appendChild(usernameSubtitle); + } + + const totpCodeSpan = document.createElement("span"); + totpCodeSpan.classList.add("cipher-subtitle"); + totpCodeSpan.textContent = formattedTotpCode; + totpCodeSpan.setAttribute("aria-label", this.getTranslation("totpCodeAria")); + totpCodeSpan.setAttribute("data-testid", "totp-code"); + containerElement.appendChild(totpCodeSpan); return containerElement; }