1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-22 11:13:46 +00:00

[PM-24304][PM-24305] - [Defect] Some fields are not disabled when editing an item from My Vault (#15982)

* disable all remaining form fields for editing personally owned My Items

* fix failing tests

* ensure collection field is also properly disabled

* clean up logic

* fix failing test

* fix test

* refactor variable to avoid using `is` prefix

* directly reference parent form for status rather than subscribe to it

* refactor subscription for form status changes

* use observable as an Output

* disable attachment button on desktop vault when the form

* disable custom field components when custom fields already exist and parent form is disabled

* disable attachments button in the browser when the edit form is disabled

* grab icon button instance for disabled state

---------

Co-authored-by: Nick Krantz <nick@livefront.com>
This commit is contained in:
Jordan Aasen
2025-08-25 15:48:00 -07:00
committed by GitHub
parent e10d13faa8
commit 9ed69ef4b8
22 changed files with 224 additions and 36 deletions

View File

@@ -1,5 +1,10 @@
<bit-item>
<button bit-item-content type="button" (click)="openAttachments()">
<button
bit-item-content
type="button"
(click)="openAttachments()"
[disabled]="parentFormDisabled"
>
{{ "attachments" | i18n }}
<span *ngIf="!canAccessAttachments" bitBadge variant="success" slot="default-trailing">
{{ "premium" | i18n }}

View File

@@ -1,4 +1,5 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { By } from "@angular/platform-browser";
import { Router } from "@angular/router";
import { RouterTestingModule } from "@angular/router/testing";
import { BehaviorSubject, of } from "rxjs";
@@ -15,6 +16,7 @@ import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.servi
import { CipherType } from "@bitwarden/common/vault/enums";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { ToastService } from "@bitwarden/components";
import { CipherFormContainer } from "@bitwarden/vault";
import BrowserPopupUtils from "../../../../../../platform/browser/browser-popup-utils";
import { FilePopoutUtilsService } from "../../../../../../tools/popup/services/file-popout-utils.service";
@@ -62,6 +64,7 @@ describe("OpenAttachmentsComponent", () => {
name: "Test User",
}),
};
const formStatusChange$ = new BehaviorSubject<"enabled" | "disabled">("enabled");
beforeEach(async () => {
openCurrentPagePopout.mockClear();
@@ -70,6 +73,7 @@ describe("OpenAttachmentsComponent", () => {
organizations$.mockClear();
showFilePopoutMessage.mockClear();
hasPremiumFromAnySource$.next(true);
formStatusChange$.next("enabled");
await TestBed.configureTestingModule({
imports: [OpenAttachmentsComponent, RouterTestingModule],
@@ -84,6 +88,10 @@ describe("OpenAttachmentsComponent", () => {
decrypt: jest.fn().mockResolvedValue(cipherView),
},
},
{
provide: CipherFormContainer,
useValue: { formStatusChange$ },
},
{
provide: ToastService,
useValue: { showToast },
@@ -147,6 +155,21 @@ describe("OpenAttachmentsComponent", () => {
expect(router.navigate).toHaveBeenCalledWith(["/premium"]);
});
it("disables attachments when the edit form is disabled", () => {
formStatusChange$.next("disabled");
fixture.detectChanges();
let button = fixture.debugElement.query(By.css("button"));
expect(button.nativeElement.disabled).toBe(true);
formStatusChange$.next("enabled");
fixture.detectChanges();
button = fixture.debugElement.query(By.css("button"));
expect(button.nativeElement.disabled).toBe(false);
});
describe("Free Orgs", () => {
beforeEach(() => {
component.cipherIsAPartOfFreeOrg = false;

View File

@@ -19,6 +19,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { CipherId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { BadgeModule, ItemModule, ToastService, TypographyModule } from "@bitwarden/components";
import { CipherFormContainer } from "@bitwarden/vault";
import BrowserPopupUtils from "../../../../../../platform/browser/browser-popup-utils";
import { FilePopoutUtilsService } from "../../../../../../tools/popup/services/file-popout-utils.service";
@@ -41,6 +42,9 @@ export class OpenAttachmentsComponent implements OnInit {
/** True when the cipher is a part of a free organization */
cipherIsAPartOfFreeOrg: boolean;
/** Tracks the disabled status of the edit cipher form */
parentFormDisabled: boolean;
constructor(
private router: Router,
private billingAccountProfileStateService: BillingAccountProfileStateService,
@@ -50,6 +54,7 @@ export class OpenAttachmentsComponent implements OnInit {
private i18nService: I18nService,
private filePopoutUtilsService: FilePopoutUtilsService,
private accountService: AccountService,
private cipherFormContainer: CipherFormContainer,
) {
this.accountService.activeAccount$
.pipe(
@@ -61,6 +66,10 @@ export class OpenAttachmentsComponent implements OnInit {
.subscribe((canAccessPremium) => {
this.canAccessAttachments = canAccessPremium;
});
this.cipherFormContainer.formStatusChange$.pipe(takeUntilDestroyed()).subscribe((status) => {
this.parentFormDisabled = status === "disabled";
});
}
async ngOnInit(): Promise<void> {