From 5034351dd39502faeac1c7a0d8910b8b0652cbc8 Mon Sep 17 00:00:00 2001 From: why520crazy Date: Sat, 16 Mar 2024 09:24:33 +0800 Subject: [PATCH] feat: add loading signal for planet --- examples/portal/src/app/app.component.html | 7 ++- examples/portal/src/app/app.component.ts | 4 +- .../planet-application-loader.spec.ts | 3 + .../application/planet-application-loader.ts | 55 +++++++------------ packages/planet/src/planet.ts | 13 +++-- 5 files changed, 37 insertions(+), 45 deletions(-) diff --git a/examples/portal/src/app/app.component.html b/examples/portal/src/app/app.component.html index 25cb271..2736465 100644 --- a/examples/portal/src/app/app.component.html +++ b/examples/portal/src/app/app.component.html @@ -39,11 +39,12 @@ -
+
- - + @if (loading(); as loadingState) { + + } diff --git a/examples/portal/src/app/app.component.ts b/examples/portal/src/app/app.component.ts index 743c362..533028b 100644 --- a/examples/portal/src/app/app.component.ts +++ b/examples/portal/src/app/app.component.ts @@ -19,8 +19,8 @@ export class AppComponent implements OnInit { activeAppNames: string[] = []; - get loadingDone() { - return this.planet.loadingDone; + get loading() { + return this.planet.loading; } constructor( diff --git a/packages/planet/src/application/planet-application-loader.spec.ts b/packages/planet/src/application/planet-application-loader.spec.ts index 2c6d6dc..e2c1ba5 100644 --- a/packages/planet/src/application/planet-application-loader.spec.ts +++ b/packages/planet/src/application/planet-application-loader.spec.ts @@ -87,8 +87,11 @@ class AppStatusChangeFaker { expect(this.spy).toHaveBeenCalledTimes(fromCalledTimes + 1); expect(this.spy).toHaveBeenCalledWith({ app: expectedApp, status: ApplicationStatus.bootstrapping }); expect(this.planetApplicationLoader.loadingDone).toBe(false); + expect(this.planetApplicationLoader.loading()).toBe(true); appRefFaker.bootstrap(); expect(this.planetApplicationLoader.loadingDone).toBe(true); + expect(this.planetApplicationLoader.loading()).toBe(false); + expect(this.spy).toHaveBeenCalledTimes(fromCalledTimes + 3); expect(this.spy).toHaveBeenCalledWith({ app: expectedApp, status: ApplicationStatus.bootstrapped }); diff --git a/packages/planet/src/application/planet-application-loader.ts b/packages/planet/src/application/planet-application-loader.ts index df4322f..aa557f7 100644 --- a/packages/planet/src/application/planet-application-loader.ts +++ b/packages/planet/src/application/planet-application-loader.ts @@ -1,4 +1,4 @@ -import { Injectable, NgZone, ApplicationRef, Injector } from '@angular/core'; +import { Injectable, NgZone, ApplicationRef, Injector, computed, signal } from '@angular/core'; import { of, Observable, Subject, forkJoin, from, throwError } from 'rxjs'; import { AssetsLoader } from '../assets-loader'; import { PlanetApplication, PlanetRouterEvent, SwitchModes, PlanetOptions } from '../planet.class'; @@ -54,6 +54,8 @@ export class PlanetApplicationLoader { private appsLoadingStart$ = new Subject(); + private innerLoading = signal(false); + public get appStatusChange(): Observable { return this.appStatusChange$.asObservable(); } @@ -62,8 +64,13 @@ export class PlanetApplicationLoader { return this.appsLoadingStart$.asObservable(); } + /** + * @deprecated please use loading signal + */ public loadingDone = false; + public loading = this.innerLoading.asReadonly(); + constructor( private assetsLoader: AssetsLoader, private planetApplicationService: PlanetApplicationService, @@ -73,9 +80,7 @@ export class PlanetApplicationLoader { applicationRef: ApplicationRef ) { if (getApplicationLoader()) { - throw new Error( - 'PlanetApplicationLoader has been injected in the portal, repeated injection is not allowed' - ); + throw new Error('PlanetApplicationLoader has been injected in the portal, repeated injection is not allowed'); } this.options = { @@ -97,9 +102,7 @@ export class PlanetApplicationLoader { this.ngZone.run(() => { const fromStatus = this.appsStatus.get(app); debug( - `app(${app.name}) status change: ${fromStatus ? ApplicationStatus[fromStatus] : 'empty'} => ${ - ApplicationStatus[status] - }` + `app(${app.name}) status change: ${fromStatus ? ApplicationStatus[fromStatus] : 'empty'} => ${ApplicationStatus[status]}` ); this.appsStatus.set(app, status); this.appStatusChange$.next({ @@ -109,10 +112,7 @@ export class PlanetApplicationLoader { }); } - private getAppStatusChange$( - app: PlanetApplication, - status = ApplicationStatus.bootstrapped - ): Observable { + private getAppStatusChange$(app: PlanetApplication, status = ApplicationStatus.bootstrapped): Observable { return this.appStatusChange.pipe( filter(event => { return event.app === app && event.status === status; @@ -140,6 +140,7 @@ export class PlanetApplicationLoader { private setLoadingDone() { this.ngZone.run(() => { this.loadingDone = true; + this.innerLoading.set(false); }); } @@ -188,9 +189,7 @@ export class PlanetApplicationLoader { appStatus === ApplicationStatus.loadError ) { debug( - `app(${app.name}) status is ${ - ApplicationStatus[appStatus as ApplicationStatus] - }, start load assets` + `app(${app.name}) status is ${ApplicationStatus[appStatus as ApplicationStatus]}, start load assets` ); hasAppsNeedLoadingAssets = true; return this.ngZone.runOutsideAngular(() => { @@ -202,6 +201,7 @@ export class PlanetApplicationLoader { }); if (hasAppsNeedLoadingAssets) { this.loadingDone = false; + this.innerLoading.set(true); } return loadApps$.length > 0 ? forkJoin(loadApps$) : of([] as PlanetApplication[]); }), @@ -212,9 +212,7 @@ export class PlanetApplicationLoader { switchMap(app => { const appStatus = this.appsStatus.get(app); if (appStatus === ApplicationStatus.bootstrapped) { - debug( - `[routeChange] app(${app.name}) status is bootstrapped, show app and active` - ); + debug(`[routeChange] app(${app.name}) status is bootstrapped, show app and active`); this.showApp(app); const appRef = getPlanetApplicationRef(app.name); appRef?.navigateByUrl(event.url); @@ -222,9 +220,7 @@ export class PlanetApplicationLoader { this.setLoadingDone(); return of(app); } else if (appStatus === ApplicationStatus.assetsLoaded) { - debug( - `[routeChange] app(${app.name}) status is assetsLoaded, start bootstrapping` - ); + debug(`[routeChange] app(${app.name}) status is assetsLoaded, start bootstrapping`); return this.bootstrapApp(app).pipe( map(() => { debug(`app(${app.name}) bootstrapped success, active it`); @@ -237,9 +233,7 @@ export class PlanetApplicationLoader { debug(`[routeChange] app(${app.name}) is active, do nothings`); const appRef = getPlanetApplicationRef(app.name); // Backwards compatibility sub app use old version which has not getCurrentRouterStateUrl - const currentUrl = appRef?.getCurrentRouterStateUrl - ? appRef.getCurrentRouterStateUrl() - : ''; + const currentUrl = appRef?.getCurrentRouterStateUrl ? appRef.getCurrentRouterStateUrl() : ''; if (currentUrl !== event.url) { appRef?.navigateByUrl(event.url); } @@ -253,9 +247,7 @@ export class PlanetApplicationLoader { return this.getAppStatusChange$(app).pipe( take(1), map(() => { - debug( - `app(${app.name}) status is bootstrapped by subscribe status change, active it` - ); + debug(`app(${app.name}) status is bootstrapped by subscribe status change, active it`); this.setAppStatus(app, ApplicationStatus.active); this.showApp(app); return app; @@ -355,10 +347,7 @@ export class PlanetApplicationLoader { } } - private bootstrapApp( - app: PlanetApplication, - defaultStatus: 'hidden' | 'display' = 'display' - ): Observable { + private bootstrapApp(app: PlanetApplication, defaultStatus: 'hidden' | 'display' = 'display'): Observable { debug(`app(${app.name}) start bootstrapping`); this.setAppStatus(app, ApplicationStatus.bootstrapping); const appRef = getPlanetApplicationRef(app.name); @@ -517,11 +506,7 @@ export class PlanetApplicationLoader { return getPlanetApplicationRef(app.name); }) ); - } else if ( - [ApplicationStatus.assetsLoading, ApplicationStatus.assetsLoaded, ApplicationStatus.bootstrapping].includes( - status - ) - ) { + } else if ([ApplicationStatus.assetsLoading, ApplicationStatus.assetsLoaded, ApplicationStatus.bootstrapping].includes(status)) { debug(`preload app(${app.name}), status is ${ApplicationStatus[status]}, return until bootstrapped`); return this.getAppStatusChange$(app).pipe( take(1), diff --git a/packages/planet/src/planet.ts b/packages/planet/src/planet.ts index f38c946..8f32f20 100644 --- a/packages/planet/src/planet.ts +++ b/packages/planet/src/planet.ts @@ -2,11 +2,7 @@ import { Injectable, Inject, Optional, Injector } from '@angular/core'; import { NavigationEnd, RouterEvent, Router } from '@angular/router'; import { PlanetOptions, PlanetApplication, PLANET_APPLICATIONS } from './planet.class'; import { PlanetApplicationService } from './application/planet-application.service'; -import { - PlanetApplicationLoader, - AppsLoadingStartEvent, - AppStatusChangeEvent -} from './application/planet-application-loader'; +import { PlanetApplicationLoader, AppsLoadingStartEvent, AppStatusChangeEvent } from './application/planet-application-loader'; import { Observable, Subscription } from 'rxjs'; import { filter, startWith, distinctUntilChanged, map } from 'rxjs/operators'; import { @@ -30,10 +26,17 @@ export class Planet { return getApplicationService(); } + /** + * @deprecated please use loading signal + */ public get loadingDone() { return this.planetApplicationLoader.loadingDone; } + public get loading() { + return this.planetApplicationLoader.loading; + } + public get appStatusChange(): Observable { return this.planetApplicationLoader.appStatusChange; }