-
Contrast
+
+
+
+
+
+ Add item
+
+
+ Next
+
+
+ Download complete
+
+
+ `,
+ }),
+ args: {
+ linkType: "primary",
+ },
+};
+
+export const Inactive: Story = {
+ render: (args) => ({
+ props: {
+ ...args,
+ onClick: () => {
+ alert("Button clicked! (This should not appear when disabled)");
+ },
+ },
+ template: /*html*/ `
+
Primary button
+
Links can not be inactive
+
Secondary button
+
+ Contrast button
`,
}),
diff --git a/libs/vault/src/cipher-form/abstractions/cipher-form-config.service.ts b/libs/vault/src/cipher-form/abstractions/cipher-form-config.service.ts
index 35d3d8725ff..a4aabbb6f19 100644
--- a/libs/vault/src/cipher-form/abstractions/cipher-form-config.service.ts
+++ b/libs/vault/src/cipher-form/abstractions/cipher-form-config.service.ts
@@ -28,6 +28,7 @@ export type OptionalInitialValues = {
// Credit Card Information
cardholderName?: string;
number?: string;
+ brand?: string;
expMonth?: string;
expYear?: string;
code?: string;
diff --git a/libs/vault/src/cipher-form/components/autofill-options/advanced-uri-option-dialog.component.ts b/libs/vault/src/cipher-form/components/autofill-options/advanced-uri-option-dialog.component.ts
index 3580b1fada8..04545730172 100644
--- a/libs/vault/src/cipher-form/components/autofill-options/advanced-uri-option-dialog.component.ts
+++ b/libs/vault/src/cipher-form/components/autofill-options/advanced-uri-option-dialog.component.ts
@@ -3,13 +3,13 @@ import { Component, inject } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import {
- ButtonLinkDirective,
ButtonModule,
+ CenterPositionStrategy,
DialogModule,
+ DialogRef,
DialogService,
DIALOG_DATA,
- DialogRef,
- CenterPositionStrategy,
+ LinkComponent,
} from "@bitwarden/components";
export type AdvancedUriOptionDialogParams = {
@@ -22,7 +22,7 @@ export type AdvancedUriOptionDialogParams = {
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
templateUrl: "advanced-uri-option-dialog.component.html",
- imports: [ButtonLinkDirective, ButtonModule, DialogModule, JslibModule],
+ imports: [LinkComponent, ButtonModule, DialogModule, JslibModule],
})
export class AdvancedUriOptionDialogComponent {
constructor(private dialogRef: DialogRef
) {}
diff --git a/libs/vault/src/cipher-form/components/card-details-section/card-details-section.component.spec.ts b/libs/vault/src/cipher-form/components/card-details-section/card-details-section.component.spec.ts
index 4b0cd0f5f90..650b4e29fe5 100644
--- a/libs/vault/src/cipher-form/components/card-details-section/card-details-section.component.spec.ts
+++ b/libs/vault/src/cipher-form/components/card-details-section/card-details-section.component.spec.ts
@@ -108,12 +108,17 @@ describe("CardDetailsSectionComponent", () => {
const cardholderName = "Ron Burgundy";
const number = "4242 4242 4242 4242";
const code = "619";
+ const brand = "Maestro";
+ const expMonth = "5";
+ const expYear = "2028";
const cardView = new CardView();
cardView.cardholderName = cardholderName;
cardView.number = number;
cardView.code = code;
- cardView.brand = "Visa";
+ cardView.brand = brand;
+ cardView.expMonth = expMonth;
+ cardView.expYear = expYear;
getInitialCipherView.mockReturnValueOnce({ card: cardView });
@@ -123,7 +128,9 @@ describe("CardDetailsSectionComponent", () => {
cardholderName,
number,
code,
- brand: cardView.brand,
+ brand,
+ expMonth,
+ expYear,
});
});
@@ -154,4 +161,27 @@ describe("CardDetailsSectionComponent", () => {
expect(heading.nativeElement.textContent.trim()).toBe("cardDetails");
});
+
+ it("initializes `cardDetailsForm` from `initialValues` when provided and editing existing cipher", () => {
+ const initialCardholderName = "New Name";
+ const initialBrand = "Amex";
+
+ (cipherFormProvider as any).config = {
+ initialValues: {
+ cardholderName: initialCardholderName,
+ brand: initialBrand,
+ },
+ };
+
+ const existingCard = new CardView();
+ existingCard.cardholderName = "Old Name";
+ existingCard.brand = "Visa";
+
+ getInitialCipherView.mockReturnValueOnce({ card: existingCard });
+
+ component.ngOnInit();
+
+ expect(component.cardDetailsForm.value.cardholderName).toBe(initialCardholderName);
+ expect(component.cardDetailsForm.value.brand).toBe(initialBrand);
+ });
});
diff --git a/libs/vault/src/cipher-form/components/card-details-section/card-details-section.component.ts b/libs/vault/src/cipher-form/components/card-details-section/card-details-section.component.ts
index 5fa8d0af131..056b93b6b99 100644
--- a/libs/vault/src/cipher-form/components/card-details-section/card-details-section.component.ts
+++ b/libs/vault/src/cipher-form/components/card-details-section/card-details-section.component.ts
@@ -158,6 +158,7 @@ export class CardDetailsSectionComponent implements OnInit {
this.cardDetailsForm.patchValue({
cardholderName: this.initialValues?.cardholderName ?? existingCard.cardholderName,
number: this.initialValues?.number ?? existingCard.number,
+ brand: this.initialValues?.brand ?? existingCard.brand,
expMonth: this.initialValues?.expMonth ?? existingCard.expMonth,
expYear: this.initialValues?.expYear ?? existingCard.expYear,
code: this.initialValues?.code ?? existingCard.code,
diff --git a/libs/vault/src/cipher-form/services/default-cipher-form.service.ts b/libs/vault/src/cipher-form/services/default-cipher-form.service.ts
index 8566e51d74f..63a9b3091e2 100644
--- a/libs/vault/src/cipher-form/services/default-cipher-form.service.ts
+++ b/libs/vault/src/cipher-form/services/default-cipher-form.service.ts
@@ -76,6 +76,9 @@ export class DefaultCipherFormService implements CipherFormService {
.then((res) => res.cipher);
} else {
// Updating a cipher with collection changes is not supported with a single request currently
+ // Save the new collectionIds before overwriting
+ const newCollectionIdsToSave = cipher.collectionIds;
+
// First update the cipher with the original collectionIds
cipher.collectionIds = config.originalCipher.collectionIds;
const newCipher = await this.cipherService.updateWithServer(
@@ -86,7 +89,7 @@ export class DefaultCipherFormService implements CipherFormService {
);
// Then save the new collection changes separately
- newCipher.collectionIds = cipher.collectionIds;
+ newCipher.collectionIds = newCollectionIdsToSave;
// TODO: Remove after migrating all SDK ops
const { cipher: encryptedCipher } = await this.cipherService.encrypt(newCipher, activeUserId);
diff --git a/libs/vault/src/cipher-view/cipher-view.component.html b/libs/vault/src/cipher-view/cipher-view.component.html
index 3d0cc4c4414..05d2ecede72 100644
--- a/libs/vault/src/cipher-view/cipher-view.component.html
+++ b/libs/vault/src/cipher-view/cipher-view.component.html
@@ -12,9 +12,15 @@
-
+
{{ "changeAtRiskPassword" | i18n }}
-
diff --git a/libs/vault/src/cipher-view/cipher-view.component.ts b/libs/vault/src/cipher-view/cipher-view.component.ts
index 26e3f18b542..24713d3f612 100644
--- a/libs/vault/src/cipher-view/cipher-view.component.ts
+++ b/libs/vault/src/cipher-view/cipher-view.component.ts
@@ -30,7 +30,7 @@ import {
CalloutModule,
SearchModule,
TypographyModule,
- AnchorLinkDirective,
+ LinkComponent,
} from "@bitwarden/components";
import { ChangeLoginPasswordService } from "../abstractions/change-login-password.service";
@@ -66,7 +66,7 @@ import { ViewIdentitySectionsComponent } from "./view-identity-sections/view-ide
ViewIdentitySectionsComponent,
LoginCredentialsViewComponent,
AutofillOptionsViewComponent,
- AnchorLinkDirective,
+ LinkComponent,
TypographyModule,
],
})
diff --git a/libs/vault/src/cipher-view/item-details/item-details-v2.component.ts b/libs/vault/src/cipher-view/item-details/item-details-v2.component.ts
index eb0e468fa4f..73e7c2706be 100644
--- a/libs/vault/src/cipher-view/item-details/item-details-v2.component.ts
+++ b/libs/vault/src/cipher-view/item-details/item-details-v2.component.ts
@@ -19,9 +19,9 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
import {
BadgeModule,
- ButtonLinkDirective,
CardComponent,
FormFieldModule,
+ LinkComponent,
TypographyModule,
} from "@bitwarden/components";
@@ -39,7 +39,7 @@ import { OrgIconDirective } from "../../components/org-icon.directive";
TypographyModule,
OrgIconDirective,
FormFieldModule,
- ButtonLinkDirective,
+ LinkComponent,
BadgeModule,
],
})
diff --git a/libs/vault/src/components/decryption-failure-dialog/decryption-failure-dialog.component.ts b/libs/vault/src/components/decryption-failure-dialog/decryption-failure-dialog.component.ts
index 6b1a0e0d8aa..e829c003c5a 100644
--- a/libs/vault/src/components/decryption-failure-dialog/decryption-failure-dialog.component.ts
+++ b/libs/vault/src/components/decryption-failure-dialog/decryption-failure-dialog.component.ts
@@ -7,7 +7,7 @@ import { CipherId } from "@bitwarden/common/types/guid";
import {
DIALOG_DATA,
DialogRef,
- AnchorLinkDirective,
+ LinkComponent,
AsyncActionsModule,
ButtonModule,
DialogModule,
@@ -32,7 +32,7 @@ export type DecryptionFailureDialogParams = {
JslibModule,
AsyncActionsModule,
ButtonModule,
- AnchorLinkDirective,
+ LinkComponent,
],
})
export class DecryptionFailureDialogComponent {
diff --git a/package-lock.json b/package-lock.json
index 55873bdb40c..752f186e970 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -28,7 +28,7 @@
"@electron/fuses": "1.8.0",
"@emotion/css": "11.13.5",
"@koa/multer": "4.0.0",
- "@koa/router": "14.0.0",
+ "@koa/router": "15.2.0",
"@microsoft/signalr": "8.0.7",
"@microsoft/signalr-protocol-msgpack": "8.0.7",
"@ng-select/ng-select": "20.7.0",
@@ -38,7 +38,7 @@
"bufferutil": "4.1.0",
"chalk": "4.1.2",
"commander": "14.0.0",
- "core-js": "3.47.0",
+ "core-js": "3.48.0",
"form-data": "4.0.4",
"https-proxy-agent": "7.0.6",
"inquirer": "8.2.6",
@@ -104,7 +104,6 @@
"@types/jsdom": "21.1.7",
"@types/koa": "3.0.1",
"@types/koa__multer": "2.0.7",
- "@types/koa__router": "12.0.4",
"@types/koa-bodyparser": "4.3.7",
"@types/koa-json": "2.0.24",
"@types/lowdb": "1.0.15",
@@ -200,12 +199,12 @@
"license": "SEE LICENSE IN LICENSE.txt",
"dependencies": {
"@koa/multer": "4.0.0",
- "@koa/router": "14.0.0",
+ "@koa/router": "15.2.0",
"big-integer": "1.6.52",
"browser-hrtime": "1.1.8",
"chalk": "4.1.2",
"commander": "14.0.0",
- "core-js": "3.47.0",
+ "core-js": "3.48.0",
"form-data": "4.0.4",
"https-proxy-agent": "7.0.6",
"inquirer": "8.2.6",
@@ -8746,18 +8745,46 @@
}
},
"node_modules/@koa/router": {
- "version": "14.0.0",
- "resolved": "https://registry.npmjs.org/@koa/router/-/router-14.0.0.tgz",
- "integrity": "sha512-LBSu5K0qAaaQcXX/0WIB9PGDevyCxxpnc1uq13vV/CgObaVxuis5hKl3Eboq/8gcb6ebnkAStW9NB/Em2eYyFA==",
+ "version": "15.2.0",
+ "resolved": "https://registry.npmjs.org/@koa/router/-/router-15.2.0.tgz",
+ "integrity": "sha512-7YUhq4W83cybfNa4E7JqJpWzoCTSvbnFltkvRaUaUX1ybFzlUoLNY1SqT8XmIAO6nGbFrev+FvJHw4mL+4WhuQ==",
"license": "MIT",
"dependencies": {
- "debug": "^4.4.1",
- "http-errors": "^2.0.0",
+ "debug": "^4.4.3",
+ "http-errors": "^2.0.1",
"koa-compose": "^4.1.0",
- "path-to-regexp": "^8.2.0"
+ "path-to-regexp": "^8.3.0"
},
"engines": {
"node": ">= 20"
+ },
+ "peerDependencies": {
+ "koa": "^2.0.0 || ^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "koa": {
+ "optional": false
+ }
+ }
+ },
+ "node_modules/@koa/router/node_modules/http-errors": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+ "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "~2.0.0",
+ "inherits": "~2.0.4",
+ "setprototypeof": "~1.2.0",
+ "statuses": "~2.0.2",
+ "toidentifier": "~1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
}
},
"node_modules/@leichtgewicht/ip-codec": {
@@ -15735,16 +15762,6 @@
"@types/koa": "*"
}
},
- "node_modules/@types/koa__router": {
- "version": "12.0.4",
- "resolved": "https://registry.npmjs.org/@types/koa__router/-/koa__router-12.0.4.tgz",
- "integrity": "sha512-Y7YBbSmfXZpa/m5UGGzb7XadJIRBRnwNY9cdAojZGp65Cpe5MAP3mOZE7e3bImt8dfKS4UFcR16SLH8L/z7PBw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/koa": "*"
- }
- },
"node_modules/@types/koa-bodyparser": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/@types/koa-bodyparser/-/koa-bodyparser-4.3.7.tgz",
@@ -20879,9 +20896,9 @@
}
},
"node_modules/core-js": {
- "version": "3.47.0",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz",
- "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==",
+ "version": "3.48.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz",
+ "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==",
"hasInstallScript": true,
"license": "MIT",
"funding": {
@@ -21479,9 +21496,9 @@
}
},
"node_modules/debug": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
- "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -35514,12 +35531,13 @@
}
},
"node_modules/path-to-regexp": {
- "version": "8.2.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
- "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
+ "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
"license": "MIT",
- "engines": {
- "node": ">=16"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
}
},
"node_modules/path-type": {
diff --git a/package.json b/package.json
index a02d67dcf51..ab54ba424d1 100644
--- a/package.json
+++ b/package.json
@@ -71,7 +71,6 @@
"@types/jsdom": "21.1.7",
"@types/koa": "3.0.1",
"@types/koa__multer": "2.0.7",
- "@types/koa__router": "12.0.4",
"@types/koa-bodyparser": "4.3.7",
"@types/koa-json": "2.0.24",
"@types/lowdb": "1.0.15",
@@ -167,7 +166,7 @@
"@electron/fuses": "1.8.0",
"@emotion/css": "11.13.5",
"@koa/multer": "4.0.0",
- "@koa/router": "14.0.0",
+ "@koa/router": "15.2.0",
"@microsoft/signalr": "8.0.7",
"@microsoft/signalr-protocol-msgpack": "8.0.7",
"@ng-select/ng-select": "20.7.0",
@@ -177,7 +176,7 @@
"bufferutil": "4.1.0",
"chalk": "4.1.2",
"commander": "14.0.0",
- "core-js": "3.47.0",
+ "core-js": "3.48.0",
"form-data": "4.0.4",
"https-proxy-agent": "7.0.6",
"inquirer": "8.2.6",