1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 15:53:27 +00:00

[PM-25682] Migrate CipherView and subviews to be TS strict compliant (#16463)

* [PM-25682] Remove ts-strict-ignore from Vault view models and update types to be strict

* [PM-25682] Ignore ViewEncryptableKeys error for old decrypt methods

* [PM-25682] Add null/undefined as possible types for isNull* and other helpers that include null checks internally

* [PM-25682] Use patchValue instead of setValue which does not support undefined values

* [PM-25682] Add type assertions and other misc. null checks where necessary

* [PM-25682] Fix importers specs

* [PM-25682] Cleanup card view/details

* [PM-25682] Fix cipher view hasAttachment helper

* [PM-25682] Cleanup unecessary null assignments in notification.background.spec.ts

* [PM-25682] Ensure linkedId is undefined instead of null

* [PM-25682] Cleanup misc typing errors

* [PM-25682] Make the CipherId required

* [PM-25682] Undo CipherId assertions

* [PM-25682] Undo brand initial value change

* [PM-25682] Update SshKeyView

* [PM-25682] Add constructor to Fido2CredentialView

* [PM-25682] Prettier

* [PM-25682] Fix strict type warnings after merge with main

* [PM-25682] Cleanup cipher view spec

* [PM-25682] Cleanup new type warnings after merge

* [PM-25682] Undo removed eslint-disable-next-line comment

* [PM-25682] Fix flaky test

* [PM-25682] Use satisfies instead of as for Fido2CredentialAutofillView
This commit is contained in:
Shane Melton
2025-10-07 08:40:57 -07:00
committed by GitHub
parent 2127f71f5d
commit 9f0a565241
54 changed files with 424 additions and 503 deletions

View File

@@ -86,7 +86,10 @@ describe("AdditionalOptionsSectionComponent", () => {
expect(cipherFormProvider.patchCipher).toHaveBeenCalled();
const patchFn = cipherFormProvider.patchCipher.mock.lastCall[0];
const updated = patchFn(new CipherView());
const newCipher = new CipherView();
newCipher.creationDate = newCipher.revisionDate = expectedCipher.creationDate;
const updated = patchFn(newCipher);
expect(updated).toEqual(expectedCipher);
});

View File

@@ -66,7 +66,7 @@ export class DeleteAttachmentComponent {
await this.cipherService.deleteAttachmentWithServer(
this.cipherId,
this.attachment.id,
this.attachment.id!,
activeUserId,
this.admin,
);

View File

@@ -67,6 +67,7 @@ describe("CardDetailsSectionComponent", () => {
cardView.brand = "Visa";
cardView.expMonth = "";
cardView.code = "";
cardView.expYear = "";
expect(patchCipherSpy).toHaveBeenCalled();
const patchFn = patchCipherSpy.mock.lastCall[0];
@@ -85,6 +86,7 @@ describe("CardDetailsSectionComponent", () => {
cardView.number = "";
cardView.expMonth = "";
cardView.code = "";
cardView.brand = "";
cardView.expYear = "2022";
expect(patchCipherSpy).toHaveBeenCalled();
@@ -122,8 +124,6 @@ describe("CardDetailsSectionComponent", () => {
number,
code,
brand: cardView.brand,
expMonth: null,
expYear: null,
});
});

View File

@@ -52,12 +52,12 @@ export class CardDetailsSectionComponent implements OnInit {
* leaving as just null gets inferred as `unknown`
*/
cardDetailsForm = this.formBuilder.group({
cardholderName: null as string | null,
number: null as string | null,
brand: null as string | null,
expMonth: null as string | null,
expYear: null as string | number | null,
code: null as string | null,
cardholderName: "",
number: "",
brand: "",
expMonth: "",
expYear: "" as string | number,
code: "",
});
/** Available Card Brands */
@@ -110,16 +110,14 @@ export class CardDetailsSectionComponent implements OnInit {
.pipe(takeUntilDestroyed())
.subscribe(({ cardholderName, number, brand, expMonth, expYear, code }) => {
this.cipherFormContainer.patchCipher((cipher) => {
const expirationYear = normalizeExpiryYearFormat(expYear);
const expirationYear = normalizeExpiryYearFormat(expYear) ?? "";
Object.assign(cipher.card, {
cardholderName,
number,
brand,
expMonth,
expYear: expirationYear,
code,
});
cipher.card.cardholderName = cardholderName;
cipher.card.number = number;
cipher.card.brand = brand;
cipher.card.expMonth = expMonth;
cipher.card.expYear = expirationYear;
cipher.card.code = code;
return cipher;
});
@@ -167,6 +165,7 @@ export class CardDetailsSectionComponent implements OnInit {
expMonth: this.initialValues?.expMonth || "",
expYear: this.initialValues?.expYear || "",
code: this.initialValues?.code || "",
brand: CardView.getCardBrandByPatterns(this.initialValues?.number) || "",
});
}
@@ -195,18 +194,4 @@ export class CardDetailsSectionComponent implements OnInit {
);
}
}
/** Set form initial form values from the current cipher */
private setInitialValues(cipherView: CipherView) {
const { cardholderName, number, brand, expMonth, expYear, code } = cipherView.card;
this.cardDetailsForm.setValue({
cardholderName: cardholderName,
number: number,
brand: brand,
expMonth: expMonth,
expYear: expYear,
code: code,
});
}
}

View File

@@ -386,7 +386,7 @@ export class CustomFieldsComponent implements OnInit, AfterViewInit {
fieldView.type = field.type;
fieldView.name = field.name;
fieldView.value = value;
fieldView.linkedId = field.linkedId;
fieldView.linkedId = field.linkedId ?? undefined;
return fieldView;
});

View File

@@ -172,7 +172,7 @@ export class IdentitySectionComponent implements OnInit {
populateFormData(cipherView: CipherView) {
const { identity } = cipherView;
this.identityForm.setValue({
this.identityForm.patchValue({
title: identity.title,
firstName: identity.firstName,
middleName: identity.middleName,

View File

@@ -312,7 +312,7 @@ export class ItemDetailsSectionComponent implements OnInit {
private async initFromExistingCipher(prefillCipher: CipherView) {
const { name, folderId, collectionIds } = prefillCipher;
this.itemDetailsForm.setValue({
this.itemDetailsForm.patchValue({
name: name ? name : (this.initialValues?.name ?? ""),
organizationId: prefillCipher.organizationId, // We do not allow changing ownership of an existing cipher.
folderId: folderId ? folderId : (this.initialValues?.folderId ?? null),

View File

@@ -36,7 +36,7 @@ export class DefaultCipherFormService implements CipherFormService {
let savedCipher: Cipher;
// Creating a new cipher
if (cipher.id == null) {
if (cipher.id == null || cipher.id === "") {
const encrypted = await this.cipherService.encrypt(cipher, activeUserId);
savedCipher = await this.cipherService.createWithServer(encrypted, config.admin);
return await this.cipherService.decrypt(savedCipher, activeUserId);

View File

@@ -44,7 +44,7 @@ import { VaultAutosizeReadOnlyTextArea } from "../../directives/readonly-textare
export class CustomFieldV2Component implements OnInit, OnChanges {
@Input({ required: true }) cipher!: CipherView;
fieldType = FieldType;
fieldOptions: Map<number, LinkedMetadata> | null = null;
fieldOptions: Map<number, LinkedMetadata> | undefined;
/** Indexes of hidden fields that are revealed */
revealedHiddenFields: number[] = [];
@@ -124,7 +124,7 @@ export class CustomFieldV2Component implements OnInit, OnChanges {
case CipherType.Identity:
return IdentityView.prototype.linkedFieldOptions;
default:
return null;
return undefined;
}
}
}