use linked types from the cipher prototype (#10167)

- When adding a new cipher the cipher view isn't defined yet
This commit is contained in:
Nick Krantz 2024-07-22 09:12:36 -05:00 committed by GitHub
parent 457c0795be
commit 019c5d6677
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 79 additions and 25 deletions

View File

@ -6,13 +6,19 @@ import { ComponentFixture, TestBed } from "@angular/core/testing";
import { By } from "@angular/platform-browser";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { CipherType, FieldType, LoginLinkedId } from "@bitwarden/common/vault/enums";
import {
CardLinkedId,
CipherType,
FieldType,
IdentityLinkedId,
LoginLinkedId,
} from "@bitwarden/common/vault/enums";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { FieldView } from "@bitwarden/common/vault/models/view/field.view";
import { LoginView } from "@bitwarden/common/vault/models/view/login.view";
import { DialogService } from "@bitwarden/components";
import { BitPasswordInputToggleDirective } from "../../../../../components/src/form-field/password-input-toggle.directive";
import { CipherFormConfig } from "../../abstractions/cipher-form-config.service";
import { CipherFormContainer } from "../../cipher-form-container";
import { CustomField, CustomFieldsComponent } from "./custom-fields.component";
@ -25,8 +31,6 @@ const mockFieldViews = [
] as FieldView[];
let originalCipherView: CipherView | null = new CipherView();
originalCipherView.type = CipherType.Login;
originalCipherView.login = new LoginView();
describe("CustomFieldsComponent", () => {
let component: CustomFieldsComponent;
@ -34,14 +38,14 @@ describe("CustomFieldsComponent", () => {
let open: jest.Mock;
let announce: jest.Mock;
let patchCipher: jest.Mock;
let config: CipherFormConfig;
beforeEach(async () => {
open = jest.fn();
announce = jest.fn().mockResolvedValue(null);
patchCipher = jest.fn();
originalCipherView = new CipherView();
originalCipherView.type = CipherType.Login;
originalCipherView.login = new LoginView();
config = {} as CipherFormConfig;
await TestBed.configureTestingModule({
imports: [CustomFieldsComponent],
@ -52,7 +56,7 @@ describe("CustomFieldsComponent", () => {
},
{
provide: CipherFormContainer,
useValue: { patchCipher, originalCipherView, registerChildForm: jest.fn(), config: {} },
useValue: { patchCipher, originalCipherView, registerChildForm: jest.fn(), config },
},
{
provide: LiveAnnouncer,
@ -73,20 +77,6 @@ describe("CustomFieldsComponent", () => {
});
describe("initializing", () => {
it("populates linkedFieldOptions", () => {
originalCipherView.login.linkedFieldOptions = new Map([
[1, { i18nKey: "one-i18", propertyKey: "one" }],
[2, { i18nKey: "two-i18", propertyKey: "two" }],
]);
component.ngOnInit();
expect(component.linkedFieldOptions).toEqual([
{ value: 1, name: "one-i18" },
{ value: 2, name: "two-i18" },
]);
});
it("populates customFieldsForm", () => {
originalCipherView.fields = mockFieldViews;
@ -130,6 +120,50 @@ describe("CustomFieldsComponent", () => {
expect(button.nativeElement.disabled).toBe(true);
});
describe("linkedFieldOptions", () => {
/** Retrieve the numerical values of an enum object */
const getEnumValues = (enumType: object) =>
Object.values(enumType).filter((v) => typeof v === "number");
it("populates for login ciphers", () => {
config.cipherType = CipherType.Login;
component.ngOnInit();
expect(component.linkedFieldOptions.map((o) => o.value)).toEqual(
expect.arrayContaining(getEnumValues(LoginLinkedId)),
);
});
it("populates for card ciphers", () => {
config.cipherType = CipherType.Card;
component.ngOnInit();
expect(component.linkedFieldOptions.map((o) => o.value)).toEqual(
expect.arrayContaining(getEnumValues(CardLinkedId)),
);
});
it("populates for identity ciphers", () => {
config.cipherType = CipherType.Identity;
component.ngOnInit();
expect(component.linkedFieldOptions.map((o) => o.value)).toEqual(
expect.arrayContaining(getEnumValues(IdentityLinkedId)),
);
});
it("sets an empty array for note ciphers", () => {
config.cipherType = CipherType.SecureNote;
component.ngOnInit();
expect(component.linkedFieldOptions).toEqual([]);
});
});
});
describe("adding new field", () => {

View File

@ -21,8 +21,11 @@ import { Subject, switchMap, take } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { FieldType, LinkedIdType } from "@bitwarden/common/vault/enums";
import { CipherType, FieldType, LinkedIdType } from "@bitwarden/common/vault/enums";
import { CardView } from "@bitwarden/common/vault/models/view/card.view";
import { FieldView } from "@bitwarden/common/vault/models/view/field.view";
import { IdentityView } from "@bitwarden/common/vault/models/view/identity.view";
import { LoginView } from "@bitwarden/common/vault/models/view/login.view";
import {
DialogService,
SectionComponent,
@ -131,10 +134,9 @@ export class CustomFieldsComponent implements OnInit, AfterViewInit {
}
ngOnInit() {
const linkedFieldsOptionsForCipher = this.getLinkedFieldsOptionsForCipher();
// Populate options for linked custom fields
this.linkedFieldOptions = Array.from(
this.cipherFormContainer.originalCipherView?.linkedFieldOptions?.entries() ?? [],
)
this.linkedFieldOptions = Array.from(linkedFieldsOptionsForCipher?.entries() ?? [])
.map(([id, linkedFieldOption]) => ({
name: this.i18nService.t(linkedFieldOption.i18nKey),
value: id,
@ -303,6 +305,24 @@ export class CustomFieldsComponent implements OnInit, AfterViewInit {
}
}
/**
* Returns the linked field options for the current cipher type
*
* Note: Note ciphers do not have linked fields
*/
private getLinkedFieldsOptionsForCipher() {
switch (this.cipherFormContainer.config.cipherType) {
case CipherType.Login:
return LoginView.prototype.linkedFieldOptions;
case CipherType.Card:
return CardView.prototype.linkedFieldOptions;
case CipherType.Identity:
return IdentityView.prototype.linkedFieldOptions;
default:
return null;
}
}
/** Create `FieldView` from the form objects and update the cipher */
private updateCipher(fields: CustomField[]) {
const newFields = fields.map((field: CustomField) => {