phase-6: add registry-driven dynamic page-section-widget rendering engine
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
import { PageConfig } from '../../shared/models/config';
|
||||
import { SectionRenderNode } from '../section-renderer/section-renderer.model';
|
||||
|
||||
export interface PageRenderModel {
|
||||
id: string;
|
||||
key: string;
|
||||
title: string;
|
||||
layout: string;
|
||||
sections: SectionRenderNode[];
|
||||
source: PageConfig;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { PageConfig } from '../../shared/models/config';
|
||||
import { PageRenderModel } from './page-renderer.model';
|
||||
import { SectionRendererService } from '../section-renderer/section-renderer.service';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class PageRendererService {
|
||||
constructor(private readonly sectionRenderer: SectionRendererService) {}
|
||||
|
||||
toRenderModel(page: PageConfig): PageRenderModel {
|
||||
const sections = (page.sections ?? [])
|
||||
.filter(section => section.visible !== false)
|
||||
.sort((a, b) => a.order - b.order)
|
||||
.map(section => this.sectionRenderer.toRenderNode(section));
|
||||
|
||||
return {
|
||||
id: page.id,
|
||||
key: page.key,
|
||||
title: page.title,
|
||||
layout: page.layout,
|
||||
sections,
|
||||
source: page
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { SectionConfig } from '../../shared/models/config';
|
||||
import { WidgetRenderNode } from '../widget-host/widget-host.model';
|
||||
|
||||
export interface SectionRenderNode {
|
||||
id: string;
|
||||
type: string;
|
||||
order: number;
|
||||
featureFlag?: string;
|
||||
visible?: boolean;
|
||||
widgets: WidgetRenderNode[];
|
||||
source: SectionConfig;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { SectionConfig } from '../../shared/models/config';
|
||||
import { SectionRenderNode } from './section-renderer.model';
|
||||
import { WidgetRenderNode } from '../widget-host/widget-host.model';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class SectionRendererService {
|
||||
toRenderNode(section: SectionConfig): SectionRenderNode {
|
||||
const widgets = (section.widgets ?? [])
|
||||
.filter(widget => widget.visible !== false)
|
||||
.map<WidgetRenderNode>(widget => ({
|
||||
id: widget.id,
|
||||
type: widget.type,
|
||||
version: widget.version,
|
||||
props: widget.props ?? {},
|
||||
featureFlag: widget.featureFlag,
|
||||
visible: widget.visible,
|
||||
source: widget
|
||||
}));
|
||||
|
||||
return {
|
||||
id: section.id,
|
||||
type: section.type,
|
||||
order: section.order,
|
||||
featureFlag: section.featureFlag,
|
||||
visible: section.visible,
|
||||
widgets,
|
||||
source: section
|
||||
};
|
||||
}
|
||||
}
|
||||
11
src/app/dynamic-renderer/widget-host/widget-host.model.ts
Normal file
11
src/app/dynamic-renderer/widget-host/widget-host.model.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { WidgetConfig } from '../../shared/models/config';
|
||||
|
||||
export interface WidgetRenderNode {
|
||||
id: string;
|
||||
type: string;
|
||||
version: string;
|
||||
props: Record<string, unknown>;
|
||||
featureFlag?: string;
|
||||
visible?: boolean;
|
||||
source: WidgetConfig;
|
||||
}
|
||||
23
src/app/dynamic-renderer/widget-host/widget-host.service.ts
Normal file
23
src/app/dynamic-renderer/widget-host/widget-host.service.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { WidgetConfig } from '../../shared/models/config';
|
||||
import { WidgetRegistryService } from '../../widgets/registry/widget-registry.service';
|
||||
import { ResolvedWidget } from '../../widgets/contracts/widget-component.contract';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class WidgetHostService {
|
||||
constructor(private readonly registry: WidgetRegistryService) {}
|
||||
|
||||
resolveWidget(widget: WidgetConfig): ResolvedWidget | null {
|
||||
const registered = this.registry.resolve(widget.type, widget.version);
|
||||
if (!registered) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
type: registered.type,
|
||||
version: registered.version,
|
||||
component: registered.component,
|
||||
props: widget.props ?? {}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user