Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve remote component loading + add first skeleton loaders #226

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
<div *ngFor="let component of (components$ | async)" #slot></div>
<div *ngFor="let component of (components$ | async);" #slot>
<ng-content *ngIf="loading"></ng-content>
SchettlerKoehler marked this conversation as resolved.
Show resolved Hide resolved
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -28,11 +28,8 @@ export class SlotComponent implements OnInit, OnDestroy {
}

subscription: Subscription | undefined
components$:
| Observable<
{ componentType: Type<unknown> | undefined; remoteComponent: RemoteComponentInfo; permissions: string[] }[]
>
| undefined
components$: Observable<SlotComponentConfiguration[]> | undefined
SchettlerKoehler marked this conversation as resolved.
Show resolved Hide resolved
loading = true

constructor(@Inject(SLOT_SERVICE) private slotService: SlotService) {}

Expand All @@ -43,23 +40,38 @@ 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<any>(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)
SchettlerKoehler marked this conversation as resolved.
Show resolved Hide resolved
})
}
})
}
}
)
}

private createComponent(
componentType: Type<unknown> | undefined,
componentInfo: { remoteComponent: RemoteComponentInfo; },
permissions: string[],
viewContainers: QueryList<ViewContainerRef>,
i: number
) {
this.loading = false
if (componentType) {
const componentRef = viewContainers.get(i)?.createComponent<any>(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()
}
Expand Down
10 changes: 7 additions & 3 deletions libs/angular-remote-components/src/lib/services/slot.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ export const SLOT_SERVICE: InjectionToken<SlotService> = new InjectionToken('SLO

export type RemoteComponentInfo = { appId: string; productName: string; baseUrl: string }

export type SlotComponentConfiguration = {
componentType: Promise<Type<unknown> | undefined> | Type<unknown> | undefined;
remoteComponent: RemoteComponentInfo;
permissions: Promise<string[]> | string[];
}

export interface SlotService {
init(): Promise<void>
getComponentsForSlot(
slotName: string
): Observable<
{ componentType: Type<unknown> | undefined; remoteComponent: RemoteComponentInfo; permissions: string[] }[]
>
): Observable<SlotComponentConfiguration[]>
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@
</svg>
</a>

<a class="layout-menu-button shadow-6" (click)="onMenuButtonClick($event)" pRipple [title]="menuButtonTitle ?? ('OCX_HEADER.MENU_TOGGLE')">
<a
class="layout-menu-button shadow-6"
(click)="onMenuButtonClick($event)"
pRipple
[title]="menuButtonTitle ?? ('OCX_HEADER.MENU_TOGGLE')"
>
<i class="pi pi-chevron-right"></i>
</a>
</div>
Expand All @@ -44,17 +49,19 @@
<ng-content></ng-content>
</div>
<div class="layout-topbar-actions-right">
<ocx-slot name="headerRight" class="layout-topbar-items"></ocx-slot>
<ocx-slot name="headerRight" class="layout-topbar-items">
<div class="flex flex-row justify-content-between w-full gap-3 h-full">
<p-skeleton shape="circle" size="2.5rem" class="h-full flex align-items-center"></p-skeleton>
SchettlerKoehler marked this conversation as resolved.
Show resolved Hide resolved
<p-skeleton shape="circle" size="2.5rem" class="h-full flex align-items-center"></p-skeleton>
<p-skeleton shape="circle" size="2.5rem" class="h-full flex align-items-center"></p-skeleton>
</div>
</ocx-slot>
<ul class="layout-topbar-items">
<!-- Only desktop: Actions (favorites, support, search, ...) as icon buttons -->
<ng-container *ocxIfBreakpoint="'desktop'">

</ng-container>
<ng-container *ocxIfBreakpoint="'desktop'"> </ng-container>

<!-- Only mobile: Actions (favorites, support, search, ...) as 'more' button + overlay -->
<li class="layout-topbar-item" *ocxIfBreakpoint="'mobile'">

</li>
<li class="layout-topbar-item" *ocxIfBreakpoint="'mobile'"></li>
</ul>
</div>
</div>
Expand Down
3 changes: 2 additions & 1 deletion libs/shell-core/src/lib/shell-core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ 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],
})
Expand Down
Loading