From e8cbcb0c3731b89b150eb6d25c0125e4623bf4a5 Mon Sep 17 00:00:00 2001 From: rr-bw <102181210+rr-bw@users.noreply.github.com> Date: Wed, 28 May 2025 01:23:17 -0700 Subject: [PATCH] [PM-18721] handle cross-component submit states --- ...ency-access-takeover-dialog.component.html | 1 + ...rgency-access-takeover-dialog.component.ts | 21 ++++++++++++++----- .../input-password.component.ts | 12 ++++------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover-dialog.component.html b/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover-dialog.component.html index 5bf36322b8f..76a9456c870 100644 --- a/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover-dialog.component.html +++ b/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover-dialog.component.html @@ -23,6 +23,7 @@ [flow]="inputPasswordFlow" [masterPasswordPolicyOptions]="masterPasswordPolicyOptions" (onPasswordFormSubmit)="handlePasswordFormSubmit($event)" + (isSubmitting)="handleIsSubmittingChange($event)" > } diff --git a/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover-dialog.component.ts b/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover-dialog.component.ts index 79c7aef605f..960fdfb1c53 100644 --- a/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover-dialog.component.ts +++ b/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover-dialog.component.ts @@ -1,6 +1,6 @@ import { CommonModule } from "@angular/common"; import { Component, Inject, OnInit, ViewChild } from "@angular/core"; -import { BehaviorSubject, firstValueFrom } from "rxjs"; +import { BehaviorSubject, combineLatest, firstValueFrom, map } from "rxjs"; import { InputPasswordComponent, @@ -65,8 +65,15 @@ export class EmergencyAccessTakeoverDialogComponent implements OnInit { @ViewChild(InputPasswordComponent) inputPasswordComponent: InputPasswordComponent | undefined = undefined; - private submittingBehaviorSubject = new BehaviorSubject(false); - submitting$ = this.submittingBehaviorSubject.asObservable(); + private parentSubmittingBehaviorSubject = new BehaviorSubject(false); + parentSubmitting$ = this.parentSubmittingBehaviorSubject.asObservable(); + + private childSubmittingBehaviorSubject = new BehaviorSubject(false); + childSubmitting$ = this.childSubmittingBehaviorSubject.asObservable(); + + submitting$ = combineLatest([this.parentSubmitting$, this.childSubmitting$]).pipe( + map(([parentIsSubmitting, childIsSubmitting]) => parentIsSubmitting || childIsSubmitting), + ); initializing = true; inputPasswordFlow = InputPasswordFlow.ChangePasswordDelegation; @@ -105,7 +112,7 @@ export class EmergencyAccessTakeoverDialogComponent implements OnInit { }; protected async handlePasswordFormSubmit(passwordInputResult: PasswordInputResult) { - this.submittingBehaviorSubject.next(true); + this.parentSubmittingBehaviorSubject.next(true); try { await this.emergencyAccessService.takeover( @@ -122,12 +129,16 @@ export class EmergencyAccessTakeoverDialogComponent implements OnInit { message: this.i18nService.t("unexpectedError"), }); } finally { - this.submittingBehaviorSubject.next(false); + this.parentSubmittingBehaviorSubject.next(false); } this.dialogRef.close(EmergencyAccessTakeoverDialogResultTypes.Done); } + protected handleIsSubmittingChange(isSubmitting: boolean) { + this.childSubmittingBehaviorSubject.next(isSubmitting); + } + /** * Strongly typed helper to open an EmergencyAccessTakeoverDialogComponent * @param dialogService Instance of the dialog service that will be used to open the dialog diff --git a/libs/auth/src/angular/input-password/input-password.component.ts b/libs/auth/src/angular/input-password/input-password.component.ts index 6eb7b91447e..79edfb32846 100644 --- a/libs/auth/src/angular/input-password/input-password.component.ts +++ b/libs/auth/src/angular/input-password/input-password.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from "@angular/core"; import { ReactiveFormsModule, FormBuilder, Validators, FormControl } from "@angular/forms"; -import { BehaviorSubject, firstValueFrom } from "rxjs"; +import { firstValueFrom } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { @@ -117,15 +117,13 @@ interface InputPasswordForm { ], }) export class InputPasswordComponent implements OnInit { - private submittingBehaviorSubject = new BehaviorSubject(false); - submitting$ = this.submittingBehaviorSubject.asObservable(); - @ViewChild(PasswordStrengthV2Component) passwordStrengthComponent: | PasswordStrengthV2Component | undefined = undefined; @Output() onPasswordFormSubmit = new EventEmitter(); @Output() onSecondaryButtonClick = new EventEmitter(); + @Output() isSubmitting = new EventEmitter(); @Input({ required: true }) flow!: InputPasswordFlow; @@ -267,7 +265,7 @@ export class InputPasswordComponent implements OnInit { submit = async () => { try { - this.submittingBehaviorSubject.next(true); + this.isSubmitting.emit(true); this.verifyFlow(); @@ -275,7 +273,6 @@ export class InputPasswordComponent implements OnInit { if (this.formGroup.invalid) { this.showErrorSummary = true; - this.submittingBehaviorSubject.next(false); return; } @@ -396,7 +393,7 @@ export class InputPasswordComponent implements OnInit { } catch (e) { this.validationService.showError(e); } finally { - this.submittingBehaviorSubject.next(false); + this.isSubmitting.emit(false); } }; @@ -453,7 +450,6 @@ export class InputPasswordComponent implements OnInit { false, ); if (!newPasswordVerified) { - this.submittingBehaviorSubject.next(false); return; }