mirror of
https://github.com/bitwarden/browser
synced 2026-02-11 05:53:42 +00:00
disable all remaining form fields for editing personally owned My Items
This commit is contained in:
@@ -16,9 +16,15 @@
|
||||
[submitBtn]="submitBtn"
|
||||
(formReady)="onFormReady()"
|
||||
(cipherSaved)="onCipherSaved($event)"
|
||||
(onFormStatusChange)="formStatusChanged($event)"
|
||||
>
|
||||
<bit-item slot="attachment-button">
|
||||
<button bit-item-content type="button" (click)="openAttachmentsDialog()">
|
||||
<button
|
||||
[disabled]="isAttachmentsButtonDisabled"
|
||||
bit-item-content
|
||||
type="button"
|
||||
(click)="openAttachmentsDialog()"
|
||||
>
|
||||
<p class="tw-m-0">
|
||||
{{ "attachments" | i18n }}
|
||||
<span
|
||||
|
||||
@@ -273,6 +273,8 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy {
|
||||
|
||||
protected canDelete = false;
|
||||
|
||||
protected isAttachmentsButtonDisabled = false;
|
||||
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) protected params: VaultItemDialogParams,
|
||||
private dialogRef: DialogRef<VaultItemDialogResult>,
|
||||
@@ -341,6 +343,10 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
formStatusChanged(status: "disabled" | "enabled") {
|
||||
this.isAttachmentsButtonDisabled = status === "disabled";
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the CipherFormComponent when the cipher is saved successfully.
|
||||
* @param cipherView - The newly saved cipher.
|
||||
|
||||
@@ -78,8 +78,8 @@ export abstract class CipherFormContainer {
|
||||
abstract enableFormFields(): void;
|
||||
|
||||
/**
|
||||
* An observable that emits when the form status changes to enabled.
|
||||
* This can be used to disable child forms when the parent form is enabled.
|
||||
* An observable that emits when the form status changes between enabled/disabled.
|
||||
* This can be used for child forms to react to changes in the form status.
|
||||
*/
|
||||
formEnabled$: Observable<void>;
|
||||
formStatusChange$: Observable<"enabled" | "disabled">;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
bitLink
|
||||
type="button"
|
||||
linkType="primary"
|
||||
*ngIf="!hasCustomFields && !isPartialEdit"
|
||||
*ngIf="!hasCustomFields && !isPartialEdit && allowNewField"
|
||||
(click)="addCustomField()"
|
||||
>
|
||||
<i class="bwi bwi-plus tw-font-bold" aria-hidden="true"></i>
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { ChangeDetectorRef, Component, Input, OnInit, ViewChild } from "@angular/core";
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
DestroyRef,
|
||||
inject,
|
||||
Input,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
} from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
||||
import { shareReplay } from "rxjs";
|
||||
@@ -56,8 +64,13 @@ export class AdditionalOptionsSectionComponent implements OnInit {
|
||||
/** True when the form is in `partial-edit` mode */
|
||||
isPartialEdit = false;
|
||||
|
||||
/** True when the form allows new fields to be added */
|
||||
allowNewField = true;
|
||||
|
||||
@Input() disableSectionMargin: boolean;
|
||||
|
||||
private destroyRef = inject(DestroyRef);
|
||||
|
||||
constructor(
|
||||
private cipherFormContainer: CipherFormContainer,
|
||||
private formBuilder: FormBuilder,
|
||||
@@ -89,6 +102,17 @@ export class AdditionalOptionsSectionComponent implements OnInit {
|
||||
this.additionalOptionsForm.disable();
|
||||
this.isPartialEdit = true;
|
||||
}
|
||||
|
||||
// Disable adding new URIs when the cipher form is disabled
|
||||
this.cipherFormContainer.formStatusChange$
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((status) => {
|
||||
if (status === "disabled") {
|
||||
this.allowNewField = false;
|
||||
} else if (status === "enabled") {
|
||||
this.allowNewField = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Opens the add custom field dialog */
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { LiveAnnouncer } from "@angular/cdk/a11y";
|
||||
import { CdkDragDrop, DragDropModule, moveItemInArray } from "@angular/cdk/drag-drop";
|
||||
import { AsyncPipe, NgForOf, NgIf } from "@angular/common";
|
||||
import { Component, OnInit, QueryList, ViewChildren } from "@angular/core";
|
||||
import { Component, DestroyRef, inject, OnInit, QueryList, ViewChildren } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
||||
import { filter, Subject, switchMap, take } from "rxjs";
|
||||
@@ -88,6 +88,7 @@ export class AutofillOptionsComponent implements OnInit {
|
||||
* Emits when a new URI input is added to the form and should be focused.
|
||||
*/
|
||||
private focusOnNewInput$ = new Subject<void>();
|
||||
private destroyRef = inject(DestroyRef);
|
||||
|
||||
constructor(
|
||||
private cipherFormContainer: CipherFormContainer,
|
||||
@@ -102,7 +103,7 @@ export class AutofillOptionsComponent implements OnInit {
|
||||
|
||||
this.autofillOptionsForm.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
||||
this.cipherFormContainer.patchCipher((cipher) => {
|
||||
cipher.login.uris = value.uris.map((uri: UriField) =>
|
||||
cipher.login.uris = value.uris?.map((uri: UriField) =>
|
||||
Object.assign(new LoginUriView(), {
|
||||
uri: uri.uri,
|
||||
match: uri.matchDetection,
|
||||
@@ -139,6 +140,15 @@ export class AutofillOptionsComponent implements OnInit {
|
||||
if (this.cipherFormContainer.config.mode === "partial-edit") {
|
||||
this.autofillOptionsForm.disable();
|
||||
}
|
||||
|
||||
// Disable adding new URIs when the cipher form is disabled
|
||||
this.cipherFormContainer.formStatusChange$
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((status) => {
|
||||
if (status === "disabled") {
|
||||
this.autofillOptionsForm.disable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private initFromExistingCipher(existingLogin: LoginView) {
|
||||
|
||||
@@ -112,11 +112,13 @@ export class CipherFormComponent implements AfterViewInit, OnInit, OnChanges, Ci
|
||||
|
||||
@Output() formReady = this.formReadySubject.asObservable();
|
||||
|
||||
@Output() onFormStatusChange = new EventEmitter<"enabled" | "disabled">();
|
||||
|
||||
/**
|
||||
* Emitted when the form is enabled
|
||||
*/
|
||||
private formEnabledSubject = new Subject<void>();
|
||||
formEnabled$ = this.formEnabledSubject.asObservable();
|
||||
private formStatusChangeSubject = new Subject<"enabled" | "disabled">();
|
||||
formStatusChange$ = this.formStatusChangeSubject.asObservable();
|
||||
|
||||
/**
|
||||
* The original cipher being edited or cloned. Null for add mode.
|
||||
@@ -158,11 +160,14 @@ export class CipherFormComponent implements AfterViewInit, OnInit, OnChanges, Ci
|
||||
|
||||
disableFormFields(): void {
|
||||
this.cipherForm.disable({ emitEvent: false });
|
||||
this.formStatusChangeSubject.next("disabled");
|
||||
this.onFormStatusChange.emit("disabled");
|
||||
}
|
||||
|
||||
enableFormFields(): void {
|
||||
this.cipherForm.enable({ emitEvent: false });
|
||||
this.formEnabledSubject.next();
|
||||
this.formStatusChangeSubject.next("enabled");
|
||||
this.onFormStatusChange.emit("enabled");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
[attr.aria-checked]="itemDetailsForm.value.favorite"
|
||||
[appA11yTitle]="'favorite' | i18n"
|
||||
(click)="toggleFavorite()"
|
||||
[disabled]="isFavoriteButtonDisabled"
|
||||
></button>
|
||||
</bit-section-header>
|
||||
<bit-card>
|
||||
|
||||
@@ -82,6 +82,8 @@ export class ItemDetailsSectionComponent implements OnInit {
|
||||
|
||||
protected userId: UserId;
|
||||
|
||||
protected isFavoriteButtonDisabled = false;
|
||||
|
||||
@Input({ required: true })
|
||||
config: CipherFormConfig;
|
||||
|
||||
@@ -248,8 +250,10 @@ export class ItemDetailsSectionComponent implements OnInit {
|
||||
if (this.itemDetailsForm.controls.organizationId.value === null) {
|
||||
this.cipherFormContainer.disableFormFields();
|
||||
this.itemDetailsForm.controls.organizationId.enable();
|
||||
this.isFavoriteButtonDisabled = true;
|
||||
} else {
|
||||
this.cipherFormContainer.enableFormFields();
|
||||
this.isFavoriteButtonDisabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,9 +98,13 @@ export class SshKeySectionComponent implements OnInit {
|
||||
|
||||
// Disable the form if the cipher form container is enabled
|
||||
// to prevent user interaction
|
||||
this.cipherFormContainer.formEnabled$
|
||||
this.cipherFormContainer.formStatusChange$
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe(() => this.sshKeyForm.disable());
|
||||
.subscribe((status) => {
|
||||
if (status === "enabled") {
|
||||
this.sshKeyForm.disable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Set form initial form values from the current cipher */
|
||||
|
||||
Reference in New Issue
Block a user