mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 13:23:34 +00:00
Migrate UIF to use takeuntilDestroyed (#15777)
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
// FIXME: Update this file to be type safe and remove this and next line
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from "@angular/core";
|
import { ChangeDetectorRef, Component, OnInit, inject, DestroyRef } from "@angular/core";
|
||||||
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
import { ActivatedRoute, Data, NavigationEnd, Router, RouterModule } from "@angular/router";
|
import { ActivatedRoute, Data, NavigationEnd, Router, RouterModule } from "@angular/router";
|
||||||
import { Subject, filter, switchMap, takeUntil, tap } from "rxjs";
|
import { filter, switchMap, tap } from "rxjs";
|
||||||
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
|
|
||||||
@@ -51,9 +52,7 @@ export interface AnonLayoutWrapperData {
|
|||||||
templateUrl: "anon-layout-wrapper.component.html",
|
templateUrl: "anon-layout-wrapper.component.html",
|
||||||
imports: [AnonLayoutComponent, RouterModule],
|
imports: [AnonLayoutComponent, RouterModule],
|
||||||
})
|
})
|
||||||
export class AnonLayoutWrapperComponent implements OnInit, OnDestroy {
|
export class AnonLayoutWrapperComponent implements OnInit {
|
||||||
private destroy$ = new Subject<void>();
|
|
||||||
|
|
||||||
protected pageTitle: string;
|
protected pageTitle: string;
|
||||||
protected pageSubtitle: string;
|
protected pageSubtitle: string;
|
||||||
protected pageIcon: Icon;
|
protected pageIcon: Icon;
|
||||||
@@ -70,6 +69,8 @@ export class AnonLayoutWrapperComponent implements OnInit, OnDestroy {
|
|||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
// Set the initial page data on load
|
// Set the initial page data on load
|
||||||
this.setAnonLayoutWrapperDataFromRouteData(this.route.snapshot.firstChild?.data);
|
this.setAnonLayoutWrapperDataFromRouteData(this.route.snapshot.firstChild?.data);
|
||||||
@@ -85,7 +86,7 @@ export class AnonLayoutWrapperComponent implements OnInit, OnDestroy {
|
|||||||
// reset page data on page changes
|
// reset page data on page changes
|
||||||
tap(() => this.resetPageData()),
|
tap(() => this.resetPageData()),
|
||||||
switchMap(() => this.route.firstChild?.data || null),
|
switchMap(() => this.route.firstChild?.data || null),
|
||||||
takeUntil(this.destroy$),
|
takeUntilDestroyed(this.destroyRef),
|
||||||
)
|
)
|
||||||
.subscribe((firstChildRouteData: Data | null) => {
|
.subscribe((firstChildRouteData: Data | null) => {
|
||||||
this.setAnonLayoutWrapperDataFromRouteData(firstChildRouteData);
|
this.setAnonLayoutWrapperDataFromRouteData(firstChildRouteData);
|
||||||
@@ -121,7 +122,7 @@ export class AnonLayoutWrapperComponent implements OnInit, OnDestroy {
|
|||||||
private listenForServiceDataChanges() {
|
private listenForServiceDataChanges() {
|
||||||
this.anonLayoutWrapperDataService
|
this.anonLayoutWrapperDataService
|
||||||
.anonLayoutWrapperData$()
|
.anonLayoutWrapperData$()
|
||||||
.pipe(takeUntil(this.destroy$))
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
.subscribe((data: AnonLayoutWrapperData) => {
|
.subscribe((data: AnonLayoutWrapperData) => {
|
||||||
this.setAnonLayoutWrapperData(data);
|
this.setAnonLayoutWrapperData(data);
|
||||||
});
|
});
|
||||||
@@ -180,9 +181,4 @@ export class AnonLayoutWrapperComponent implements OnInit, OnDestroy {
|
|||||||
this.hideCardWrapper = null;
|
this.hideCardWrapper = null;
|
||||||
this.hideIcon = null;
|
this.hideIcon = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.destroy$.next();
|
|
||||||
this.destroy$.complete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
// FIXME: Update this file to be type safe and remove this and next line
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { Directive, HostListener, model, OnDestroy, Optional } from "@angular/core";
|
import { Directive, HostListener, model, Optional, inject, DestroyRef } from "@angular/core";
|
||||||
import { BehaviorSubject, finalize, Subject, takeUntil, tap } from "rxjs";
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
|
import { BehaviorSubject, finalize, tap } from "rxjs";
|
||||||
|
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||||
@@ -16,8 +17,7 @@ import { FunctionReturningAwaitable, functionToObservable } from "../utils/funct
|
|||||||
@Directive({
|
@Directive({
|
||||||
selector: "[bitAction]",
|
selector: "[bitAction]",
|
||||||
})
|
})
|
||||||
export class BitActionDirective implements OnDestroy {
|
export class BitActionDirective {
|
||||||
private destroy$ = new Subject<void>();
|
|
||||||
private _loading$ = new BehaviorSubject<boolean>(false);
|
private _loading$ = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,6 +40,8 @@ export class BitActionDirective implements OnDestroy {
|
|||||||
|
|
||||||
readonly handler = model<FunctionReturningAwaitable>(undefined, { alias: "bitAction" });
|
readonly handler = model<FunctionReturningAwaitable>(undefined, { alias: "bitAction" });
|
||||||
|
|
||||||
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private buttonComponent: ButtonLikeAbstraction,
|
private buttonComponent: ButtonLikeAbstraction,
|
||||||
@Optional() private validationService?: ValidationService,
|
@Optional() private validationService?: ValidationService,
|
||||||
@@ -62,13 +64,8 @@ export class BitActionDirective implements OnDestroy {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
finalize(() => (this.loading = false)),
|
finalize(() => (this.loading = false)),
|
||||||
takeUntil(this.destroy$),
|
takeUntilDestroyed(this.destroyRef),
|
||||||
)
|
)
|
||||||
.subscribe();
|
.subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
this.destroy$.next();
|
|
||||||
this.destroy$.complete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
// FIXME: Update this file to be type safe and remove this and next line
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { Directive, OnDestroy, OnInit, Optional, input } from "@angular/core";
|
import { Directive, OnInit, Optional, input, inject, DestroyRef } from "@angular/core";
|
||||||
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
import { FormGroupDirective } from "@angular/forms";
|
import { FormGroupDirective } from "@angular/forms";
|
||||||
import { BehaviorSubject, catchError, filter, of, Subject, switchMap, takeUntil } from "rxjs";
|
import { BehaviorSubject, catchError, filter, of, switchMap } from "rxjs";
|
||||||
|
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||||
@@ -15,8 +16,9 @@ import { FunctionReturningAwaitable, functionToObservable } from "../utils/funct
|
|||||||
@Directive({
|
@Directive({
|
||||||
selector: "[formGroup][bitSubmit]",
|
selector: "[formGroup][bitSubmit]",
|
||||||
})
|
})
|
||||||
export class BitSubmitDirective implements OnInit, OnDestroy {
|
export class BitSubmitDirective implements OnInit {
|
||||||
private destroy$ = new Subject<void>();
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
private _loading$ = new BehaviorSubject<boolean>(false);
|
private _loading$ = new BehaviorSubject<boolean>(false);
|
||||||
private _disabled$ = new BehaviorSubject<boolean>(false);
|
private _disabled$ = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
@@ -51,7 +53,7 @@ export class BitSubmitDirective implements OnInit, OnDestroy {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
takeUntil(this.destroy$),
|
takeUntilDestroyed(),
|
||||||
)
|
)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: () => (this.loading = false),
|
next: () => (this.loading = false),
|
||||||
@@ -60,13 +62,15 @@ export class BitSubmitDirective implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.formGroupDirective.statusChanges.pipe(takeUntil(this.destroy$)).subscribe((c) => {
|
this.formGroupDirective.statusChanges
|
||||||
if (this.allowDisabledFormSubmit()) {
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
this._disabled$.next(false);
|
.subscribe((c) => {
|
||||||
} else {
|
if (this.allowDisabledFormSubmit()) {
|
||||||
this._disabled$.next(c === "DISABLED");
|
this._disabled$.next(false);
|
||||||
}
|
} else {
|
||||||
});
|
this._disabled$.next(c === "DISABLED");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get disabled() {
|
get disabled() {
|
||||||
@@ -85,9 +89,4 @@ export class BitSubmitDirective implements OnInit, OnDestroy {
|
|||||||
this.disabled = value;
|
this.disabled = value;
|
||||||
this._loading$.next(value);
|
this._loading$.next(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
this.destroy$.next();
|
|
||||||
this.destroy$.complete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
// FIXME: Update this file to be type safe and remove this and next line
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { Directive, OnDestroy, Optional, input } from "@angular/core";
|
import { Directive, Optional, input } from "@angular/core";
|
||||||
import { Subject, takeUntil } from "rxjs";
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
|
|
||||||
import { ButtonLikeAbstraction } from "../shared/button-like.abstraction";
|
import { ButtonLikeAbstraction } from "../shared/button-like.abstraction";
|
||||||
|
|
||||||
@@ -26,9 +26,7 @@ import { BitSubmitDirective } from "./bit-submit.directive";
|
|||||||
@Directive({
|
@Directive({
|
||||||
selector: "button[bitFormButton]",
|
selector: "button[bitFormButton]",
|
||||||
})
|
})
|
||||||
export class BitFormButtonDirective implements OnDestroy {
|
export class BitFormButtonDirective {
|
||||||
private destroy$ = new Subject<void>();
|
|
||||||
|
|
||||||
readonly type = input<string>();
|
readonly type = input<string>();
|
||||||
readonly disabled = input<boolean>();
|
readonly disabled = input<boolean>();
|
||||||
|
|
||||||
@@ -38,7 +36,7 @@ export class BitFormButtonDirective implements OnDestroy {
|
|||||||
@Optional() actionDirective?: BitActionDirective,
|
@Optional() actionDirective?: BitActionDirective,
|
||||||
) {
|
) {
|
||||||
if (submitDirective && buttonComponent) {
|
if (submitDirective && buttonComponent) {
|
||||||
submitDirective.loading$.pipe(takeUntil(this.destroy$)).subscribe((loading) => {
|
submitDirective.loading$.pipe(takeUntilDestroyed()).subscribe((loading) => {
|
||||||
if (this.type() === "submit") {
|
if (this.type() === "submit") {
|
||||||
buttonComponent.loading.set(loading);
|
buttonComponent.loading.set(loading);
|
||||||
} else {
|
} else {
|
||||||
@@ -46,7 +44,7 @@ export class BitFormButtonDirective implements OnDestroy {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
submitDirective.disabled$.pipe(takeUntil(this.destroy$)).subscribe((disabled) => {
|
submitDirective.disabled$.pipe(takeUntilDestroyed()).subscribe((disabled) => {
|
||||||
const disabledValue = this.disabled();
|
const disabledValue = this.disabled();
|
||||||
if (disabledValue !== false) {
|
if (disabledValue !== false) {
|
||||||
buttonComponent.disabled.set(disabledValue || disabled);
|
buttonComponent.disabled.set(disabledValue || disabled);
|
||||||
@@ -55,18 +53,13 @@ export class BitFormButtonDirective implements OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (submitDirective && actionDirective) {
|
if (submitDirective && actionDirective) {
|
||||||
actionDirective.loading$.pipe(takeUntil(this.destroy$)).subscribe((disabled) => {
|
actionDirective.loading$.pipe(takeUntilDestroyed()).subscribe((disabled) => {
|
||||||
submitDirective.disabled = disabled;
|
submitDirective.disabled = disabled;
|
||||||
});
|
});
|
||||||
|
|
||||||
submitDirective.disabled$.pipe(takeUntil(this.destroy$)).subscribe((disabled) => {
|
submitDirective.disabled$.pipe(takeUntilDestroyed()).subscribe((disabled) => {
|
||||||
actionDirective.disabled = disabled;
|
actionDirective.disabled = disabled;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
this.destroy$.next();
|
|
||||||
this.destroy$.complete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,13 +11,14 @@ import {
|
|||||||
ContentChildren,
|
ContentChildren,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
Input,
|
Input,
|
||||||
OnDestroy,
|
|
||||||
Output,
|
Output,
|
||||||
QueryList,
|
QueryList,
|
||||||
ViewChildren,
|
ViewChildren,
|
||||||
input,
|
input,
|
||||||
|
inject,
|
||||||
|
DestroyRef,
|
||||||
} from "@angular/core";
|
} from "@angular/core";
|
||||||
import { Subject, takeUntil } from "rxjs";
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
|
|
||||||
import { TabHeaderComponent } from "../shared/tab-header.component";
|
import { TabHeaderComponent } from "../shared/tab-header.component";
|
||||||
import { TabListContainerDirective } from "../shared/tab-list-container.directive";
|
import { TabListContainerDirective } from "../shared/tab-list-container.directive";
|
||||||
@@ -40,11 +41,10 @@ let nextId = 0;
|
|||||||
TabBodyComponent,
|
TabBodyComponent,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class TabGroupComponent
|
export class TabGroupComponent implements AfterContentChecked, AfterContentInit, AfterViewInit {
|
||||||
implements AfterContentChecked, AfterContentInit, AfterViewInit, OnDestroy
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
{
|
|
||||||
private readonly _groupId: number;
|
private readonly _groupId: number;
|
||||||
private readonly destroy$ = new Subject<void>();
|
|
||||||
private _indexToSelect: number | null = 0;
|
private _indexToSelect: number | null = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -150,7 +150,7 @@ export class TabGroupComponent
|
|||||||
ngAfterContentInit() {
|
ngAfterContentInit() {
|
||||||
// Subscribe to any changes in the number of tabs, in order to be able
|
// Subscribe to any changes in the number of tabs, in order to be able
|
||||||
// to re-render content when new tabs are added or removed.
|
// to re-render content when new tabs are added or removed.
|
||||||
this.tabs.changes.pipe(takeUntil(this.destroy$)).subscribe(() => {
|
this.tabs.changes.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
|
||||||
const indexToSelect = this._clampTabIndex(this._indexToSelect);
|
const indexToSelect = this._clampTabIndex(this._indexToSelect);
|
||||||
|
|
||||||
// If the selected tab didn't explicitly change, keep the previously
|
// If the selected tab didn't explicitly change, keep the previously
|
||||||
@@ -183,11 +183,6 @@ export class TabGroupComponent
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.destroy$.next();
|
|
||||||
this.destroy$.complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
private _clampTabIndex(index: number): number {
|
private _clampTabIndex(index: number): number {
|
||||||
return Math.min(this.tabs.length - 1, Math.max(index || 0, 0));
|
return Math.min(this.tabs.length - 1, Math.max(index || 0, 0));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ import {
|
|||||||
Component,
|
Component,
|
||||||
HostListener,
|
HostListener,
|
||||||
Input,
|
Input,
|
||||||
OnDestroy,
|
|
||||||
ViewChild,
|
ViewChild,
|
||||||
input,
|
input,
|
||||||
|
inject,
|
||||||
|
DestroyRef,
|
||||||
} from "@angular/core";
|
} from "@angular/core";
|
||||||
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
import { IsActiveMatchOptions, RouterLinkActive, RouterModule } from "@angular/router";
|
import { IsActiveMatchOptions, RouterLinkActive, RouterModule } from "@angular/router";
|
||||||
import { Subject, takeUntil } from "rxjs";
|
|
||||||
|
|
||||||
import { TabListItemDirective } from "../shared/tab-list-item.directive";
|
import { TabListItemDirective } from "../shared/tab-list-item.directive";
|
||||||
|
|
||||||
@@ -22,9 +23,8 @@ import { TabNavBarComponent } from "./tab-nav-bar.component";
|
|||||||
templateUrl: "tab-link.component.html",
|
templateUrl: "tab-link.component.html",
|
||||||
imports: [TabListItemDirective, RouterModule],
|
imports: [TabListItemDirective, RouterModule],
|
||||||
})
|
})
|
||||||
export class TabLinkComponent implements FocusableOption, AfterViewInit, OnDestroy {
|
export class TabLinkComponent implements FocusableOption, AfterViewInit {
|
||||||
private destroy$ = new Subject<void>();
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
@ViewChild(TabListItemDirective) tabItem: TabListItemDirective;
|
@ViewChild(TabListItemDirective) tabItem: TabListItemDirective;
|
||||||
@ViewChild("rla") routerLinkActive: RouterLinkActive;
|
@ViewChild("rla") routerLinkActive: RouterLinkActive;
|
||||||
|
|
||||||
@@ -61,12 +61,7 @@ export class TabLinkComponent implements FocusableOption, AfterViewInit, OnDestr
|
|||||||
// The active state of tab links are tracked via the routerLinkActive directive
|
// The active state of tab links are tracked via the routerLinkActive directive
|
||||||
// We need to watch for changes to tell the parent nav group when the tab is active
|
// We need to watch for changes to tell the parent nav group when the tab is active
|
||||||
this.routerLinkActive.isActiveChange
|
this.routerLinkActive.isActiveChange
|
||||||
.pipe(takeUntil(this.destroy$))
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
.subscribe((_) => this._tabNavBar.updateActiveLink());
|
.subscribe((_) => this._tabNavBar.updateActiveLink());
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.destroy$.next();
|
|
||||||
this.destroy$.complete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user