1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-27 01:53:23 +00:00
Files
browser/libs/components/src/async-actions/bit-action.directive.ts
Will Martin 827c4c0301 [PM-15847] libs/components strict migration (#15738)
This PR migrates `libs/components` to use strict TypeScript.

- Remove `@ts-strict-ignore` from each file in `libs/components` and resolved any new compilation errors
- Converted ViewChild and ContentChild decorators to use the new signal-based queries using the [Angular signal queries migration](https://angular.dev/reference/migrations/signal-queries)
  - Made view/content children `required` where appropriate, eliminating the need for additional null checking. This helped simplify the strict migration.

---

Co-authored-by: Vicki League <vleague@bitwarden.com>
2025-08-18 15:36:45 -04:00

70 lines
2.1 KiB
TypeScript

import { DestroyRef, Directive, HostListener, inject, model, Optional } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { BehaviorSubject, finalize, tap } from "rxjs";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
import { ButtonLikeAbstraction } from "../shared/button-like.abstraction";
import { FunctionReturningAwaitable, functionToObservable } from "../utils/function-to-observable";
/**
* Allow a single button to perform async actions on click and reflect the progress in the UI by automatically
* activating the loading effect while the action is processed.
*/
@Directive({
selector: "[bitAction]",
})
export class BitActionDirective {
private _loading$ = new BehaviorSubject<boolean>(false);
/**
* Observable of loading behavior subject
*
* Used in `form-button.directive.ts`
*/
readonly loading$ = this._loading$.asObservable();
get loading() {
return this._loading$.value;
}
set loading(value: boolean) {
this._loading$.next(value);
this.buttonComponent.loading.set(value);
}
disabled = false;
readonly handler = model.required<FunctionReturningAwaitable>({ alias: "bitAction" });
private readonly destroyRef = inject(DestroyRef);
constructor(
private buttonComponent: ButtonLikeAbstraction,
@Optional() private validationService?: ValidationService,
@Optional() private logService?: LogService,
) {}
@HostListener("click")
protected async onClick() {
if (!this.handler() || this.loading || this.disabled || this.buttonComponent.disabled()) {
return;
}
this.loading = true;
functionToObservable(this.handler())
.pipe(
tap({
error: (err: unknown) => {
this.logService?.error(`Async action exception: ${err}`);
this.validationService?.showError(err);
},
}),
finalize(() => (this.loading = false)),
takeUntilDestroyed(this.destroyRef),
)
.subscribe();
}
}