mirror of
https://github.com/bitwarden/browser
synced 2026-02-27 01:53:23 +00:00
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>
70 lines
2.1 KiB
TypeScript
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();
|
|
}
|
|
}
|