mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-11 10:10:25 +01:00
[PM-9926] Linked Fields order (#10174)
* refactor linkedFieldOption to take in an attributes object * add sort positions for existing linked fields * sort linked fields on new custom fields
This commit is contained in:
parent
88f585e09d
commit
decc7a3031
@ -1,11 +1,30 @@
|
||||
import { LinkedIdType } from "./enums";
|
||||
import { ItemView } from "./models/view/item.view";
|
||||
|
||||
type LinkedMetadataAttributes = {
|
||||
/**
|
||||
* The i18n key used to describe the decorated class property in the UI.
|
||||
* If it is null, then the name of the class property will be used as the i18n key.
|
||||
*/
|
||||
i18nKey?: string;
|
||||
|
||||
/**
|
||||
* The position of the individual field to be applied when sorted.
|
||||
*/
|
||||
sortPosition: number;
|
||||
};
|
||||
|
||||
export class LinkedMetadata {
|
||||
private readonly _i18nKey: string;
|
||||
readonly sortPosition: number;
|
||||
|
||||
constructor(
|
||||
readonly propertyKey: string,
|
||||
private readonly _i18nKey?: string,
|
||||
) {}
|
||||
attributes: LinkedMetadataAttributes,
|
||||
) {
|
||||
this._i18nKey = attributes?.i18nKey;
|
||||
this.sortPosition = attributes.sortPosition;
|
||||
}
|
||||
|
||||
get i18nKey() {
|
||||
return this._i18nKey ?? this.propertyKey;
|
||||
@ -16,15 +35,14 @@ export class LinkedMetadata {
|
||||
* A decorator used to set metadata used by Linked custom fields. Apply it to a class property or getter to make it
|
||||
* available as a Linked custom field option.
|
||||
* @param id - A unique value that is saved in the Field model. It is used to look up the decorated class property.
|
||||
* @param i18nKey - The i18n key used to describe the decorated class property in the UI. If it is null, then the name
|
||||
* of the class property will be used as the i18n key.
|
||||
* @param options - {@link LinkedMetadataAttributes}
|
||||
*/
|
||||
export function linkedFieldOption(id: LinkedIdType, i18nKey?: string) {
|
||||
export function linkedFieldOption(id: LinkedIdType, attributes: LinkedMetadataAttributes) {
|
||||
return (prototype: ItemView, propertyKey: string) => {
|
||||
if (prototype.linkedFieldOptions == null) {
|
||||
prototype.linkedFieldOptions = new Map<LinkedIdType, LinkedMetadata>();
|
||||
}
|
||||
|
||||
prototype.linkedFieldOptions.set(id, new LinkedMetadata(propertyKey, i18nKey));
|
||||
prototype.linkedFieldOptions.set(id, new LinkedMetadata(propertyKey, attributes));
|
||||
};
|
||||
}
|
||||
|
@ -6,13 +6,13 @@ import { linkedFieldOption } from "../../linked-field-option.decorator";
|
||||
import { ItemView } from "./item.view";
|
||||
|
||||
export class CardView extends ItemView {
|
||||
@linkedFieldOption(LinkedId.CardholderName)
|
||||
@linkedFieldOption(LinkedId.CardholderName, { sortPosition: 0 })
|
||||
cardholderName: string = null;
|
||||
@linkedFieldOption(LinkedId.ExpMonth, "expirationMonth")
|
||||
@linkedFieldOption(LinkedId.ExpMonth, { sortPosition: 3, i18nKey: "expirationMonth" })
|
||||
expMonth: string = null;
|
||||
@linkedFieldOption(LinkedId.ExpYear, "expirationYear")
|
||||
@linkedFieldOption(LinkedId.ExpYear, { sortPosition: 4, i18nKey: "expirationYear" })
|
||||
expYear: string = null;
|
||||
@linkedFieldOption(LinkedId.Code, "securityCode")
|
||||
@linkedFieldOption(LinkedId.Code, { sortPosition: 5, i18nKey: "securityCode" })
|
||||
code: string = null;
|
||||
|
||||
private _brand: string = null;
|
||||
@ -27,7 +27,7 @@ export class CardView extends ItemView {
|
||||
return this.number != null ? "•".repeat(this.number.length) : null;
|
||||
}
|
||||
|
||||
@linkedFieldOption(LinkedId.Brand)
|
||||
@linkedFieldOption(LinkedId.Brand, { sortPosition: 2 })
|
||||
get brand(): string {
|
||||
return this._brand;
|
||||
}
|
||||
@ -36,7 +36,7 @@ export class CardView extends ItemView {
|
||||
this._subTitle = null;
|
||||
}
|
||||
|
||||
@linkedFieldOption(LinkedId.Number)
|
||||
@linkedFieldOption(LinkedId.Number, { sortPosition: 1 })
|
||||
get number(): string {
|
||||
return this._number;
|
||||
}
|
||||
|
@ -7,37 +7,37 @@ import { linkedFieldOption } from "../../linked-field-option.decorator";
|
||||
import { ItemView } from "./item.view";
|
||||
|
||||
export class IdentityView extends ItemView {
|
||||
@linkedFieldOption(LinkedId.Title)
|
||||
@linkedFieldOption(LinkedId.Title, { sortPosition: 0 })
|
||||
title: string = null;
|
||||
@linkedFieldOption(LinkedId.MiddleName)
|
||||
@linkedFieldOption(LinkedId.MiddleName, { sortPosition: 2 })
|
||||
middleName: string = null;
|
||||
@linkedFieldOption(LinkedId.Address1)
|
||||
@linkedFieldOption(LinkedId.Address1, { sortPosition: 12 })
|
||||
address1: string = null;
|
||||
@linkedFieldOption(LinkedId.Address2)
|
||||
@linkedFieldOption(LinkedId.Address2, { sortPosition: 13 })
|
||||
address2: string = null;
|
||||
@linkedFieldOption(LinkedId.Address3)
|
||||
@linkedFieldOption(LinkedId.Address3, { sortPosition: 14 })
|
||||
address3: string = null;
|
||||
@linkedFieldOption(LinkedId.City, "cityTown")
|
||||
@linkedFieldOption(LinkedId.City, { sortPosition: 15, i18nKey: "cityTown" })
|
||||
city: string = null;
|
||||
@linkedFieldOption(LinkedId.State, "stateProvince")
|
||||
@linkedFieldOption(LinkedId.State, { sortPosition: 16, i18nKey: "stateProvince" })
|
||||
state: string = null;
|
||||
@linkedFieldOption(LinkedId.PostalCode, "zipPostalCode")
|
||||
@linkedFieldOption(LinkedId.PostalCode, { sortPosition: 17, i18nKey: "zipPostalCode" })
|
||||
postalCode: string = null;
|
||||
@linkedFieldOption(LinkedId.Country)
|
||||
@linkedFieldOption(LinkedId.Country, { sortPosition: 18 })
|
||||
country: string = null;
|
||||
@linkedFieldOption(LinkedId.Company)
|
||||
@linkedFieldOption(LinkedId.Company, { sortPosition: 6 })
|
||||
company: string = null;
|
||||
@linkedFieldOption(LinkedId.Email)
|
||||
@linkedFieldOption(LinkedId.Email, { sortPosition: 10 })
|
||||
email: string = null;
|
||||
@linkedFieldOption(LinkedId.Phone)
|
||||
@linkedFieldOption(LinkedId.Phone, { sortPosition: 11 })
|
||||
phone: string = null;
|
||||
@linkedFieldOption(LinkedId.Ssn)
|
||||
@linkedFieldOption(LinkedId.Ssn, { sortPosition: 7 })
|
||||
ssn: string = null;
|
||||
@linkedFieldOption(LinkedId.Username)
|
||||
@linkedFieldOption(LinkedId.Username, { sortPosition: 5 })
|
||||
username: string = null;
|
||||
@linkedFieldOption(LinkedId.PassportNumber)
|
||||
@linkedFieldOption(LinkedId.PassportNumber, { sortPosition: 8 })
|
||||
passportNumber: string = null;
|
||||
@linkedFieldOption(LinkedId.LicenseNumber)
|
||||
@linkedFieldOption(LinkedId.LicenseNumber, { sortPosition: 9 })
|
||||
licenseNumber: string = null;
|
||||
|
||||
private _firstName: string = null;
|
||||
@ -48,7 +48,7 @@ export class IdentityView extends ItemView {
|
||||
super();
|
||||
}
|
||||
|
||||
@linkedFieldOption(LinkedId.FirstName)
|
||||
@linkedFieldOption(LinkedId.FirstName, { sortPosition: 1 })
|
||||
get firstName(): string {
|
||||
return this._firstName;
|
||||
}
|
||||
@ -57,7 +57,7 @@ export class IdentityView extends ItemView {
|
||||
this._subTitle = null;
|
||||
}
|
||||
|
||||
@linkedFieldOption(LinkedId.LastName)
|
||||
@linkedFieldOption(LinkedId.LastName, { sortPosition: 4 })
|
||||
get lastName(): string {
|
||||
return this._lastName;
|
||||
}
|
||||
@ -83,7 +83,7 @@ export class IdentityView extends ItemView {
|
||||
return this._subTitle;
|
||||
}
|
||||
|
||||
@linkedFieldOption(LinkedId.FullName)
|
||||
@linkedFieldOption(LinkedId.FullName, { sortPosition: 3 })
|
||||
get fullName(): string {
|
||||
if (
|
||||
this.title != null ||
|
||||
|
@ -10,9 +10,9 @@ import { ItemView } from "./item.view";
|
||||
import { LoginUriView } from "./login-uri.view";
|
||||
|
||||
export class LoginView extends ItemView {
|
||||
@linkedFieldOption(LinkedId.Username)
|
||||
@linkedFieldOption(LinkedId.Username, { sortPosition: 0 })
|
||||
username: string = null;
|
||||
@linkedFieldOption(LinkedId.Password)
|
||||
@linkedFieldOption(LinkedId.Password, { sortPosition: 1 })
|
||||
password: string = null;
|
||||
|
||||
passwordRevisionDate?: Date = null;
|
||||
|
@ -20,7 +20,6 @@ import { Subject, zip } 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 { 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";
|
||||
@ -135,13 +134,14 @@ export class CustomFieldsComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngOnInit() {
|
||||
const linkedFieldsOptionsForCipher = this.getLinkedFieldsOptionsForCipher();
|
||||
const optionsArray = Array.from(linkedFieldsOptionsForCipher?.entries() ?? []);
|
||||
optionsArray.sort((a, b) => a[1].sortPosition - b[1].sortPosition);
|
||||
|
||||
// Populate options for linked custom fields
|
||||
this.linkedFieldOptions = Array.from(linkedFieldsOptionsForCipher?.entries() ?? [])
|
||||
.map(([id, linkedFieldOption]) => ({
|
||||
this.linkedFieldOptions = optionsArray.map(([id, linkedFieldOption]) => ({
|
||||
name: this.i18nService.t(linkedFieldOption.i18nKey),
|
||||
value: id,
|
||||
}))
|
||||
.sort(Utils.getSortFunction(this.i18nService, "name"));
|
||||
}));
|
||||
|
||||
// Populate the form with the existing fields
|
||||
this.cipherFormContainer.originalCipherView?.fields?.forEach((field) => {
|
||||
|
Loading…
Reference in New Issue
Block a user