From a8ebcdb5e7a16832de9a4dcaf40947d02d98bfe8 Mon Sep 17 00:00:00 2001 From: Bastian Jakobi Date: Fri, 19 Apr 2024 17:09:17 +0200 Subject: [PATCH 1/5] refactor: improve remote component loading and add first skeleton loaders --- .../lib/components/slot/slot.component.html | 4 +- .../src/lib/components/slot/slot.component.ts | 44 ++++++++++++------- .../src/lib/services/slot.service.ts | 10 +++-- .../portal-header/header.component.html | 23 ++++++---- libs/shell-core/src/lib/shell-core.module.ts | 5 ++- 5 files changed, 56 insertions(+), 30 deletions(-) diff --git a/libs/angular-remote-components/src/lib/components/slot/slot.component.html b/libs/angular-remote-components/src/lib/components/slot/slot.component.html index 85229487..7b3cab3c 100644 --- a/libs/angular-remote-components/src/lib/components/slot/slot.component.html +++ b/libs/angular-remote-components/src/lib/components/slot/slot.component.html @@ -1 +1,3 @@ -
\ No newline at end of file +
+ +
\ No newline at end of file diff --git a/libs/angular-remote-components/src/lib/components/slot/slot.component.ts b/libs/angular-remote-components/src/lib/components/slot/slot.component.ts index 863e78d1..0f1a2459 100644 --- a/libs/angular-remote-components/src/lib/components/slot/slot.component.ts +++ b/libs/angular-remote-components/src/lib/components/slot/slot.component.ts @@ -10,7 +10,7 @@ import { ViewContainerRef, } from '@angular/core' import { BehaviorSubject, Subscription, Observable, combineLatest } from 'rxjs' -import { RemoteComponentInfo, SLOT_SERVICE, SlotService } from '../../services/slot.service' +import { RemoteComponentInfo, SLOT_SERVICE, SlotComponentConfiguration, SlotService } from '../../services/slot.service' import { ocxRemoteComponent } from '../../model/remote-component' @Component({ @@ -28,11 +28,8 @@ export class SlotComponent implements OnInit, OnDestroy { } subscription: Subscription | undefined - components$: - | Observable< - { componentType: Type | undefined; remoteComponent: RemoteComponentInfo; permissions: string[] }[] - > - | undefined + components$: Observable | undefined + loading = true constructor(@Inject(SLOT_SERVICE) private slotService: SlotService) {} @@ -43,16 +40,9 @@ export class SlotComponent implements OnInit, OnDestroy { if (viewContainers && viewContainers.length === components.length) { components.forEach((componentInfo, i) => { if (componentInfo.componentType) { - const componentRef = viewContainers.get(i)?.createComponent(componentInfo.componentType) - if (componentRef && 'ocxInitRemoteComponent' in componentRef.instance) { - ;(componentRef.instance as ocxRemoteComponent).ocxInitRemoteComponent({ - appId: componentInfo.remoteComponent.appId, - productName: componentInfo.remoteComponent.productName, - baseUrl: componentInfo.remoteComponent.baseUrl, - permissions: componentInfo.permissions, - }) - } - componentRef?.changeDetectorRef.detectChanges() + Promise.all([Promise.resolve(componentInfo.componentType), Promise.resolve(componentInfo.permissions)]).then(([componentType, permissions]) => { + this.createComponent(componentType, componentInfo, permissions, viewContainers, i) + }) } }) } @@ -60,6 +50,28 @@ export class SlotComponent implements OnInit, OnDestroy { ) } + private createComponent( + componentType: Type | undefined, + componentInfo: { remoteComponent: RemoteComponentInfo; }, + permissions: string[], + viewContainers: QueryList, + i: number + ) { + this.loading = false + if (componentType) { + const componentRef = viewContainers.get(i)?.createComponent(componentType) + if (componentRef && 'ocxInitRemoteComponent' in componentRef.instance) { + ;(componentRef.instance as ocxRemoteComponent).ocxInitRemoteComponent({ + appId: componentInfo.remoteComponent.appId, + productName: componentInfo.remoteComponent.productName, + baseUrl: componentInfo.remoteComponent.baseUrl, + permissions: permissions, + }) + } + componentRef?.changeDetectorRef.detectChanges() + } + } + ngOnDestroy(): void { this.subscription?.unsubscribe() } diff --git a/libs/angular-remote-components/src/lib/services/slot.service.ts b/libs/angular-remote-components/src/lib/services/slot.service.ts index 5f4cd32d..c753556f 100644 --- a/libs/angular-remote-components/src/lib/services/slot.service.ts +++ b/libs/angular-remote-components/src/lib/services/slot.service.ts @@ -5,11 +5,15 @@ export const SLOT_SERVICE: InjectionToken = new InjectionToken('SLO export type RemoteComponentInfo = { appId: string; productName: string; baseUrl: string } +export type SlotComponentConfiguration = { + componentType: Promise | undefined> | Type | undefined; + remoteComponent: RemoteComponentInfo; + permissions: Promise | string[]; +} + export interface SlotService { init(): Promise getComponentsForSlot( slotName: string - ): Observable< - { componentType: Type | undefined; remoteComponent: RemoteComponentInfo; permissions: string[] }[] - > + ): Observable } diff --git a/libs/shell-core/src/lib/components/portal-header/header.component.html b/libs/shell-core/src/lib/components/portal-header/header.component.html index 90aa15d4..af82d901 100644 --- a/libs/shell-core/src/lib/components/portal-header/header.component.html +++ b/libs/shell-core/src/lib/components/portal-header/header.component.html @@ -34,7 +34,12 @@ - + @@ -44,17 +49,19 @@
- + +
+ + + +
+
    - - - + -
  • - -
  • +
diff --git a/libs/shell-core/src/lib/shell-core.module.ts b/libs/shell-core/src/lib/shell-core.module.ts index 337713d0..40188d20 100644 --- a/libs/shell-core/src/lib/shell-core.module.ts +++ b/libs/shell-core/src/lib/shell-core.module.ts @@ -8,10 +8,11 @@ import { GlobalErrorComponent } from './components/error-component/global-error. import { PortalFooterComponent } from './components/portal-footer/portal-footer.component' import { HeaderComponent } from './components/portal-header/header.component' import { PortalViewportComponent } from './components/portal-viewport/portal-viewport.component' +import { SkeletonModule } from 'primeng/skeleton' @NgModule({ - imports: [CommonModule, RouterModule, AngularRemoteComponentsModule, AngularAcceleratorModule, ToastModule], + imports: [CommonModule, RouterModule, AngularRemoteComponentsModule, AngularAcceleratorModule, ToastModule, SkeletonModule], declarations: [PortalViewportComponent, HeaderComponent, PortalFooterComponent, GlobalErrorComponent], - exports: [PortalViewportComponent, HeaderComponent, PortalFooterComponent, ToastModule, GlobalErrorComponent], + exports: [PortalViewportComponent, HeaderComponent, PortalFooterComponent, ToastModule, GlobalErrorComponent, SkeletonModule], }) export class ShellCoreModule {} From daa1db67b1921272a47b9640218110ebd8a544f7 Mon Sep 17 00:00:00 2001 From: Bastian Jakobi Date: Fri, 19 Apr 2024 17:14:20 +0200 Subject: [PATCH 2/5] refactor: remove unnecessary export --- libs/shell-core/src/lib/shell-core.module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/shell-core/src/lib/shell-core.module.ts b/libs/shell-core/src/lib/shell-core.module.ts index 40188d20..ffec2656 100644 --- a/libs/shell-core/src/lib/shell-core.module.ts +++ b/libs/shell-core/src/lib/shell-core.module.ts @@ -13,6 +13,6 @@ import { SkeletonModule } from 'primeng/skeleton' @NgModule({ imports: [CommonModule, RouterModule, AngularRemoteComponentsModule, AngularAcceleratorModule, ToastModule, SkeletonModule], declarations: [PortalViewportComponent, HeaderComponent, PortalFooterComponent, GlobalErrorComponent], - exports: [PortalViewportComponent, HeaderComponent, PortalFooterComponent, ToastModule, GlobalErrorComponent, SkeletonModule], + exports: [PortalViewportComponent, HeaderComponent, PortalFooterComponent, ToastModule, GlobalErrorComponent], }) export class ShellCoreModule {} From 3f7d0111bcc582f67d48ba093142a94d5bb976a5 Mon Sep 17 00:00:00 2001 From: Bastian Jakobi Date: Tue, 23 Apr 2024 12:43:09 +0200 Subject: [PATCH 3/5] fix: fix remote component loading + add workspace name property to currentWorkspace/currentPortal --- .../src/lib/components/slot/slot.component.html | 2 +- .../src/lib/components/slot/slot.component.ts | 11 ++++++++--- .../topics/current-workspace/v1/workspace.model.ts | 1 + .../lib/core/initializer/standalone.initializer.ts | 5 ++++- .../components/portal-header/header.component.html | 8 +++++--- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/libs/angular-remote-components/src/lib/components/slot/slot.component.html b/libs/angular-remote-components/src/lib/components/slot/slot.component.html index 7b3cab3c..c974cbb3 100644 --- a/libs/angular-remote-components/src/lib/components/slot/slot.component.html +++ b/libs/angular-remote-components/src/lib/components/slot/slot.component.html @@ -1,3 +1,3 @@
- +
\ No newline at end of file diff --git a/libs/angular-remote-components/src/lib/components/slot/slot.component.ts b/libs/angular-remote-components/src/lib/components/slot/slot.component.ts index 0f1a2459..dd94ea0f 100644 --- a/libs/angular-remote-components/src/lib/components/slot/slot.component.ts +++ b/libs/angular-remote-components/src/lib/components/slot/slot.component.ts @@ -1,10 +1,12 @@ import { Component, + ContentChild, Inject, Input, OnDestroy, OnInit, QueryList, + TemplateRef, Type, ViewChildren, ViewContainerRef, @@ -27,9 +29,10 @@ export class SlotComponent implements OnInit, OnDestroy { this._viewContainers$.next(value) } + @ContentChild('skeleton') skeleton: TemplateRef | undefined + subscription: Subscription | undefined components$: Observable | undefined - loading = true constructor(@Inject(SLOT_SERVICE) private slotService: SlotService) {} @@ -57,9 +60,11 @@ export class SlotComponent implements OnInit, OnDestroy { viewContainers: QueryList, i: number ) { - this.loading = false + const viewContainer = viewContainers.get(i); + viewContainer?.clear() + viewContainer?.element.nativeElement.replaceChildren() if (componentType) { - const componentRef = viewContainers.get(i)?.createComponent(componentType) + const componentRef = viewContainer?.createComponent(componentType) if (componentRef && 'ocxInitRemoteComponent' in componentRef.instance) { ;(componentRef.instance as ocxRemoteComponent).ocxInitRemoteComponent({ appId: componentInfo.remoteComponent.appId, diff --git a/libs/integration-interface/src/lib/topics/current-workspace/v1/workspace.model.ts b/libs/integration-interface/src/lib/topics/current-workspace/v1/workspace.model.ts index ee0c277b..60ee78ac 100644 --- a/libs/integration-interface/src/lib/topics/current-workspace/v1/workspace.model.ts +++ b/libs/integration-interface/src/lib/topics/current-workspace/v1/workspace.model.ts @@ -6,6 +6,7 @@ export interface Workspace { * @deprecated will be renamed to workspaceName */ portalName: string + workspaceName: string /** * @deprecated will be removed */ diff --git a/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts b/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts index 7c929611..5fe774fd 100644 --- a/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts +++ b/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts @@ -64,7 +64,10 @@ export function standaloneInitializer( throw e } console.log(`📃 portal OK? `, portal) - await appStateService.currentPortal$.publish(portal) + await appStateService.currentPortal$.publish({ + ...portal, + workspaceName: portal.portalName + }) const standaloneMfeInfo: MfeInfo = { mountPath: '/', diff --git a/libs/shell-core/src/lib/components/portal-header/header.component.html b/libs/shell-core/src/lib/components/portal-header/header.component.html index af82d901..5f77e90d 100644 --- a/libs/shell-core/src/lib/components/portal-header/header.component.html +++ b/libs/shell-core/src/lib/components/portal-header/header.component.html @@ -51,9 +51,11 @@
- - - + +
+ +
+
    From 65b5b2cac983882748807a64bb6f31e84383e0fd Mon Sep 17 00:00:00 2001 From: Bastian Jakobi Date: Tue, 23 Apr 2024 12:47:47 +0200 Subject: [PATCH 4/5] fix: fix mock --- .../mocks/app-state-service-mock.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/angular-integration-interface/mocks/app-state-service-mock.ts b/libs/angular-integration-interface/mocks/app-state-service-mock.ts index 367ea2e9..2d1ecfb2 100644 --- a/libs/angular-integration-interface/mocks/app-state-service-mock.ts +++ b/libs/angular-integration-interface/mocks/app-state-service-mock.ts @@ -21,6 +21,7 @@ export class AppStateServiceMock { globalLoading$ = new FakeTopic(false) currentMfe$ = new FakeTopic({ mountPath: '/', remoteBaseUrl: '.', baseHref: '/', shellName: 'test' }) currentPage$ = new FakeTopic(undefined) - currentPortal$ = new FakeTopic({ baseUrl: '/', microfrontendRegistrations: [], portalName: 'Test portal' }) + currentPortal$ = new FakeTopic({ baseUrl: '/', microfrontendRegistrations: [], portalName: 'Test portal', workspaceName: 'Test portal' }) + currentWorkspace$ = new FakeTopic({ baseUrl: '/', microfrontendRegistrations: [], portalName: 'Test workspace', workspaceName: 'Test workspace' }) isAuthenticated$ = new FakeTopic(null) } From 86610ea367fe8323f43d381c7a12dae29111b718 Mon Sep 17 00:00:00 2001 From: Bastian Jakobi Date: Tue, 23 Apr 2024 12:56:22 +0200 Subject: [PATCH 5/5] fix: fix test mocks to match latest workspace model --- .../src/lib/components/page-header/page-header.component.spec.ts | 1 + .../lib/components/search-header/search-header.component.spec.ts | 1 + .../announcement-banner/announcement-banner.component.spec.ts | 1 + .../components/portal-footer/portal-footer.component.spec.ts | 1 + .../components/portal-viewport/portal-viewport.component.spec.ts | 1 + .../components/search-criteria/search-criteria.component.spec.ts | 1 + 6 files changed, 6 insertions(+) diff --git a/libs/angular-accelerator/src/lib/components/page-header/page-header.component.spec.ts b/libs/angular-accelerator/src/lib/components/page-header/page-header.component.spec.ts index f1498edc..8abc869e 100644 --- a/libs/angular-accelerator/src/lib/components/page-header/page-header.component.spec.ts +++ b/libs/angular-accelerator/src/lib/components/page-header/page-header.component.spec.ts @@ -92,6 +92,7 @@ describe('PageHeaderComponent', () => { await appStateService.currentPortal$.publish({ id: 'i-am-test-portal', portalName: 'test', + workspaceName: 'test', baseUrl: '', microfrontendRegistrations: [], }) diff --git a/libs/angular-accelerator/src/lib/components/search-header/search-header.component.spec.ts b/libs/angular-accelerator/src/lib/components/search-header/search-header.component.spec.ts index 646b8291..555a5847 100644 --- a/libs/angular-accelerator/src/lib/components/search-header/search-header.component.spec.ts +++ b/libs/angular-accelerator/src/lib/components/search-header/search-header.component.spec.ts @@ -53,6 +53,7 @@ describe('SearchHeaderComponent', () => { await appStateService.currentPortal$.publish({ id: 'i-am-test-portal', portalName: 'test', + workspaceName: 'test', baseUrl: '', microfrontendRegistrations: [], }) diff --git a/libs/portal-integration-angular/src/lib/core/components/announcement-banner/announcement-banner.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/announcement-banner/announcement-banner.component.spec.ts index c9f2d390..b3da205e 100644 --- a/libs/portal-integration-angular/src/lib/core/components/announcement-banner/announcement-banner.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/announcement-banner/announcement-banner.component.spec.ts @@ -48,6 +48,7 @@ describe('AnnouncementBannerComponent', () => { await appStateService.currentPortal$.publish({ id: 'i-am-test-portal', portalName: 'test', + workspaceName: 'test', baseUrl: '', microfrontendRegistrations: [], }) diff --git a/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.spec.ts index d31e20ce..02e74100 100644 --- a/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.spec.ts @@ -40,6 +40,7 @@ describe('PortalFooterComponent', () => { await appStateService.currentPortal$.publish({ id: 'i-am-test-portal', portalName: 'test', + workspaceName: 'test', baseUrl: '', microfrontendRegistrations: [], }) diff --git a/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts index 00e69813..6cade19d 100644 --- a/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts @@ -98,6 +98,7 @@ describe('PortalViewportComponent', () => { await appStateService.currentPortal$.publish({ id: 'i-am-test-portal', portalName: 'test', + workspaceName: 'test', baseUrl: '', microfrontendRegistrations: [], }) diff --git a/libs/portal-integration-angular/src/lib/core/components/search-criteria/search-criteria.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/search-criteria/search-criteria.component.spec.ts index 9210c847..b46411b4 100644 --- a/libs/portal-integration-angular/src/lib/core/components/search-criteria/search-criteria.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/search-criteria/search-criteria.component.spec.ts @@ -55,6 +55,7 @@ describe('SearchCriteriaComponent', () => { await appStateService.currentPortal$.publish({ id: 'i-am-test-portal', portalName: 'test', + workspaceName: 'test', baseUrl: '', microfrontendRegistrations: [], })