@praxisui/core 10.0.0-rc.16 → 10.0.0-rc.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/ai/component-registry.json +2 -2
- package/fesm2022/praxisui-core.mjs +65 -18
- package/package.json +1 -1
- package/types/praxisui-core.d.ts +9 -1
package/README.md
CHANGED
|
@@ -93,6 +93,15 @@ backend B7 acceptance is complete.
|
|
|
93
93
|
|
|
94
94
|
`GovernedColorPaletteService` is the canonical Angular client for color-palette projections published by Praxis Config. Published palettes carry a stable `familyKey`, an explicit `variant` identity and token-level `displayName`/`aliases`; incomplete legacy projections are rejected before caching. The service supports list/read/capabilities/preview, exact `list(familyKey)` queries, tenant/environment-isolated caching, conditional ETag revalidation and deterministic `version`/`etag` pins. Consumers may use names and aliases for presentation and discovery only: `paletteKey` and `tokenId` remain the persisted identities, and local metadata must not become a second source of governance. `GovernedColorTokenSelection` carries the exact palette/version/ETag/token observation beside the existing CSS-string field value; applications persist it only through an explicit domain field or mapping.
|
|
95
95
|
|
|
96
|
+
## Declarative Page DataSources (`page.dataSources`)
|
|
97
|
+
|
|
98
|
+
`WidgetPageDefinition.dataSources` and `WidgetPageDataSourceRuntimeService` allow dynamic pages and dashboards to fetch backend KPIs, group-by aggregations, and time-series metrics without imperative host `HttpClient` orchestration:
|
|
99
|
+
|
|
100
|
+
- **Endpoint resolution (`endpointKey` + `resourcePath`)**: resolves URLs through the `API_URL` token using `endpointKey` (falling back to `'default'`) so multi-service enterprise hosts route each DataSource to its target microservice.
|
|
101
|
+
- **Transform presets & JsonLogic**: supports `{ kind: 'path', path }`, `{ kind: 'group-by-map', mappings, totalField }` (initializing declared keys with `0` for sparse buckets), `{ kind: 'timeseries-last', mappings }`, or arbitrary JsonLogic expressions.
|
|
102
|
+
- **Transient state overlay (`targetStatePath`)**: merges resolved payloads into a non-persisted runtime overlay over `page.state.values[targetStatePath]` and coalesces concurrent emissions via microtask batching before re-evaluating `page.state.derived` and `composition.links`. Live runtime payloads never dirty `authoredPageDefinition` or trigger `autoPersist` writes.
|
|
103
|
+
- **Resilience & visibility-aware polling**: `errorPolicy` (`'fallback' | 'silent' | 'propagate'`) applies `fallbackValue` only before the first successful response so transient network errors during polling (`refreshIntervalMs`) never overwrite live data with static fallbacks. Subsequent poll ticks pause while `document.visibilityState === 'hidden'` and resume immediately on `visibilitychange`.
|
|
104
|
+
|
|
96
105
|
## LLM Recommendation Guide
|
|
97
106
|
|
|
98
107
|
- `BUILTIN_WIDGET_SHELL_PRESETS` is the canonical catalog for reusable shell
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "1.0.0",
|
|
3
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"generatedAt": "2026-10-14T22:05:37.957Z",
|
|
4
4
|
"packageName": "@praxisui/core",
|
|
5
|
-
"packageVersion": "10.0.0-rc.
|
|
5
|
+
"packageVersion": "10.0.0-rc.17",
|
|
6
6
|
"sourceRegistry": "praxis-component-registry-ingestion",
|
|
7
7
|
"sourceRegistryVersion": "1.0.0",
|
|
8
8
|
"componentCount": 4,
|
|
@@ -40174,17 +40174,51 @@ class WidgetPageDataSourceRuntimeService {
|
|
|
40174
40174
|
}
|
|
40175
40175
|
return request$.pipe(map((res) => this.transformPayload(res, dataSource)));
|
|
40176
40176
|
}
|
|
40177
|
+
/**
|
|
40178
|
+
* Normaliza `page.dataSources` aceitando tanto o formato canônico em Array quanto Object Map indexado por id.
|
|
40179
|
+
*/
|
|
40180
|
+
normalizeDataSources(dataSources) {
|
|
40181
|
+
if (!dataSources || typeof dataSources !== 'object') {
|
|
40182
|
+
return [];
|
|
40183
|
+
}
|
|
40184
|
+
if (Array.isArray(dataSources)) {
|
|
40185
|
+
return dataSources.filter((item) => !!item &&
|
|
40186
|
+
typeof item === 'object' &&
|
|
40187
|
+
!Array.isArray(item) &&
|
|
40188
|
+
typeof item.id === 'string' &&
|
|
40189
|
+
item.id.trim().length > 0 &&
|
|
40190
|
+
typeof item.resourcePath === 'string' &&
|
|
40191
|
+
item.resourcePath.trim().length > 0);
|
|
40192
|
+
}
|
|
40193
|
+
return Object.entries(dataSources)
|
|
40194
|
+
.filter(([key, item]) => key.trim().length > 0 &&
|
|
40195
|
+
!!item &&
|
|
40196
|
+
typeof item === 'object' &&
|
|
40197
|
+
!Array.isArray(item) &&
|
|
40198
|
+
typeof item.resourcePath === 'string' &&
|
|
40199
|
+
item.resourcePath.trim().length > 0)
|
|
40200
|
+
.map(([key, item]) => {
|
|
40201
|
+
const candidateId = item.id;
|
|
40202
|
+
return {
|
|
40203
|
+
...item,
|
|
40204
|
+
id: typeof candidateId === 'string' && candidateId.trim().length > 0
|
|
40205
|
+
? candidateId.trim()
|
|
40206
|
+
: key.trim(),
|
|
40207
|
+
};
|
|
40208
|
+
});
|
|
40209
|
+
}
|
|
40177
40210
|
/**
|
|
40178
40211
|
* Inicia a orquestração reativa de todos os DataSources declarados em uma página dinâmica.
|
|
40179
40212
|
* Retorna uma função de teardown que cancela todas as requisições em voo e timers de polling.
|
|
40180
40213
|
*/
|
|
40181
40214
|
startDataSources(dataSources, onUpdate, onDiagnostic) {
|
|
40182
|
-
|
|
40215
|
+
const normalizedDataSources = this.normalizeDataSources(dataSources);
|
|
40216
|
+
if (!normalizedDataSources.length) {
|
|
40183
40217
|
return () => { };
|
|
40184
40218
|
}
|
|
40185
40219
|
const destroy$ = new Subject();
|
|
40186
40220
|
const visibilityCallbacks = [];
|
|
40187
|
-
for (const ds of
|
|
40221
|
+
for (const ds of normalizedDataSources) {
|
|
40188
40222
|
if (ds.autoFetch === false) {
|
|
40189
40223
|
continue;
|
|
40190
40224
|
}
|
|
@@ -46034,6 +46068,7 @@ class DynamicWidgetPageComponent {
|
|
|
46034
46068
|
this.currentDataSourcesSignature) {
|
|
46035
46069
|
this.dataSourceRuntimeOverlay.clear();
|
|
46036
46070
|
this.dataSourceDiagnostics.clear();
|
|
46071
|
+
this.pendingDataSourceUpdates = [];
|
|
46037
46072
|
this.currentDataSourcesSignature = null;
|
|
46038
46073
|
}
|
|
46039
46074
|
this.pageRuntime = this.buildStateRuntime(this.pageDefinition?.state, this.pageDefinition?.context);
|
|
@@ -46366,9 +46401,8 @@ class DynamicWidgetPageComponent {
|
|
|
46366
46401
|
};
|
|
46367
46402
|
}
|
|
46368
46403
|
getDataSourcesSignature(dataSources) {
|
|
46369
|
-
|
|
46370
|
-
|
|
46371
|
-
: null;
|
|
46404
|
+
const normalized = this.dataSourceRuntime.normalizeDataSources(dataSources);
|
|
46405
|
+
return normalized.length > 0 ? JSON.stringify(normalized) : null;
|
|
46372
46406
|
}
|
|
46373
46407
|
bootstrapCompositionAdapter(page) {
|
|
46374
46408
|
if (!page) {
|
|
@@ -48783,15 +48817,22 @@ class DynamicWidgetPageComponent {
|
|
|
48783
48817
|
themePreset: themePreset || undefined,
|
|
48784
48818
|
}, persist);
|
|
48785
48819
|
}
|
|
48786
|
-
applyAuthoringPageUpdate(next, persist = true, runtime
|
|
48820
|
+
applyAuthoringPageUpdate(next, persist = true, runtime, syncCompositionAdapter = true, skipStateWidgetProjection = false, emitUnchangedCanonicalPage = true) {
|
|
48787
48821
|
this.applyPageUpdate(next, persist, runtime, syncCompositionAdapter, skipStateWidgetProjection, emitUnchangedCanonicalPage);
|
|
48788
48822
|
if (this.authoredPageDefinition) {
|
|
48789
48823
|
this.pageAuthoringChange.emit(this.clonePageDefinition(this.authoredPageDefinition));
|
|
48790
48824
|
}
|
|
48791
48825
|
}
|
|
48792
|
-
applyPageUpdate(next, persist = true, runtime
|
|
48826
|
+
applyPageUpdate(next, persist = true, runtime, syncCompositionAdapter = true, skipStateWidgetProjection = false, emitUnchangedCanonicalPage = true) {
|
|
48793
48827
|
this.assertNoLegacyConnections(next);
|
|
48794
|
-
|
|
48828
|
+
if (this.getDataSourcesSignature(next.dataSources) !==
|
|
48829
|
+
this.currentDataSourcesSignature) {
|
|
48830
|
+
this.dataSourceRuntimeOverlay.clear();
|
|
48831
|
+
this.dataSourceDiagnostics.clear();
|
|
48832
|
+
this.pendingDataSourceUpdates = [];
|
|
48833
|
+
}
|
|
48834
|
+
const effectiveRuntime = runtime ?? this.buildStateRuntime(next.state, next.context);
|
|
48835
|
+
const normalized = { ...next, state: effectiveRuntime.state };
|
|
48795
48836
|
const normalizedWidgets = this.applyEditShellActions(normalized.widgets || []);
|
|
48796
48837
|
const bootstrapSnapshot = syncCompositionAdapter
|
|
48797
48838
|
? this.bootstrapCompositionAdapter(normalized)
|
|
@@ -48799,13 +48840,13 @@ class DynamicWidgetPageComponent {
|
|
|
48799
48840
|
const stateBoundWidgets = skipStateWidgetProjection
|
|
48800
48841
|
? normalizedWidgets
|
|
48801
48842
|
: bootstrapSnapshot
|
|
48802
|
-
? this.applyBootstrapCompositionHydration(normalizedWidgets, bootstrapSnapshot,
|
|
48843
|
+
? this.applyBootstrapCompositionHydration(normalizedWidgets, bootstrapSnapshot, effectiveRuntime)
|
|
48803
48844
|
: this.compositionDefinition
|
|
48804
48845
|
? this.compositionRuntime.projectStateWidgetInputs(this.compositionDefinition, {
|
|
48805
48846
|
widgets: normalizedWidgets,
|
|
48806
48847
|
state: {
|
|
48807
|
-
primaryValues: this.cloneStateValues(
|
|
48808
|
-
derivedValues: this.cloneStateValues(
|
|
48848
|
+
primaryValues: this.cloneStateValues(effectiveRuntime.primaryValues),
|
|
48849
|
+
derivedValues: this.cloneStateValues(effectiveRuntime.derivedValues),
|
|
48809
48850
|
transientValues: this.cloneStateValues(this.compositionRuntime.getSnapshot().state.transientValues),
|
|
48810
48851
|
changedPaths: [],
|
|
48811
48852
|
diagnostics: [],
|
|
@@ -48818,9 +48859,9 @@ class DynamicWidgetPageComponent {
|
|
|
48818
48859
|
});
|
|
48819
48860
|
this.pageDefinition = hydrated;
|
|
48820
48861
|
this.page = hydrated;
|
|
48821
|
-
this.pageState =
|
|
48822
|
-
this.pageRuntime =
|
|
48823
|
-
this.applyResponsivePresentation(hydrated, hydrated?.widgets || stateBoundWidgets,
|
|
48862
|
+
this.pageState = effectiveRuntime.state;
|
|
48863
|
+
this.pageRuntime = effectiveRuntime;
|
|
48864
|
+
this.applyResponsivePresentation(hydrated, hydrated?.widgets || stateBoundWidgets, effectiveRuntime);
|
|
48824
48865
|
this.restartDataSources(hydrated);
|
|
48825
48866
|
if (this.widgetEventBus) {
|
|
48826
48867
|
this.wiringSubscription?.unsubscribe();
|
|
@@ -48836,7 +48877,7 @@ class DynamicWidgetPageComponent {
|
|
|
48836
48877
|
if (authoredPageChanged || emitUnchangedCanonicalPage) {
|
|
48837
48878
|
this.pageChange.emit(canonicalPage);
|
|
48838
48879
|
}
|
|
48839
|
-
this.reportStateDiagnostics(
|
|
48880
|
+
this.reportStateDiagnostics(effectiveRuntime.diagnostics);
|
|
48840
48881
|
if (authoredPageChanged &&
|
|
48841
48882
|
persist &&
|
|
48842
48883
|
this.autoPersist &&
|
|
@@ -48927,12 +48968,14 @@ class DynamicWidgetPageComponent {
|
|
|
48927
48968
|
this.currentDataSourcesSignature = signature;
|
|
48928
48969
|
this.dataSourceRuntimeOverlay.clear();
|
|
48929
48970
|
this.dataSourceDiagnostics.clear();
|
|
48971
|
+
this.pendingDataSourceUpdates = [];
|
|
48930
48972
|
this.dataSourceTeardown?.();
|
|
48931
48973
|
this.dataSourceTeardown = undefined;
|
|
48932
|
-
|
|
48974
|
+
const normalizedDataSources = this.dataSourceRuntime.normalizeDataSources(dataSources);
|
|
48975
|
+
if (normalizedDataSources.length === 0) {
|
|
48933
48976
|
return;
|
|
48934
48977
|
}
|
|
48935
|
-
this.dataSourceTeardown = this.dataSourceRuntime.startDataSources(
|
|
48978
|
+
this.dataSourceTeardown = this.dataSourceRuntime.startDataSources(normalizedDataSources, (update) => this.handleDataSourceUpdate(update), (diagnostic) => this.handleDataSourceDiagnostic(diagnostic));
|
|
48936
48979
|
}
|
|
48937
48980
|
applyLayout(layout, grouping, deviceLayoutColumnsSelected = false) {
|
|
48938
48981
|
this.layout = layout;
|
|
@@ -49274,7 +49317,11 @@ class DynamicWidgetPageComponent {
|
|
|
49274
49317
|
}
|
|
49275
49318
|
return this.compositionRuntime.projectStateWidgetInputs(this.compositionDefinition, {
|
|
49276
49319
|
widgets,
|
|
49277
|
-
state:
|
|
49320
|
+
state: {
|
|
49321
|
+
...snapshot.state,
|
|
49322
|
+
primaryValues: this.cloneStateValues(this.pageRuntime.primaryValues),
|
|
49323
|
+
derivedValues: this.cloneStateValues(this.pageRuntime.derivedValues),
|
|
49324
|
+
},
|
|
49278
49325
|
now: snapshot.generatedAt,
|
|
49279
49326
|
}).widgets;
|
|
49280
49327
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisui/core",
|
|
3
|
-
"version": "10.0.0-rc.
|
|
3
|
+
"version": "10.0.0-rc.17",
|
|
4
4
|
"description": "Core library for Praxis UI Workspace: types, tokens, services and utilities shared across @praxisui/* packages.",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"@angular/cdk": "^21.0.0",
|
package/types/praxisui-core.d.ts
CHANGED
|
@@ -18261,11 +18261,19 @@ declare class WidgetPageDataSourceRuntimeService {
|
|
|
18261
18261
|
*/
|
|
18262
18262
|
fetchDataSource(dataSource: WidgetPageDataSourceDefinition): Observable<unknown>;
|
|
18263
18263
|
private executeRawRequest;
|
|
18264
|
+
/**
|
|
18265
|
+
* Normaliza `page.dataSources` aceitando tanto o formato canônico em Array quanto Object Map indexado por id.
|
|
18266
|
+
*/
|
|
18267
|
+
normalizeDataSources(dataSources: WidgetPageDataSourceDefinition[] | Record<string, Omit<WidgetPageDataSourceDefinition, 'id'> & {
|
|
18268
|
+
id?: string;
|
|
18269
|
+
}> | undefined | null): WidgetPageDataSourceDefinition[];
|
|
18264
18270
|
/**
|
|
18265
18271
|
* Inicia a orquestração reativa de todos os DataSources declarados em uma página dinâmica.
|
|
18266
18272
|
* Retorna uma função de teardown que cancela todas as requisições em voo e timers de polling.
|
|
18267
18273
|
*/
|
|
18268
|
-
startDataSources(dataSources: WidgetPageDataSourceDefinition[] |
|
|
18274
|
+
startDataSources(dataSources: WidgetPageDataSourceDefinition[] | Record<string, Omit<WidgetPageDataSourceDefinition, 'id'> & {
|
|
18275
|
+
id?: string;
|
|
18276
|
+
}> | undefined, onUpdate: (event: WidgetPageDataSourceUpdateEvent) => void, onDiagnostic?: (diagnostic: WidgetPageDataSourceDiagnostic) => void): () => void;
|
|
18269
18277
|
/**
|
|
18270
18278
|
* Transforma a resposta bruta do backend aplicando envelope canônico ou JsonLogic.
|
|
18271
18279
|
*/
|