Sprint 8: add widget manifest and data source engine
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { NgComponentOutlet } from '@angular/common';
|
||||
import { Observable } from 'rxjs';
|
||||
import { PageRenderModel } from '../../dynamic-renderer/page-renderer/page-renderer.model';
|
||||
import { WidgetRenderNode } from '../../dynamic-renderer/widget-host/widget-host.model';
|
||||
import { ResolvedWidget } from '../../widgets/contracts/widget-component.contract';
|
||||
import { WidgetHostService } from '../../dynamic-renderer/widget-host/widget-host.service';
|
||||
import { RuntimeDiagnosticsService } from '../../core/runtime/runtime-diagnostics.service';
|
||||
import { UnknownWidgetComponent } from '../../widgets/ui';
|
||||
import { ConfigService } from '../../core/config/config.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dynamic-page-layout',
|
||||
@@ -16,21 +15,21 @@ import { ConfigService } from '../../core/config/config.service';
|
||||
@if (model) {
|
||||
<main class="dynamic-page-layout" [attr.data-layout]="model.layout">
|
||||
@for (section of model.sections; track section.id) {
|
||||
<section
|
||||
class="dynamic-section"
|
||||
[attr.data-section-type]="section.type"
|
||||
[attr.data-section-layout]="section.layout?.strategy ?? section.type"
|
||||
[style.--section-columns]="section.layout?.columns ?? null"
|
||||
[style.--section-gap]="section.layout?.gap ?? null"
|
||||
[style.--section-align]="section.layout?.align ?? null"
|
||||
[class.dynamic-section--desktop-hidden]="section.visibility?.desktop === false"
|
||||
[class.dynamic-section--tablet-hidden]="section.visibility?.tablet === false"
|
||||
[class.dynamic-section--mobile-hidden]="section.visibility?.mobile === false"
|
||||
>
|
||||
<section
|
||||
class="dynamic-section"
|
||||
[attr.data-section-type]="section.type"
|
||||
[attr.data-section-layout]="section.layout?.strategy ?? section.type"
|
||||
[style.--section-columns]="section.layout?.columns ?? null"
|
||||
[style.--section-gap]="section.layout?.gap ?? null"
|
||||
[style.--section-align]="section.layout?.align ?? null"
|
||||
[class.dynamic-section--desktop-hidden]="section.visibility?.desktop === false"
|
||||
[class.dynamic-section--tablet-hidden]="section.visibility?.tablet === false"
|
||||
[class.dynamic-section--mobile-hidden]="section.visibility?.mobile === false"
|
||||
>
|
||||
@for (widget of section.widgets; track widget.id) {
|
||||
<div class="dynamic-widget" [attr.data-widget-type]="widget.type">
|
||||
@if (resolveWidget(widget, section.id); as resolved) {
|
||||
<ng-container *ngComponentOutlet="resolved.component; inputs: resolved.props"></ng-container>
|
||||
@if (resolveWidget(widget, section, model.id) | async; as resolved) {
|
||||
<ng-container *ngComponentOutlet="$any(resolved).component; inputs: { section: $any(resolved).section, data: $any(resolved).data }"></ng-container>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@@ -71,42 +70,10 @@ import { ConfigService } from '../../core/config/config.service';
|
||||
})
|
||||
export class DynamicPageLayoutComponent {
|
||||
@Input() model: PageRenderModel | null = null;
|
||||
private readonly loggedUnknownWidgets = new Set<string>();
|
||||
|
||||
constructor(
|
||||
private readonly widgetHost: WidgetHostService,
|
||||
private readonly diagnostics: RuntimeDiagnosticsService,
|
||||
private readonly configService: ConfigService
|
||||
) {}
|
||||
constructor(private readonly widgetHost: WidgetHostService) {}
|
||||
|
||||
resolveWidget(widget: WidgetRenderNode, sectionId?: string) {
|
||||
const resolved = this.widgetHost.resolveWidget(widget.source);
|
||||
if (resolved) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
const diagnosticKey = `${this.model?.id ?? 'unknown'}:${sectionId ?? 'unknown'}:${widget.id}`;
|
||||
if (!this.loggedUnknownWidgets.has(diagnosticKey)) {
|
||||
this.loggedUnknownWidgets.add(diagnosticKey);
|
||||
|
||||
const tenantId = this.configService.getBootstrapSnapshot()?.tenant.id ?? 'unknown';
|
||||
this.diagnostics.logUnknownWidget({
|
||||
tenant: tenantId,
|
||||
page: this.model?.key ?? 'unknown',
|
||||
section: sectionId ?? 'unknown',
|
||||
widget: `${widget.type}@${widget.version}`,
|
||||
reason: 'not_registered_in_widget_registry'
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: widget.type,
|
||||
version: widget.version,
|
||||
component: UnknownWidgetComponent,
|
||||
props: {
|
||||
widgetType: widget.type,
|
||||
widgetVersion: widget.version
|
||||
}
|
||||
};
|
||||
resolveWidget(widget: WidgetRenderNode, section: PageRenderModel['sections'][number], pageId: string): Observable<ResolvedWidget> {
|
||||
return this.widgetHost.resolveWidget(widget.source, section.source, pageId);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user