From e646718fbe60a372893b94e88c9e142dd5a3fb60 Mon Sep 17 00:00:00 2001 From: muhammedaltug Date: Thu, 24 Dec 2020 11:03:37 +0300 Subject: [PATCH] - add wait services - remove ngxs from api interceptor and loader-bar component - remove filter input from loader bar component --- .../src/lib/interceptors/api.interceptor.ts | 10 ++-- .../src/lib/services/http-wait.service.ts | 44 +++++++++++++++ .../packages/core/src/lib/services/index.ts | 2 + .../src/lib/services/lazy-load.service.ts | 10 +++- .../src/lib/services/resource-wait.service.ts | 41 ++++++++++++++ .../src/lib/services/router-wait.service.ts | 53 +++++++++++++++++++ .../loader-bar/loader-bar.component.ts | 51 ++++++------------ 7 files changed, 168 insertions(+), 43 deletions(-) create mode 100644 npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts create mode 100644 npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts create mode 100644 npm/ng-packs/packages/core/src/lib/services/router-wait.service.ts diff --git a/npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts b/npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts index a2b08c07db..ad60178a98 100644 --- a/npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts +++ b/npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts @@ -1,10 +1,9 @@ import { HttpHandler, HttpHeaders, HttpInterceptor, HttpRequest } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { Store } from '@ngxs/store'; import { OAuthService } from 'angular-oauth2-oidc'; import { finalize } from 'rxjs/operators'; -import { StartLoader, StopLoader } from '../actions/loader.actions'; import { SessionStateService } from '../services/session-state.service'; +import { HttpWaitService } from '../services/http-wait.service'; @Injectable({ providedIn: 'root', @@ -12,20 +11,19 @@ import { SessionStateService } from '../services/session-state.service'; export class ApiInterceptor implements HttpInterceptor { constructor( private oAuthService: OAuthService, - private store: Store, private sessionState: SessionStateService, + private httpWaitService: HttpWaitService, ) {} intercept(request: HttpRequest, next: HttpHandler) { - this.store.dispatch(new StartLoader(request)); - + this.httpWaitService.addRequest(request); return next .handle( request.clone({ setHeaders: this.getAdditionalHeaders(request.headers), }), ) - .pipe(finalize(() => this.store.dispatch(new StopLoader(request)))); + .pipe(finalize(() => this.httpWaitService.deleteRequest(request))); } getAdditionalHeaders(existingHeaders?: HttpHeaders) { diff --git a/npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts b/npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts new file mode 100644 index 0000000000..96427594ae --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts @@ -0,0 +1,44 @@ +import { Injectable } from '@angular/core'; +import { HttpRequest } from '@angular/common/http'; +import { InternalStore } from '../utils/internal-store-utils'; + +export interface HttpWaitState { + requests: Set>; +} + +@Injectable({ + providedIn: 'root', +}) +export class HttpWaitService { + protected store = new InternalStore({ requests: new Set() }); + + getLoading() { + return !!this.store.state.requests.size; + } + + getLoading$() { + return this.store.sliceState(({ requests }) => !!requests.size); + } + + updateLoading$() { + return this.store.sliceUpdate(({ requests }) => !!requests.size); + } + + clearLoading() { + this.store.patch({ requests: new Set() }); + } + + addRequest(request: HttpRequest) { + const requests = this.store.state.requests; + requests.add(request); + this.store.patch({ requests }); + } + + deleteRequest(request: HttpRequest) { + const requests = this.store.state.requests; + requests.delete(request); + this.store.patch({ requests }); + } + + // TODO: Add filter function +} diff --git a/npm/ng-packs/packages/core/src/lib/services/index.ts b/npm/ng-packs/packages/core/src/lib/services/index.ts index 5b294c4905..47b146ea9f 100644 --- a/npm/ng-packs/packages/core/src/lib/services/index.ts +++ b/npm/ng-packs/packages/core/src/lib/services/index.ts @@ -4,6 +4,7 @@ export * from './config-state.service'; export * from './content-projection.service'; export * from './dom-insertion.service'; export * from './environment.service'; +export * from './http-wait.service'; export * from './lazy-load.service'; export * from './list.service'; export * from './localization.service'; @@ -13,6 +14,7 @@ export * from './profile-state.service'; export * from './profile.service'; export * from './replaceable-components.service'; export * from './rest.service'; +export * from './router-wait.service'; export * from './routes.service'; export * from './session-state.service'; export * from './subscription.service'; diff --git a/npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts b/npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts index 5d44bb0879..0aca94c94a 100644 --- a/npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import { concat, Observable, of, throwError } from 'rxjs'; import { delay, retryWhen, shareReplay, take, tap } from 'rxjs/operators'; import { LoadingStrategy } from '../strategies'; +import { ResourceWaitService } from './resource-wait.service'; @Injectable({ providedIn: 'root', @@ -9,9 +10,11 @@ import { LoadingStrategy } from '../strategies'; export class LazyLoadService { readonly loaded = new Map(); + constructor(private resourceWaitService: ResourceWaitService) {} + load(strategy: LoadingStrategy, retryTimes?: number, retryDelay?: number): Observable { if (this.loaded.has(strategy.path)) return of(new CustomEvent('load')); - + this.resourceWaitService.addResource(strategy.path); return strategy.createStream().pipe( retryWhen(error$ => concat( @@ -19,7 +22,10 @@ export class LazyLoadService { throwError(new CustomEvent('error')), ), ), - tap(() => this.loaded.set(strategy.path, strategy.element)), + tap(() => { + this.loaded.set(strategy.path, strategy.element); + this.resourceWaitService.deleteResource(strategy.path); + }), delay(100), shareReplay({ bufferSize: 1, refCount: true }), ); diff --git a/npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts b/npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts new file mode 100644 index 0000000000..16351837a2 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@angular/core'; +import { InternalStore } from '../utils/internal-store-utils'; + +export interface ResourceWaitState { + resources: Set; +} + +@Injectable({ + providedIn: 'root', +}) +export class ResourceWaitService { + private store = new InternalStore({ resources: new Set() }); + + getLoading() { + return !!this.store.state.resources.size; + } + + getLoading$() { + return this.store.sliceState(({ resources }) => !!resources.size); + } + + updateLoading$() { + return this.store.sliceUpdate(({ resources }) => !!resources.size); + } + + clearLoading() { + this.store.patch({ resources: new Set() }); + } + + addResource(resource: string) { + const resources = this.store.state.resources; + resources.add(resource); + this.store.patch({ resources }); + } + + deleteResource(resource: string) { + const resources = this.store.state.resources; + resources.delete(resource); + this.store.patch({ resources }); + } +} diff --git a/npm/ng-packs/packages/core/src/lib/services/router-wait.service.ts b/npm/ng-packs/packages/core/src/lib/services/router-wait.service.ts new file mode 100644 index 0000000000..d1306e63c9 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/services/router-wait.service.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@angular/core'; +import { + NavigationCancel, + NavigationEnd, + NavigationError, + NavigationStart, + Router, +} from '@angular/router'; +import { filter } from 'rxjs/operators'; +import { InternalStore } from '../utils/internal-store-utils'; + +export interface RouterWaitState { + loading: boolean; +} + +@Injectable({ + providedIn: 'root', +}) +export class RouterWaitService { + private store = new InternalStore({ loading: false }); + constructor(private router: Router) { + this.router.events + .pipe( + filter( + event => + event instanceof NavigationStart || + event instanceof NavigationEnd || + event instanceof NavigationError || + event instanceof NavigationCancel, + ), + ) + .subscribe(event => { + if (event instanceof NavigationStart) this.setLoading(true); + else this.setLoading(false); + }); + } + + getLoading() { + return this.store.state.loading; + } + + getLoading$() { + return this.store.sliceState(({ loading }) => loading); + } + + updateLoading$() { + return this.store.sliceUpdate(({ loading }) => loading); + } + + setLoading(loading: boolean) { + this.store.patch({ loading }); + } +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts index f94b6b3656..729a844440 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts @@ -1,9 +1,9 @@ -import { StartLoader, StopLoader, SubscriptionService } from '@abp/ng.core'; +import { SubscriptionService } from '@abp/ng.core'; import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router'; -import { Actions, ofActionSuccessful } from '@ngxs/store'; -import { Subscription, timer } from 'rxjs'; -import { filter } from 'rxjs/operators'; +import { Router } from '@angular/router'; +import { combineLatest, Subscription, timer } from 'rxjs'; +import { RouterWaitService } from '../../../../../core/src/lib/services/router-wait.service'; +import { HttpWaitService } from '../../../../../core/src/lib/services/http-wait.service'; @Component({ selector: 'abp-loader-bar', @@ -51,10 +51,6 @@ export class LoaderBarComponent implements OnDestroy, OnInit { stopDelay = 800; - @Input() - filter = (action: StartLoader | StopLoader) => - action.payload.url.indexOf('openid-configuration') < 0; - private readonly clearProgress = () => { this.progressLevel = 0; this.cdRef.detectChanges(); @@ -78,44 +74,27 @@ export class LoaderBarComponent implements OnDestroy, OnInit { } constructor( - private actions: Actions, private router: Router, private cdRef: ChangeDetectorRef, private subscription: SubscriptionService, + private httpWaitService: HttpWaitService, + private routerWaiterService: RouterWaitService, ) {} - private subscribeToLoadActions() { - this.subscription.addOne( - this.actions.pipe(ofActionSuccessful(StartLoader, StopLoader), filter(this.filter)), - action => { - if (action instanceof StartLoader) this.startLoading(); - else this.stopLoading(); - }, - ); + ngOnInit() { + this.subscribeLoading(); } - private subscribeToRouterEvents() { + subscribeLoading() { this.subscription.addOne( - this.router.events.pipe( - filter( - event => - event instanceof NavigationStart || - event instanceof NavigationEnd || - event instanceof NavigationError, - ), - ), - event => { - if (event instanceof NavigationStart) this.startLoading(); + combineLatest([this.httpWaitService.getLoading$(), this.routerWaiterService.getLoading$()]), + ([httpLoading, routerLoading]) => { + if (httpLoading || routerLoading) this.startLoading(); else this.stopLoading(); }, ); } - ngOnInit() { - this.subscribeToLoadActions(); - this.subscribeToRouterEvents(); - } - ngOnDestroy() { if (this.interval) this.interval.unsubscribe(); } @@ -124,8 +103,10 @@ export class LoaderBarComponent implements OnDestroy, OnInit { if (this.isLoading || (this.interval && !this.interval.closed)) return; this.isLoading = true; - + this.progressLevel = 0; this.interval = timer(0, this.intervalPeriod).subscribe(this.reportProgress); + this.timer.unsubscribe(); + this.cdRef.detectChanges(); } stopLoading() {