From a61d7fd4daff99b9e6f5d25a92ad61c7ef94cf08 Mon Sep 17 00:00:00 2001 From: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> Date: Fri, 11 Jul 2025 09:31:37 -0500 Subject: [PATCH] [PM-23672] Switching Custom Fields - Desktop (#15563) --- .../custom-fields-v2.component.spec.ts | 64 +++++++++++++++++++ .../custom-fields-v2.component.ts | 13 ++-- 2 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.spec.ts diff --git a/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.spec.ts b/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.spec.ts new file mode 100644 index 00000000000..510a5a86179 --- /dev/null +++ b/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.spec.ts @@ -0,0 +1,64 @@ +import { SimpleChanges } from "@angular/core"; +import { ComponentFixture, TestBed } from "@angular/core/testing"; +import { mock } from "jest-mock-extended"; + +import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { CipherType } from "@bitwarden/common/vault/enums"; +import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { IdentityView } from "@bitwarden/common/vault/models/view/identity.view"; +import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; + +import { CustomFieldV2Component } from "./custom-fields-v2.component"; + +describe("CustomFieldV2Component", () => { + let component: CustomFieldV2Component; + let fixture: ComponentFixture; + + const currentCipher = new CipherView(); + currentCipher.type = CipherType.Login; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [], + providers: [ + { provide: I18nService, useValue: { t: (key: string) => key } }, + { provide: EventCollectionService, useValue: mock() }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(CustomFieldV2Component); + component = fixture.componentInstance; + component.cipher = currentCipher; + fixture.detectChanges(); + }); + + it("updates fieldOptions on cipher change", () => { + component.ngOnChanges({ + cipher: { + currentValue: currentCipher, + previousValue: null, + firstChange: true, + isFirstChange: () => true, + }, + } as SimpleChanges); + + expect(component.fieldOptions).toEqual(LoginView.prototype.linkedFieldOptions); + + const newCipher = new CipherView(); + newCipher.type = CipherType.Identity; + + component.cipher = newCipher; + component.ngOnChanges({ + cipher: { + currentValue: newCipher, + previousValue: currentCipher, + firstChange: false, + isFirstChange: () => false, + }, + } as SimpleChanges); + fixture.detectChanges(); + + expect(component.fieldOptions).toEqual(IdentityView.prototype.linkedFieldOptions); + }); +}); diff --git a/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.ts b/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.ts index 9a6f93026e5..2fc35574ba5 100644 --- a/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.ts +++ b/libs/vault/src/cipher-view/custom-fields/custom-fields-v2.component.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { CommonModule } from "@angular/common"; import { Component, Input, OnChanges, OnInit, SimpleChanges } from "@angular/core"; @@ -8,6 +6,7 @@ import { EventCollectionService } from "@bitwarden/common/abstractions/event/eve import { EventType } from "@bitwarden/common/enums"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { CipherType, FieldType, LinkedIdType } from "@bitwarden/common/vault/enums"; +import { LinkedMetadata } from "@bitwarden/common/vault/linked-field-option.decorator"; import { CardView } from "@bitwarden/common/vault/models/view/card.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { IdentityView } from "@bitwarden/common/vault/models/view/identity.view"; @@ -43,9 +42,9 @@ import { VaultAutosizeReadOnlyTextArea } from "../../directives/readonly-textare ], }) export class CustomFieldV2Component implements OnInit, OnChanges { - @Input() cipher: CipherView; + @Input({ required: true }) cipher!: CipherView; fieldType = FieldType; - fieldOptions: any; + fieldOptions: Map | null = null; /** Indexes of hidden fields that are revealed */ revealedHiddenFields: number[] = []; @@ -67,12 +66,14 @@ export class CustomFieldV2Component implements OnInit, OnChanges { ngOnChanges(changes: SimpleChanges): void { if (changes["cipher"]) { this.revealedHiddenFields = []; + this.fieldOptions = this.getLinkedFieldsOptionsForCipher(); } } getLinkedType(linkedId: LinkedIdType) { - const linkedType = this.fieldOptions.get(linkedId); - return this.i18nService.t(linkedType.i18nKey); + const linkedType = this.fieldOptions?.get(linkedId); + + return linkedType ? this.i18nService.t(linkedType.i18nKey) : null; } get canViewPassword() {