@praxisui/core 9.0.4-rc.32 → 9.0.4-rc.34
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/ai/component-registry.json +6 -6
- package/fesm2022/praxisui-core.mjs +1161 -1054
- package/package.json +1 -1
- package/types/praxisui-core.d.ts +7 -0
|
@@ -22766,696 +22766,1084 @@ function getEditorialSolutionPresetById(presetId) {
|
|
|
22766
22766
|
return match ? structuredClone(match) : undefined;
|
|
22767
22767
|
}
|
|
22768
22768
|
|
|
22769
|
-
|
|
22770
|
-
|
|
22771
|
-
|
|
22772
|
-
]);
|
|
22773
|
-
/**
|
|
22774
|
-
* Normalizes a CompositionLink for deterministic persistence.
|
|
22775
|
-
* Ensures explicit ordering and strips compatibility-only legacy residues.
|
|
22776
|
-
*/
|
|
22777
|
-
function normalizeCompositionLink(link) {
|
|
22778
|
-
const normalized = {
|
|
22779
|
-
id: link.id,
|
|
22780
|
-
from: normalizeEndpoint(link.from),
|
|
22781
|
-
to: normalizeEndpoint(link.to),
|
|
22782
|
-
intent: link.intent,
|
|
22783
|
-
};
|
|
22784
|
-
if (link.transform) {
|
|
22785
|
-
normalized.transform = clone$1(link.transform);
|
|
22786
|
-
}
|
|
22787
|
-
const condition = normalizeCondition(link.condition);
|
|
22788
|
-
if (condition !== undefined) {
|
|
22789
|
-
normalized.condition = condition;
|
|
22769
|
+
class NestedWidgetConfigAccessor {
|
|
22770
|
+
listNestedWidgets(owner) {
|
|
22771
|
+
return this.listNestedWidgetsInDefinition(owner.key, owner.definition, []);
|
|
22790
22772
|
}
|
|
22791
|
-
|
|
22792
|
-
|
|
22793
|
-
|
|
22773
|
+
resolveNestedWidget(owner, nestedPath) {
|
|
22774
|
+
if (!nestedPath?.length) {
|
|
22775
|
+
return undefined;
|
|
22776
|
+
}
|
|
22777
|
+
return this.resolveNestedWidgetInDefinition(owner.definition, nestedPath);
|
|
22794
22778
|
}
|
|
22795
|
-
|
|
22796
|
-
|
|
22797
|
-
|
|
22779
|
+
setNestedWidgetInput(owner, nestedPath, inputName, value) {
|
|
22780
|
+
const normalizedInputName = String(inputName || '').trim();
|
|
22781
|
+
if (!nestedPath?.length || !normalizedInputName) {
|
|
22782
|
+
return { widget: this.clone(owner), changed: false };
|
|
22783
|
+
}
|
|
22784
|
+
const next = this.clone(owner);
|
|
22785
|
+
const changed = this.setNestedWidgetInputInDefinition(next.definition, nestedPath, normalizedInputName, this.clone(value));
|
|
22786
|
+
return { widget: next, changed };
|
|
22798
22787
|
}
|
|
22799
|
-
|
|
22800
|
-
|
|
22801
|
-
|
|
22802
|
-
|
|
22803
|
-
|
|
22804
|
-
|
|
22805
|
-
|
|
22806
|
-
|
|
22807
|
-
.sort(compareNormalizedLinks);
|
|
22808
|
-
}
|
|
22809
|
-
/**
|
|
22810
|
-
* Canonical persisted write surface for CompositionLink[].
|
|
22811
|
-
* New saved shapes must serialize links under `composition.links`.
|
|
22812
|
-
* Semantic guards persist only through `link.condition` as Json Logic.
|
|
22813
|
-
* Operational delivery behavior remains under `link.policy` and must not be
|
|
22814
|
-
* folded into the condition payload.
|
|
22815
|
-
*/
|
|
22816
|
-
function serializeCompositionLinks(links) {
|
|
22817
|
-
return {
|
|
22818
|
-
version: WIDGET_PAGE_COMPOSITION_SCHEMA_VERSION,
|
|
22819
|
-
links: normalizeCompositionLinks(links),
|
|
22820
|
-
};
|
|
22821
|
-
}
|
|
22822
|
-
/**
|
|
22823
|
-
* Writes the canonical persisted composition surface into a page shape.
|
|
22824
|
-
* The canonical writer omits legacy `connections` to avoid dual-write ambiguity.
|
|
22825
|
-
*/
|
|
22826
|
-
function writeCompositionLinksToPersistedPage(page, links) {
|
|
22827
|
-
const { composition: _legacyComposition, ...rest } = clone$1(page);
|
|
22828
|
-
return {
|
|
22829
|
-
...rest,
|
|
22830
|
-
composition: serializeCompositionLinks(links),
|
|
22831
|
-
};
|
|
22832
|
-
}
|
|
22833
|
-
function normalizeEndpoint(endpoint) {
|
|
22834
|
-
if (endpoint.kind === 'component-port') {
|
|
22835
|
-
const nestedPath = normalizeNestedPath(endpoint.ref.nestedPath);
|
|
22836
|
-
return {
|
|
22837
|
-
kind: 'component-port',
|
|
22838
|
-
ref: {
|
|
22839
|
-
widget: endpoint.ref.widget,
|
|
22840
|
-
port: endpoint.ref.port,
|
|
22841
|
-
direction: endpoint.ref.direction,
|
|
22842
|
-
...(endpoint.ref.componentType ? { componentType: endpoint.ref.componentType } : {}),
|
|
22843
|
-
...(endpoint.ref.bindingPath ? { bindingPath: endpoint.ref.bindingPath } : {}),
|
|
22844
|
-
...(nestedPath.length ? { nestedPath } : {}),
|
|
22845
|
-
},
|
|
22846
|
-
};
|
|
22788
|
+
removeNestedWidgetInput(owner, nestedPath, inputName) {
|
|
22789
|
+
const normalizedInputName = String(inputName || '').trim();
|
|
22790
|
+
if (!nestedPath?.length || !normalizedInputName) {
|
|
22791
|
+
return { widget: this.clone(owner), changed: false };
|
|
22792
|
+
}
|
|
22793
|
+
const next = this.clone(owner);
|
|
22794
|
+
const changed = this.removeNestedWidgetInputInDefinition(next.definition, nestedPath, normalizedInputName);
|
|
22795
|
+
return { widget: next, changed };
|
|
22847
22796
|
}
|
|
22848
|
-
|
|
22849
|
-
|
|
22850
|
-
|
|
22851
|
-
|
|
22852
|
-
|
|
22797
|
+
listNestedWidgetsInDefinition(ownerWidgetKey, definition, basePath) {
|
|
22798
|
+
const results = [];
|
|
22799
|
+
for (const location of this.listChildWidgetLocations(definition)) {
|
|
22800
|
+
for (const [index, widget] of location.widgets.entries()) {
|
|
22801
|
+
if (!this.isWidgetDefinition(widget)) {
|
|
22802
|
+
continue;
|
|
22803
|
+
}
|
|
22804
|
+
const childWidgetKey = this.resolveChildWidgetKey(widget);
|
|
22805
|
+
const widgetSegment = {
|
|
22806
|
+
kind: 'widget',
|
|
22807
|
+
...(childWidgetKey ? { key: childWidgetKey } : { index }),
|
|
22808
|
+
componentType: widget.id,
|
|
22809
|
+
};
|
|
22810
|
+
const nestedPath = [
|
|
22811
|
+
...basePath,
|
|
22812
|
+
...location.path,
|
|
22813
|
+
widgetSegment,
|
|
22814
|
+
];
|
|
22815
|
+
results.push({
|
|
22816
|
+
ownerWidgetKey,
|
|
22817
|
+
nestedPath,
|
|
22818
|
+
widget: this.clone(widget),
|
|
22819
|
+
componentId: widget.id,
|
|
22820
|
+
childWidgetKey,
|
|
22821
|
+
});
|
|
22822
|
+
results.push(...this.listNestedWidgetsInDefinition(ownerWidgetKey, widget, nestedPath));
|
|
22823
|
+
}
|
|
22824
|
+
}
|
|
22825
|
+
return results;
|
|
22853
22826
|
}
|
|
22854
|
-
|
|
22855
|
-
|
|
22856
|
-
|
|
22857
|
-
|
|
22858
|
-
|
|
22859
|
-
|
|
22860
|
-
|
|
22861
|
-
|
|
22862
|
-
|
|
22863
|
-
|
|
22864
|
-
|
|
22865
|
-
|
|
22866
|
-
|
|
22867
|
-
|
|
22868
|
-
|
|
22869
|
-
|
|
22870
|
-
|
|
22871
|
-
|
|
22872
|
-
return [];
|
|
22827
|
+
resolveNestedWidgetInDefinition(definition, nestedPath) {
|
|
22828
|
+
const location = this.resolveWidgetArrayLocation(definition, nestedPath, 0);
|
|
22829
|
+
if (!location) {
|
|
22830
|
+
return undefined;
|
|
22831
|
+
}
|
|
22832
|
+
const widgetSegment = nestedPath[location.segmentCount];
|
|
22833
|
+
if (widgetSegment?.kind !== 'widget' || !widgetSegment.key) {
|
|
22834
|
+
return undefined;
|
|
22835
|
+
}
|
|
22836
|
+
const child = location.widgets.find((widget) => widget.childWidgetKey === widgetSegment.key);
|
|
22837
|
+
if (!this.isWidgetDefinition(child)) {
|
|
22838
|
+
return undefined;
|
|
22839
|
+
}
|
|
22840
|
+
const remaining = nestedPath.slice(location.segmentCount + 1);
|
|
22841
|
+
if (!remaining.length) {
|
|
22842
|
+
return this.clone(child);
|
|
22843
|
+
}
|
|
22844
|
+
return this.resolveNestedWidgetInDefinition(child, remaining);
|
|
22873
22845
|
}
|
|
22874
|
-
|
|
22875
|
-
.
|
|
22876
|
-
|
|
22877
|
-
|
|
22878
|
-
};
|
|
22879
|
-
if (segment.id) {
|
|
22880
|
-
normalized.id = segment.id;
|
|
22846
|
+
setNestedWidgetInputInDefinition(definition, nestedPath, inputName, value) {
|
|
22847
|
+
const location = this.resolveWidgetArrayLocation(definition, nestedPath, 0);
|
|
22848
|
+
if (!location) {
|
|
22849
|
+
return false;
|
|
22881
22850
|
}
|
|
22882
|
-
|
|
22883
|
-
|
|
22851
|
+
const widgetSegment = nestedPath[location.segmentCount];
|
|
22852
|
+
if (widgetSegment?.kind !== 'widget' || !widgetSegment.key) {
|
|
22853
|
+
return false;
|
|
22884
22854
|
}
|
|
22885
|
-
|
|
22886
|
-
|
|
22855
|
+
const widgetIndex = location.widgets.findIndex((widget) => widget.childWidgetKey === widgetSegment.key);
|
|
22856
|
+
if (widgetIndex < 0) {
|
|
22857
|
+
return false;
|
|
22887
22858
|
}
|
|
22888
|
-
|
|
22889
|
-
|
|
22859
|
+
const remaining = nestedPath.slice(location.segmentCount + 1);
|
|
22860
|
+
const child = location.widgets[widgetIndex];
|
|
22861
|
+
if (!this.isWidgetDefinition(child)) {
|
|
22862
|
+
return false;
|
|
22890
22863
|
}
|
|
22891
|
-
|
|
22892
|
-
|
|
22893
|
-
|
|
22894
|
-
|
|
22895
|
-
|
|
22896
|
-
|
|
22897
|
-
|
|
22898
|
-
|
|
22899
|
-
|
|
22900
|
-
|
|
22901
|
-
|
|
22902
|
-
|
|
22903
|
-
|
|
22864
|
+
if (remaining.length) {
|
|
22865
|
+
return this.setNestedWidgetInputInDefinition(child, remaining, inputName, value);
|
|
22866
|
+
}
|
|
22867
|
+
const currentInputs = child.inputs || {};
|
|
22868
|
+
const nextInputs = {
|
|
22869
|
+
...currentInputs,
|
|
22870
|
+
[inputName]: value,
|
|
22871
|
+
};
|
|
22872
|
+
if (this.isEqual(currentInputs, nextInputs)) {
|
|
22873
|
+
return false;
|
|
22874
|
+
}
|
|
22875
|
+
location.widgets[widgetIndex] = {
|
|
22876
|
+
...child,
|
|
22877
|
+
inputs: nextInputs,
|
|
22878
|
+
};
|
|
22879
|
+
return true;
|
|
22904
22880
|
}
|
|
22905
|
-
|
|
22906
|
-
|
|
22881
|
+
removeNestedWidgetInputInDefinition(definition, nestedPath, inputName) {
|
|
22882
|
+
const location = this.resolveWidgetArrayLocation(definition, nestedPath, 0);
|
|
22883
|
+
if (!location) {
|
|
22884
|
+
return false;
|
|
22885
|
+
}
|
|
22886
|
+
const widgetSegment = nestedPath[location.segmentCount];
|
|
22887
|
+
if (widgetSegment?.kind !== 'widget' || !widgetSegment.key) {
|
|
22888
|
+
return false;
|
|
22889
|
+
}
|
|
22890
|
+
const widgetIndex = location.widgets.findIndex((widget) => widget.childWidgetKey === widgetSegment.key);
|
|
22891
|
+
if (widgetIndex < 0) {
|
|
22892
|
+
return false;
|
|
22893
|
+
}
|
|
22894
|
+
const remaining = nestedPath.slice(location.segmentCount + 1);
|
|
22895
|
+
const child = location.widgets[widgetIndex];
|
|
22896
|
+
if (!this.isWidgetDefinition(child)) {
|
|
22897
|
+
return false;
|
|
22898
|
+
}
|
|
22899
|
+
if (remaining.length) {
|
|
22900
|
+
return this.removeNestedWidgetInputInDefinition(child, remaining, inputName);
|
|
22901
|
+
}
|
|
22902
|
+
const currentInputs = child.inputs || {};
|
|
22903
|
+
if (!Object.prototype.hasOwnProperty.call(currentInputs, inputName)) {
|
|
22904
|
+
return false;
|
|
22905
|
+
}
|
|
22906
|
+
const { [inputName]: _runtimeValue, ...nextInputs } = currentInputs;
|
|
22907
|
+
location.widgets[widgetIndex] = {
|
|
22908
|
+
...child,
|
|
22909
|
+
inputs: nextInputs,
|
|
22910
|
+
};
|
|
22911
|
+
return true;
|
|
22907
22912
|
}
|
|
22908
|
-
|
|
22909
|
-
|
|
22910
|
-
|
|
22911
|
-
|
|
22913
|
+
listChildWidgetLocations(definition) {
|
|
22914
|
+
const config = definition.inputs?.['config'];
|
|
22915
|
+
if (!config || typeof config !== 'object') {
|
|
22916
|
+
return [];
|
|
22917
|
+
}
|
|
22918
|
+
if (definition.id === 'praxis-tabs') {
|
|
22919
|
+
return this.listTabsWidgetLocations(config);
|
|
22920
|
+
}
|
|
22921
|
+
if (definition.id === 'praxis-expansion') {
|
|
22922
|
+
return this.listExpansionWidgetLocations(config);
|
|
22923
|
+
}
|
|
22924
|
+
return [];
|
|
22925
|
+
}
|
|
22926
|
+
listTabsWidgetLocations(config) {
|
|
22927
|
+
const locations = [];
|
|
22928
|
+
const tabs = Array.isArray(config['tabs']) ? config['tabs'] : [];
|
|
22929
|
+
for (const [index, tab] of tabs.entries()) {
|
|
22930
|
+
if (!tab || typeof tab !== 'object') {
|
|
22931
|
+
continue;
|
|
22932
|
+
}
|
|
22933
|
+
const widgets = this.asWidgetDefinitions(tab['widgets']);
|
|
22934
|
+
if (!widgets.some((widget) => this.isWidgetDefinition(widget))) {
|
|
22935
|
+
continue;
|
|
22936
|
+
}
|
|
22937
|
+
locations.push({
|
|
22938
|
+
path: [{
|
|
22939
|
+
kind: 'tab',
|
|
22940
|
+
...this.segmentIdentity(tab, index),
|
|
22941
|
+
}],
|
|
22942
|
+
widgets,
|
|
22943
|
+
});
|
|
22944
|
+
}
|
|
22945
|
+
const nav = config['nav'];
|
|
22946
|
+
const links = nav && typeof nav === 'object' && Array.isArray(nav['links'])
|
|
22947
|
+
? nav['links']
|
|
22948
|
+
: [];
|
|
22949
|
+
for (const [index, link] of links.entries()) {
|
|
22950
|
+
if (!link || typeof link !== 'object') {
|
|
22951
|
+
continue;
|
|
22952
|
+
}
|
|
22953
|
+
const widgets = this.asWidgetDefinitions(link['widgets']);
|
|
22954
|
+
if (!widgets.some((widget) => this.isWidgetDefinition(widget))) {
|
|
22955
|
+
continue;
|
|
22956
|
+
}
|
|
22957
|
+
locations.push({
|
|
22958
|
+
path: [
|
|
22959
|
+
{ kind: 'nav' },
|
|
22960
|
+
{
|
|
22961
|
+
kind: 'link',
|
|
22962
|
+
...this.segmentIdentity(link, index),
|
|
22963
|
+
},
|
|
22964
|
+
],
|
|
22965
|
+
widgets,
|
|
22966
|
+
});
|
|
22967
|
+
}
|
|
22968
|
+
return locations;
|
|
22969
|
+
}
|
|
22970
|
+
listExpansionWidgetLocations(config) {
|
|
22971
|
+
const panels = Array.isArray(config['panels']) ? config['panels'] : [];
|
|
22972
|
+
const locations = [];
|
|
22973
|
+
for (const [index, panel] of panels.entries()) {
|
|
22974
|
+
if (!panel || typeof panel !== 'object') {
|
|
22975
|
+
continue;
|
|
22976
|
+
}
|
|
22977
|
+
const widgets = this.asWidgetDefinitions(panel['widgets']);
|
|
22978
|
+
if (!widgets.some((widget) => this.isWidgetDefinition(widget))) {
|
|
22979
|
+
continue;
|
|
22980
|
+
}
|
|
22981
|
+
locations.push({
|
|
22982
|
+
path: [{
|
|
22983
|
+
kind: 'panel',
|
|
22984
|
+
...this.segmentIdentity(panel, index),
|
|
22985
|
+
}],
|
|
22986
|
+
widgets,
|
|
22987
|
+
});
|
|
22988
|
+
}
|
|
22989
|
+
return locations;
|
|
22990
|
+
}
|
|
22991
|
+
resolveWidgetArrayLocation(definition, nestedPath, offset) {
|
|
22992
|
+
if (definition.id === 'praxis-tabs') {
|
|
22993
|
+
return this.resolveTabsWidgetArray(definition, nestedPath, offset);
|
|
22994
|
+
}
|
|
22995
|
+
if (definition.id === 'praxis-expansion') {
|
|
22996
|
+
return this.resolveExpansionWidgetArray(definition, nestedPath, offset);
|
|
22997
|
+
}
|
|
22912
22998
|
return undefined;
|
|
22913
22999
|
}
|
|
22914
|
-
|
|
22915
|
-
|
|
22916
|
-
|
|
22917
|
-
|
|
22918
|
-
|
|
22919
|
-
|
|
22920
|
-
|
|
22921
|
-
|
|
22922
|
-
|
|
22923
|
-
|
|
22924
|
-
|
|
22925
|
-
|
|
23000
|
+
resolveTabsWidgetArray(definition, nestedPath, offset) {
|
|
23001
|
+
const config = definition.inputs?.['config'];
|
|
23002
|
+
if (!config || typeof config !== 'object') {
|
|
23003
|
+
return undefined;
|
|
23004
|
+
}
|
|
23005
|
+
const first = nestedPath[offset];
|
|
23006
|
+
if (first?.kind === 'tab') {
|
|
23007
|
+
const tabs = Array.isArray(config['tabs'])
|
|
23008
|
+
? config['tabs']
|
|
23009
|
+
: [];
|
|
23010
|
+
const tab = this.findBySegment(tabs, first);
|
|
23011
|
+
const widgets = tab && typeof tab === 'object'
|
|
23012
|
+
? this.asWidgetDefinitions(tab['widgets'])
|
|
23013
|
+
: [];
|
|
23014
|
+
return widgets.length ? { widgets, segmentCount: offset + 1 } : undefined;
|
|
23015
|
+
}
|
|
23016
|
+
const linkSegment = first?.kind === 'nav'
|
|
23017
|
+
? nestedPath[offset + 1]
|
|
23018
|
+
: first;
|
|
23019
|
+
if (linkSegment?.kind !== 'link') {
|
|
23020
|
+
return undefined;
|
|
23021
|
+
}
|
|
23022
|
+
const nav = config['nav'];
|
|
23023
|
+
const links = nav && typeof nav === 'object' && Array.isArray(nav['links'])
|
|
23024
|
+
? nav['links']
|
|
23025
|
+
: [];
|
|
23026
|
+
const link = this.findBySegment(links, linkSegment);
|
|
23027
|
+
const widgets = link && typeof link === 'object'
|
|
23028
|
+
? this.asWidgetDefinitions(link['widgets'])
|
|
23029
|
+
: [];
|
|
23030
|
+
return widgets.length
|
|
23031
|
+
? { widgets, segmentCount: first?.kind === 'nav' ? offset + 2 : offset + 1 }
|
|
23032
|
+
: undefined;
|
|
23033
|
+
}
|
|
23034
|
+
resolveExpansionWidgetArray(definition, nestedPath, offset) {
|
|
23035
|
+
const config = definition.inputs?.['config'];
|
|
23036
|
+
const panelSegment = nestedPath[offset];
|
|
23037
|
+
if (!config || typeof config !== 'object' || panelSegment?.kind !== 'panel') {
|
|
23038
|
+
return undefined;
|
|
23039
|
+
}
|
|
23040
|
+
const panels = Array.isArray(config['panels'])
|
|
23041
|
+
? config['panels']
|
|
23042
|
+
: [];
|
|
23043
|
+
const panel = this.findBySegment(panels, panelSegment);
|
|
23044
|
+
const widgets = panel && typeof panel === 'object'
|
|
23045
|
+
? this.asWidgetDefinitions(panel['widgets'])
|
|
23046
|
+
: [];
|
|
23047
|
+
return widgets.length ? { widgets, segmentCount: offset + 1 } : undefined;
|
|
23048
|
+
}
|
|
23049
|
+
findBySegment(items, segment) {
|
|
23050
|
+
if (segment.id) {
|
|
23051
|
+
const byId = items.find((item) => !!item
|
|
23052
|
+
&& typeof item === 'object'
|
|
23053
|
+
&& item['id'] === segment.id);
|
|
23054
|
+
if (byId) {
|
|
23055
|
+
return byId;
|
|
23056
|
+
}
|
|
23057
|
+
}
|
|
23058
|
+
if (typeof segment.index === 'number') {
|
|
23059
|
+
return items[segment.index];
|
|
23060
|
+
}
|
|
22926
23061
|
return undefined;
|
|
22927
23062
|
}
|
|
22928
|
-
|
|
22929
|
-
? [
|
|
22930
|
-
|
|
22931
|
-
|
|
22932
|
-
|
|
22933
|
-
|
|
22934
|
-
const normalized = {
|
|
22935
|
-
...(metadata.label ? { label: metadata.label } : {}),
|
|
22936
|
-
...(metadata.description ? { description: metadata.description } : {}),
|
|
22937
|
-
...(tags?.length ? { tags } : {}),
|
|
22938
|
-
...(metadata.deprecated !== undefined ? { deprecated: metadata.deprecated } : {}),
|
|
22939
|
-
...(source ? { source } : {}),
|
|
22940
|
-
};
|
|
22941
|
-
return Object.keys(normalized).length ? normalized : undefined;
|
|
22942
|
-
}
|
|
22943
|
-
function compareNormalizedLinks(a, b) {
|
|
22944
|
-
return compareValues([
|
|
22945
|
-
a.id,
|
|
22946
|
-
a.intent,
|
|
22947
|
-
endpointSortKey(a.from),
|
|
22948
|
-
endpointSortKey(a.to),
|
|
22949
|
-
JSON.stringify(a.condition ?? null),
|
|
22950
|
-
], [
|
|
22951
|
-
b.id,
|
|
22952
|
-
b.intent,
|
|
22953
|
-
endpointSortKey(b.from),
|
|
22954
|
-
endpointSortKey(b.to),
|
|
22955
|
-
JSON.stringify(b.condition ?? null),
|
|
22956
|
-
]);
|
|
22957
|
-
}
|
|
22958
|
-
function endpointSortKey(endpoint) {
|
|
22959
|
-
if (endpoint.kind === 'component-port') {
|
|
22960
|
-
return [
|
|
22961
|
-
endpoint.kind,
|
|
22962
|
-
endpoint.ref.widget,
|
|
22963
|
-
endpoint.ref.port,
|
|
22964
|
-
endpoint.ref.direction,
|
|
22965
|
-
endpoint.ref.bindingPath || '',
|
|
22966
|
-
endpoint.ref.componentType || '',
|
|
22967
|
-
JSON.stringify(normalizeNestedPath(endpoint.ref.nestedPath)),
|
|
22968
|
-
].join('|');
|
|
23063
|
+
segmentIdentity(source, index) {
|
|
23064
|
+
const id = typeof source['id'] === 'string' ? source['id'].trim() : '';
|
|
23065
|
+
return {
|
|
23066
|
+
...(id ? { id } : {}),
|
|
23067
|
+
index,
|
|
23068
|
+
};
|
|
22969
23069
|
}
|
|
22970
|
-
|
|
22971
|
-
return [
|
|
22972
|
-
endpoint.kind,
|
|
22973
|
-
endpoint.ref.actionId,
|
|
22974
|
-
endpoint.ref.payloadExpr || '',
|
|
22975
|
-
JSON.stringify(endpoint.ref.payload ?? null),
|
|
22976
|
-
].join('|');
|
|
23070
|
+
asWidgetDefinitions(value) {
|
|
23071
|
+
return Array.isArray(value) ? value : [];
|
|
22977
23072
|
}
|
|
22978
|
-
|
|
22979
|
-
|
|
22980
|
-
|
|
22981
|
-
|
|
22982
|
-
|
|
22983
|
-
|
|
22984
|
-
|
|
22985
|
-
|
|
22986
|
-
|
|
22987
|
-
if (
|
|
22988
|
-
return
|
|
23073
|
+
isWidgetDefinition(value) {
|
|
23074
|
+
return !!value
|
|
23075
|
+
&& typeof value === 'object'
|
|
23076
|
+
&& typeof value.id === 'string';
|
|
23077
|
+
}
|
|
23078
|
+
resolveChildWidgetKey(widget) {
|
|
23079
|
+
return widget.childWidgetKey || '';
|
|
23080
|
+
}
|
|
23081
|
+
clone(value) {
|
|
23082
|
+
if (value == null || typeof value !== 'object') {
|
|
23083
|
+
return value;
|
|
22989
23084
|
}
|
|
23085
|
+
return JSON.parse(JSON.stringify(value));
|
|
22990
23086
|
}
|
|
22991
|
-
|
|
22992
|
-
|
|
22993
|
-
function clone$1(value) {
|
|
22994
|
-
if (value == null || typeof value !== 'object') {
|
|
22995
|
-
return value;
|
|
23087
|
+
isEqual(left, right) {
|
|
23088
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
22996
23089
|
}
|
|
22997
|
-
return JSON.parse(JSON.stringify(value));
|
|
22998
23090
|
}
|
|
22999
23091
|
|
|
23000
|
-
|
|
23001
|
-
|
|
23002
|
-
|
|
23003
|
-
|
|
23004
|
-
}
|
|
23005
|
-
/** Utility: build a natural key from identity fields. */
|
|
23006
|
-
function buildPageKey(identity) {
|
|
23007
|
-
const app = sanitize(identity.appId || 'app');
|
|
23008
|
-
const tenant = sanitize(identity.tenantId || '*');
|
|
23009
|
-
const user = sanitize(identity.userId || '*');
|
|
23010
|
-
const route = sanitize(identity.routePath || '/');
|
|
23011
|
-
const locale = identity.locale ? `:${sanitize(identity.locale)}` : '';
|
|
23012
|
-
return `${app}:${tenant}:${user}:${route}${locale}`;
|
|
23013
|
-
}
|
|
23014
|
-
function sanitize(s) {
|
|
23015
|
-
return String(s).replace(/\s+/g, '_').replace(/[:]/g, '-');
|
|
23016
|
-
}
|
|
23092
|
+
const WIDGET_PAGE_COMPOSITION_SCHEMA_VERSION = '1.0.0';
|
|
23093
|
+
const STRUCTURAL_NESTED_PATH_KINDS$1 = new Set([
|
|
23094
|
+
'nav',
|
|
23095
|
+
]);
|
|
23017
23096
|
/**
|
|
23018
|
-
*
|
|
23019
|
-
*
|
|
23097
|
+
* Normalizes a CompositionLink for deterministic persistence.
|
|
23098
|
+
* Ensures explicit ordering and strips compatibility-only legacy residues.
|
|
23020
23099
|
*/
|
|
23021
|
-
function
|
|
23022
|
-
const
|
|
23023
|
-
id:
|
|
23024
|
-
|
|
23025
|
-
|
|
23026
|
-
|
|
23027
|
-
|
|
23028
|
-
|
|
23029
|
-
|
|
23030
|
-
byKey.set(w.key, w);
|
|
23031
|
-
byId.set(w.id, w);
|
|
23100
|
+
function normalizeCompositionLink(link) {
|
|
23101
|
+
const normalized = {
|
|
23102
|
+
id: link.id,
|
|
23103
|
+
from: normalizeEndpoint(link.from),
|
|
23104
|
+
to: normalizeEndpoint(link.to),
|
|
23105
|
+
intent: link.intent,
|
|
23106
|
+
};
|
|
23107
|
+
if (link.transform) {
|
|
23108
|
+
normalized.transform = clone$1(link.transform);
|
|
23032
23109
|
}
|
|
23033
|
-
|
|
23110
|
+
const condition = normalizeCondition(link.condition);
|
|
23111
|
+
if (condition !== undefined) {
|
|
23112
|
+
normalized.condition = condition;
|
|
23113
|
+
}
|
|
23114
|
+
const policy = normalizePolicy(link.policy);
|
|
23115
|
+
if (policy) {
|
|
23116
|
+
normalized.policy = policy;
|
|
23117
|
+
}
|
|
23118
|
+
const metadata = normalizeMetadata(link.metadata);
|
|
23119
|
+
if (metadata) {
|
|
23120
|
+
normalized.metadata = metadata;
|
|
23121
|
+
}
|
|
23122
|
+
return normalized;
|
|
23034
23123
|
}
|
|
23035
23124
|
/**
|
|
23036
|
-
*
|
|
23125
|
+
* Normalizes an array of CompositionLinks for deterministic persistence.
|
|
23037
23126
|
*/
|
|
23038
|
-
function
|
|
23039
|
-
|
|
23040
|
-
|
|
23041
|
-
|
|
23042
|
-
return {
|
|
23043
|
-
id: opts?.id || generateId(),
|
|
23044
|
-
key: buildPageKey(identity),
|
|
23045
|
-
version: opts?.version || '1.0.0',
|
|
23046
|
-
title: opts?.title,
|
|
23047
|
-
description: opts?.description,
|
|
23048
|
-
tags: opts?.tags || [],
|
|
23049
|
-
identity,
|
|
23050
|
-
status: opts?.status || 'draft',
|
|
23051
|
-
page: pageWithIds,
|
|
23052
|
-
owner: opts?.owner,
|
|
23053
|
-
createdAt: now,
|
|
23054
|
-
updatedAt: now,
|
|
23055
|
-
parentId: opts?.parentId,
|
|
23056
|
-
};
|
|
23127
|
+
function normalizeCompositionLinks(links) {
|
|
23128
|
+
return links
|
|
23129
|
+
.map(normalizeCompositionLink)
|
|
23130
|
+
.sort(compareNormalizedLinks);
|
|
23057
23131
|
}
|
|
23058
|
-
|
|
23059
|
-
|
|
23060
|
-
|
|
23061
|
-
|
|
23062
|
-
|
|
23063
|
-
|
|
23064
|
-
|
|
23065
|
-
|
|
23066
|
-
const DEFAULT_TITLE$1 = 'Governed knowledge timeline';
|
|
23067
|
-
const DEFAULT_EMPTY_TEXT$1 = 'No safe timeline events published for this change-set.';
|
|
23068
|
-
function domainKnowledgeTimelineToRichContentDocument(timeline, options = {}) {
|
|
23132
|
+
/**
|
|
23133
|
+
* Canonical persisted write surface for CompositionLink[].
|
|
23134
|
+
* New saved shapes must serialize links under `composition.links`.
|
|
23135
|
+
* Semantic guards persist only through `link.condition` as Json Logic.
|
|
23136
|
+
* Operational delivery behavior remains under `link.policy` and must not be
|
|
23137
|
+
* folded into the condition payload.
|
|
23138
|
+
*/
|
|
23139
|
+
function serializeCompositionLinks(links) {
|
|
23069
23140
|
return {
|
|
23070
|
-
|
|
23071
|
-
|
|
23072
|
-
nodes: [
|
|
23073
|
-
{
|
|
23074
|
-
type: 'timeline',
|
|
23075
|
-
id: `domain-knowledge-timeline:${timeline.changeSetId}`,
|
|
23076
|
-
title: options.title ?? DEFAULT_TITLE$1,
|
|
23077
|
-
emptyText: options.emptyText ?? DEFAULT_EMPTY_TEXT$1,
|
|
23078
|
-
orientation: 'vertical',
|
|
23079
|
-
position: 'right',
|
|
23080
|
-
connectorVariant: 'solid',
|
|
23081
|
-
connectorColor: 'neutral',
|
|
23082
|
-
markerVariant: 'icon',
|
|
23083
|
-
markerColor: 'info',
|
|
23084
|
-
markerStyle: 'filled',
|
|
23085
|
-
items: timeline.events
|
|
23086
|
-
.filter(isSafeTimelineEvent$1)
|
|
23087
|
-
.map((event, index) => mapTimelineEvent$1(event, index)),
|
|
23088
|
-
},
|
|
23089
|
-
],
|
|
23141
|
+
version: WIDGET_PAGE_COMPOSITION_SCHEMA_VERSION,
|
|
23142
|
+
links: normalizeCompositionLinks(links),
|
|
23090
23143
|
};
|
|
23091
23144
|
}
|
|
23092
|
-
|
|
23093
|
-
|
|
23094
|
-
|
|
23095
|
-
|
|
23096
|
-
|
|
23097
|
-
const
|
|
23098
|
-
const meta = [target, operations].filter((value) => Boolean(value)).join(' | ');
|
|
23145
|
+
/**
|
|
23146
|
+
* Writes the canonical persisted composition surface into a page shape.
|
|
23147
|
+
* The canonical writer omits legacy `connections` to avoid dual-write ambiguity.
|
|
23148
|
+
*/
|
|
23149
|
+
function writeCompositionLinksToPersistedPage(page, links) {
|
|
23150
|
+
const { composition: _legacyComposition, ...rest } = stripRuntimeOnlyState(clone$1(page), links);
|
|
23099
23151
|
return {
|
|
23100
|
-
|
|
23101
|
-
|
|
23102
|
-
subtitle: event.actor ? `${event.actorType ?? 'actor'}: ${event.actor}` : event.actorType ?? undefined,
|
|
23103
|
-
opposite: event.occurredAt ?? undefined,
|
|
23104
|
-
meta: meta || undefined,
|
|
23105
|
-
badge: event.validationStatus ?? event.status ?? event.eventType,
|
|
23106
|
-
icon: iconForEvent$1(event.eventType),
|
|
23107
|
-
markerColor: markerColorForEvent$1(event.eventType),
|
|
23108
|
-
connectorColor: markerColorForEvent$1(event.eventType),
|
|
23152
|
+
...rest,
|
|
23153
|
+
composition: serializeCompositionLinks(links),
|
|
23109
23154
|
};
|
|
23110
23155
|
}
|
|
23111
|
-
function
|
|
23112
|
-
const
|
|
23113
|
-
|
|
23114
|
-
|
|
23115
|
-
|
|
23116
|
-
|
|
23117
|
-
|
|
23118
|
-
|
|
23119
|
-
const operationTypes = event.operationTypes?.filter(Boolean) ?? [];
|
|
23120
|
-
if (!operationTypes.length && event.operationCount == null) {
|
|
23121
|
-
return null;
|
|
23122
|
-
}
|
|
23123
|
-
const count = event.operationCount == null ? null : `${event.operationCount} operation${event.operationCount === 1 ? '' : 's'}`;
|
|
23124
|
-
const types = operationTypes.length ? operationTypes.join(', ') : null;
|
|
23125
|
-
return [count, types].filter((value) => Boolean(value)).join(': ') || null;
|
|
23126
|
-
}
|
|
23127
|
-
function iconForEvent$1(eventType) {
|
|
23128
|
-
if (eventType.includes('applied')) {
|
|
23129
|
-
return 'published_with_changes';
|
|
23130
|
-
}
|
|
23131
|
-
if (eventType.includes('approved')) {
|
|
23132
|
-
return 'verified';
|
|
23133
|
-
}
|
|
23134
|
-
if (eventType.includes('rejected')) {
|
|
23135
|
-
return 'block';
|
|
23156
|
+
function stripRuntimeOnlyState(page, links) {
|
|
23157
|
+
const stateSchema = page.state?.schema || {};
|
|
23158
|
+
const nonPersistentPaths = Object.keys(stateSchema)
|
|
23159
|
+
.filter((path) => stateSchema[path]?.persist === false)
|
|
23160
|
+
.map((path) => path.trim())
|
|
23161
|
+
.filter(Boolean);
|
|
23162
|
+
if (!nonPersistentPaths.length) {
|
|
23163
|
+
return page;
|
|
23136
23164
|
}
|
|
23137
|
-
|
|
23138
|
-
|
|
23165
|
+
const next = clone$1(page);
|
|
23166
|
+
if (next.state?.values) {
|
|
23167
|
+
for (const path of nonPersistentPaths) {
|
|
23168
|
+
removeValueAtPath(next.state.values, path);
|
|
23169
|
+
}
|
|
23139
23170
|
}
|
|
23140
|
-
|
|
23141
|
-
|
|
23171
|
+
const accessor = new NestedWidgetConfigAccessor();
|
|
23172
|
+
for (const link of links) {
|
|
23173
|
+
const source = link.from;
|
|
23174
|
+
const target = link.to;
|
|
23175
|
+
if (source.kind !== 'state' || target.kind !== 'component-port') {
|
|
23176
|
+
continue;
|
|
23177
|
+
}
|
|
23178
|
+
if (!nonPersistentPaths.some((path) => isPathWithin(source.ref.path, path))) {
|
|
23179
|
+
continue;
|
|
23180
|
+
}
|
|
23181
|
+
const widgetIndex = next.widgets?.findIndex((widget) => widget.key === target.ref.widget) ?? -1;
|
|
23182
|
+
if (widgetIndex < 0 || !next.widgets) {
|
|
23183
|
+
continue;
|
|
23184
|
+
}
|
|
23185
|
+
if (target.ref.nestedPath?.length) {
|
|
23186
|
+
const result = accessor.removeNestedWidgetInput(next.widgets[widgetIndex], target.ref.nestedPath, target.ref.port);
|
|
23187
|
+
if (result.changed) {
|
|
23188
|
+
next.widgets[widgetIndex] = result.widget;
|
|
23189
|
+
}
|
|
23190
|
+
continue;
|
|
23191
|
+
}
|
|
23192
|
+
const inputPath = target.ref.bindingPath || target.ref.port;
|
|
23193
|
+
const inputs = next.widgets[widgetIndex].definition.inputs;
|
|
23194
|
+
if (inputs) {
|
|
23195
|
+
removeValueAtPath(inputs, inputPath);
|
|
23196
|
+
}
|
|
23142
23197
|
}
|
|
23143
|
-
return
|
|
23198
|
+
return next;
|
|
23144
23199
|
}
|
|
23145
|
-
function
|
|
23146
|
-
|
|
23147
|
-
|
|
23148
|
-
|
|
23149
|
-
|
|
23150
|
-
|
|
23200
|
+
function isPathWithin(candidate, parent) {
|
|
23201
|
+
return candidate === parent || candidate.startsWith(`${parent}.`);
|
|
23202
|
+
}
|
|
23203
|
+
function removeValueAtPath(target, path) {
|
|
23204
|
+
const segments = String(path || '')
|
|
23205
|
+
.split('.')
|
|
23206
|
+
.map((segment) => segment.trim())
|
|
23207
|
+
.filter(Boolean);
|
|
23208
|
+
if (!segments.length) {
|
|
23209
|
+
return;
|
|
23151
23210
|
}
|
|
23152
|
-
|
|
23153
|
-
|
|
23211
|
+
let current = target;
|
|
23212
|
+
for (const segment of segments.slice(0, -1)) {
|
|
23213
|
+
const next = current[segment];
|
|
23214
|
+
if (!next || typeof next !== 'object' || Array.isArray(next)) {
|
|
23215
|
+
return;
|
|
23216
|
+
}
|
|
23217
|
+
current = next;
|
|
23154
23218
|
}
|
|
23155
|
-
|
|
23156
|
-
|
|
23219
|
+
delete current[segments[segments.length - 1]];
|
|
23220
|
+
}
|
|
23221
|
+
function normalizeEndpoint(endpoint) {
|
|
23222
|
+
if (endpoint.kind === 'component-port') {
|
|
23223
|
+
const nestedPath = normalizeNestedPath(endpoint.ref.nestedPath);
|
|
23224
|
+
return {
|
|
23225
|
+
kind: 'component-port',
|
|
23226
|
+
ref: {
|
|
23227
|
+
widget: endpoint.ref.widget,
|
|
23228
|
+
port: endpoint.ref.port,
|
|
23229
|
+
direction: endpoint.ref.direction,
|
|
23230
|
+
...(endpoint.ref.componentType ? { componentType: endpoint.ref.componentType } : {}),
|
|
23231
|
+
...(endpoint.ref.bindingPath ? { bindingPath: endpoint.ref.bindingPath } : {}),
|
|
23232
|
+
...(nestedPath.length ? { nestedPath } : {}),
|
|
23233
|
+
},
|
|
23234
|
+
};
|
|
23157
23235
|
}
|
|
23158
|
-
if (
|
|
23159
|
-
return
|
|
23236
|
+
if (endpoint.kind === 'global-action') {
|
|
23237
|
+
return {
|
|
23238
|
+
kind: 'global-action',
|
|
23239
|
+
ref: normalizeGlobalActionRef(endpoint.ref),
|
|
23240
|
+
};
|
|
23160
23241
|
}
|
|
23161
|
-
return
|
|
23242
|
+
return {
|
|
23243
|
+
kind: 'state',
|
|
23244
|
+
ref: {
|
|
23245
|
+
path: endpoint.ref.path,
|
|
23246
|
+
...(endpoint.ref.layer ? { layer: endpoint.ref.layer } : {}),
|
|
23247
|
+
},
|
|
23248
|
+
};
|
|
23162
23249
|
}
|
|
23163
|
-
|
|
23164
|
-
const DEFAULT_TITLE = 'Governed decision timeline';
|
|
23165
|
-
const DEFAULT_EMPTY_TEXT = 'No safe timeline events published for this decision.';
|
|
23166
|
-
function domainRuleTimelineToRichContentDocument(timeline, options = {}) {
|
|
23250
|
+
function normalizeGlobalActionRef(ref) {
|
|
23167
23251
|
return {
|
|
23168
|
-
|
|
23169
|
-
|
|
23170
|
-
|
|
23171
|
-
|
|
23172
|
-
type: 'timeline',
|
|
23173
|
-
id: `domain-rule-timeline:${timeline.ruleDefinitionId}`,
|
|
23174
|
-
title: options.title ?? DEFAULT_TITLE,
|
|
23175
|
-
emptyText: options.emptyText ?? DEFAULT_EMPTY_TEXT,
|
|
23176
|
-
orientation: 'vertical',
|
|
23177
|
-
position: 'right',
|
|
23178
|
-
connectorVariant: 'solid',
|
|
23179
|
-
connectorColor: 'neutral',
|
|
23180
|
-
markerVariant: 'icon',
|
|
23181
|
-
markerColor: 'info',
|
|
23182
|
-
markerStyle: 'filled',
|
|
23183
|
-
items: timeline.events
|
|
23184
|
-
.filter(isSafeTimelineEvent)
|
|
23185
|
-
.map((event, index) => mapTimelineEvent(event, index)),
|
|
23186
|
-
},
|
|
23187
|
-
],
|
|
23252
|
+
actionId: String(ref.actionId || '').trim(),
|
|
23253
|
+
...(ref.payload !== undefined ? { payload: clone$1(ref.payload) } : {}),
|
|
23254
|
+
...(ref.payloadExpr ? { payloadExpr: String(ref.payloadExpr).trim() } : {}),
|
|
23255
|
+
...(ref.meta && typeof ref.meta === 'object' ? { meta: { ...ref.meta } } : {}),
|
|
23188
23256
|
};
|
|
23189
23257
|
}
|
|
23190
|
-
function
|
|
23191
|
-
|
|
23258
|
+
function normalizeNestedPath(nestedPath) {
|
|
23259
|
+
if (!nestedPath?.length) {
|
|
23260
|
+
return [];
|
|
23261
|
+
}
|
|
23262
|
+
return nestedPath
|
|
23263
|
+
.map((segment) => {
|
|
23264
|
+
const normalized = {
|
|
23265
|
+
kind: segment.kind,
|
|
23266
|
+
};
|
|
23267
|
+
if (segment.id) {
|
|
23268
|
+
normalized.id = segment.id;
|
|
23269
|
+
}
|
|
23270
|
+
if (segment.key) {
|
|
23271
|
+
normalized.key = segment.key;
|
|
23272
|
+
}
|
|
23273
|
+
if (typeof segment.index === 'number' && Number.isFinite(segment.index)) {
|
|
23274
|
+
normalized.index = Math.trunc(segment.index);
|
|
23275
|
+
}
|
|
23276
|
+
if (segment.componentType) {
|
|
23277
|
+
normalized.componentType = segment.componentType;
|
|
23278
|
+
}
|
|
23279
|
+
return normalized;
|
|
23280
|
+
})
|
|
23281
|
+
.filter((segment) => !!segment.kind
|
|
23282
|
+
&& (!!segment.id
|
|
23283
|
+
|| !!segment.key
|
|
23284
|
+
|| typeof segment.index === 'number'
|
|
23285
|
+
|| !!segment.componentType
|
|
23286
|
+
|| segment.kind === 'widget'
|
|
23287
|
+
|| STRUCTURAL_NESTED_PATH_KINDS$1.has(segment.kind)));
|
|
23192
23288
|
}
|
|
23193
|
-
function
|
|
23194
|
-
|
|
23195
|
-
|
|
23196
|
-
|
|
23197
|
-
|
|
23198
|
-
|
|
23199
|
-
|
|
23200
|
-
|
|
23201
|
-
opposite: event.occurredAt ?? undefined,
|
|
23202
|
-
meta: meta || undefined,
|
|
23203
|
-
badge: event.targetLayer ?? event.eventType,
|
|
23204
|
-
icon: iconForEvent(event.eventType),
|
|
23205
|
-
markerColor: markerColorForEvent(event.eventType),
|
|
23206
|
-
connectorColor: markerColorForEvent(event.eventType),
|
|
23207
|
-
};
|
|
23289
|
+
function normalizeCondition(condition) {
|
|
23290
|
+
if (condition === undefined) {
|
|
23291
|
+
return undefined;
|
|
23292
|
+
}
|
|
23293
|
+
if (condition === null) {
|
|
23294
|
+
return null;
|
|
23295
|
+
}
|
|
23296
|
+
return clone$1(condition);
|
|
23208
23297
|
}
|
|
23209
|
-
function
|
|
23210
|
-
|
|
23211
|
-
|
|
23212
|
-
|
|
23213
|
-
|
|
23214
|
-
|
|
23215
|
-
|
|
23298
|
+
function normalizePolicy(policy) {
|
|
23299
|
+
if (!policy) {
|
|
23300
|
+
return undefined;
|
|
23301
|
+
}
|
|
23302
|
+
const normalized = {
|
|
23303
|
+
...(policy.debounceMs !== undefined ? { debounceMs: policy.debounceMs } : {}),
|
|
23304
|
+
...(policy.distinct !== undefined ? { distinct: policy.distinct } : {}),
|
|
23305
|
+
...(policy.distinctBy ? { distinctBy: policy.distinctBy } : {}),
|
|
23306
|
+
...(policy.delivery ? { delivery: policy.delivery } : {}),
|
|
23307
|
+
...(policy.missingValuePolicy ? { missingValuePolicy: policy.missingValuePolicy } : {}),
|
|
23308
|
+
...(policy.errorPolicy ? { errorPolicy: policy.errorPolicy } : {}),
|
|
23309
|
+
};
|
|
23310
|
+
return Object.keys(normalized).length ? normalized : undefined;
|
|
23216
23311
|
}
|
|
23217
|
-
function
|
|
23218
|
-
if (
|
|
23219
|
-
return
|
|
23312
|
+
function normalizeMetadata(metadata) {
|
|
23313
|
+
if (!metadata) {
|
|
23314
|
+
return undefined;
|
|
23220
23315
|
}
|
|
23221
|
-
|
|
23222
|
-
|
|
23316
|
+
const tags = metadata.tags?.length
|
|
23317
|
+
? [...metadata.tags].sort((a, b) => a.localeCompare(b))
|
|
23318
|
+
: undefined;
|
|
23319
|
+
const source = metadata.source === 'legacy-widget-connection'
|
|
23320
|
+
? undefined
|
|
23321
|
+
: metadata.source;
|
|
23322
|
+
const normalized = {
|
|
23323
|
+
...(metadata.label ? { label: metadata.label } : {}),
|
|
23324
|
+
...(metadata.description ? { description: metadata.description } : {}),
|
|
23325
|
+
...(tags?.length ? { tags } : {}),
|
|
23326
|
+
...(metadata.deprecated !== undefined ? { deprecated: metadata.deprecated } : {}),
|
|
23327
|
+
...(source ? { source } : {}),
|
|
23328
|
+
};
|
|
23329
|
+
return Object.keys(normalized).length ? normalized : undefined;
|
|
23330
|
+
}
|
|
23331
|
+
function compareNormalizedLinks(a, b) {
|
|
23332
|
+
return compareValues([
|
|
23333
|
+
a.id,
|
|
23334
|
+
a.intent,
|
|
23335
|
+
endpointSortKey(a.from),
|
|
23336
|
+
endpointSortKey(a.to),
|
|
23337
|
+
JSON.stringify(a.condition ?? null),
|
|
23338
|
+
], [
|
|
23339
|
+
b.id,
|
|
23340
|
+
b.intent,
|
|
23341
|
+
endpointSortKey(b.from),
|
|
23342
|
+
endpointSortKey(b.to),
|
|
23343
|
+
JSON.stringify(b.condition ?? null),
|
|
23344
|
+
]);
|
|
23345
|
+
}
|
|
23346
|
+
function endpointSortKey(endpoint) {
|
|
23347
|
+
if (endpoint.kind === 'component-port') {
|
|
23348
|
+
return [
|
|
23349
|
+
endpoint.kind,
|
|
23350
|
+
endpoint.ref.widget,
|
|
23351
|
+
endpoint.ref.port,
|
|
23352
|
+
endpoint.ref.direction,
|
|
23353
|
+
endpoint.ref.bindingPath || '',
|
|
23354
|
+
endpoint.ref.componentType || '',
|
|
23355
|
+
JSON.stringify(normalizeNestedPath(endpoint.ref.nestedPath)),
|
|
23356
|
+
].join('|');
|
|
23223
23357
|
}
|
|
23224
|
-
if (
|
|
23225
|
-
return
|
|
23358
|
+
if (endpoint.kind === 'global-action') {
|
|
23359
|
+
return [
|
|
23360
|
+
endpoint.kind,
|
|
23361
|
+
endpoint.ref.actionId,
|
|
23362
|
+
endpoint.ref.payloadExpr || '',
|
|
23363
|
+
JSON.stringify(endpoint.ref.payload ?? null),
|
|
23364
|
+
].join('|');
|
|
23226
23365
|
}
|
|
23227
|
-
return
|
|
23366
|
+
return [
|
|
23367
|
+
endpoint.kind,
|
|
23368
|
+
endpoint.ref.path,
|
|
23369
|
+
endpoint.ref.layer || '',
|
|
23370
|
+
].join('|');
|
|
23228
23371
|
}
|
|
23229
|
-
function
|
|
23230
|
-
|
|
23231
|
-
|
|
23232
|
-
|
|
23233
|
-
|
|
23234
|
-
|
|
23372
|
+
function compareValues(left, right) {
|
|
23373
|
+
for (let index = 0; index < Math.max(left.length, right.length); index += 1) {
|
|
23374
|
+
const comparison = (left[index] || '').localeCompare(right[index] || '');
|
|
23375
|
+
if (comparison !== 0) {
|
|
23376
|
+
return comparison;
|
|
23377
|
+
}
|
|
23235
23378
|
}
|
|
23236
|
-
|
|
23237
|
-
|
|
23379
|
+
return 0;
|
|
23380
|
+
}
|
|
23381
|
+
function clone$1(value) {
|
|
23382
|
+
if (value == null || typeof value !== 'object') {
|
|
23383
|
+
return value;
|
|
23238
23384
|
}
|
|
23239
|
-
return
|
|
23385
|
+
return JSON.parse(JSON.stringify(value));
|
|
23240
23386
|
}
|
|
23241
23387
|
|
|
23242
|
-
|
|
23243
|
-
|
|
23244
|
-
const
|
|
23245
|
-
|
|
23246
|
-
'notEquals',
|
|
23247
|
-
'in',
|
|
23248
|
-
'notIn',
|
|
23249
|
-
'contains',
|
|
23250
|
-
'startsWith',
|
|
23251
|
-
'between',
|
|
23252
|
-
'gte',
|
|
23253
|
-
'lte',
|
|
23254
|
-
'isNull',
|
|
23255
|
-
'isNotNull',
|
|
23256
|
-
]);
|
|
23257
|
-
const PRAXIS_QUERY_FILTER_PREDICATE_SOURCE_KINDS = new Set([
|
|
23258
|
-
'selected-records',
|
|
23259
|
-
'manual',
|
|
23260
|
-
'workflow',
|
|
23261
|
-
'current-context',
|
|
23262
|
-
]);
|
|
23263
|
-
const PRAXIS_QUERY_FILTER_GOVERNANCE_SOURCES = new Set([
|
|
23264
|
-
'selected-records',
|
|
23265
|
-
'manual',
|
|
23266
|
-
'workflow',
|
|
23267
|
-
'ai-authored',
|
|
23268
|
-
]);
|
|
23269
|
-
function normalizeRecord(record) {
|
|
23270
|
-
if (!record || typeof record !== 'object')
|
|
23271
|
-
return null;
|
|
23272
|
-
const next = Object.entries(record).reduce((acc, [key, value]) => {
|
|
23273
|
-
if (value === null || value === undefined)
|
|
23274
|
-
return acc;
|
|
23275
|
-
if (Array.isArray(value) && value.length === 0)
|
|
23276
|
-
return acc;
|
|
23277
|
-
if (typeof value === 'string' && value.trim() === '')
|
|
23278
|
-
return acc;
|
|
23279
|
-
acc[key] = value;
|
|
23280
|
-
return acc;
|
|
23281
|
-
}, {});
|
|
23282
|
-
return Object.keys(next).length ? next : null;
|
|
23388
|
+
/** Utility: generate a random id using crypto.randomUUID or fallback. */
|
|
23389
|
+
function generateId() {
|
|
23390
|
+
const g = globalThis.crypto?.randomUUID?.();
|
|
23391
|
+
return g || `id_${Math.random().toString(36).slice(2, 10)}_${Date.now().toString(36)}`;
|
|
23283
23392
|
}
|
|
23284
|
-
|
|
23285
|
-
|
|
23286
|
-
|
|
23287
|
-
|
|
23288
|
-
|
|
23289
|
-
|
|
23290
|
-
|
|
23291
|
-
return
|
|
23393
|
+
/** Utility: build a natural key from identity fields. */
|
|
23394
|
+
function buildPageKey(identity) {
|
|
23395
|
+
const app = sanitize(identity.appId || 'app');
|
|
23396
|
+
const tenant = sanitize(identity.tenantId || '*');
|
|
23397
|
+
const user = sanitize(identity.userId || '*');
|
|
23398
|
+
const route = sanitize(identity.routePath || '/');
|
|
23399
|
+
const locale = identity.locale ? `:${sanitize(identity.locale)}` : '';
|
|
23400
|
+
return `${app}:${tenant}:${user}:${route}${locale}`;
|
|
23292
23401
|
}
|
|
23293
|
-
function
|
|
23294
|
-
|
|
23295
|
-
return null;
|
|
23296
|
-
const kind = typeof source['kind'] === 'string' ? source['kind'].trim() : '';
|
|
23297
|
-
if (!PRAXIS_QUERY_FILTER_PREDICATE_SOURCE_KINDS.has(kind))
|
|
23298
|
-
return null;
|
|
23299
|
-
const field = typeof source['field'] === 'string' && source['field'].trim()
|
|
23300
|
-
? source['field'].trim()
|
|
23301
|
-
: null;
|
|
23302
|
-
const selectedIds = Array.isArray(source['selectedIds'])
|
|
23303
|
-
? source['selectedIds'].filter((id) => (typeof id === 'string' && id.trim() !== '') ||
|
|
23304
|
-
(typeof id === 'number' && Number.isFinite(id)))
|
|
23305
|
-
: [];
|
|
23306
|
-
return {
|
|
23307
|
-
kind: kind,
|
|
23308
|
-
...(field ? { field } : {}),
|
|
23309
|
-
...(selectedIds.length ? { selectedIds } : {}),
|
|
23310
|
-
};
|
|
23402
|
+
function sanitize(s) {
|
|
23403
|
+
return String(s).replace(/\s+/g, '_').replace(/[:]/g, '-');
|
|
23311
23404
|
}
|
|
23312
|
-
|
|
23313
|
-
|
|
23314
|
-
|
|
23315
|
-
|
|
23316
|
-
|
|
23317
|
-
|
|
23318
|
-
:
|
|
23319
|
-
|
|
23320
|
-
|
|
23321
|
-
|
|
23322
|
-
const
|
|
23323
|
-
|
|
23324
|
-
|
|
23325
|
-
|
|
23326
|
-
|
|
23327
|
-
next.decisionId = decisionId;
|
|
23328
|
-
if (explanation)
|
|
23329
|
-
next.explanation = explanation;
|
|
23330
|
-
return Object.keys(next).length ? next : null;
|
|
23331
|
-
}
|
|
23332
|
-
function normalizePraxisQueryFilterNode(node) {
|
|
23333
|
-
if (!node || typeof node !== 'object')
|
|
23334
|
-
return null;
|
|
23335
|
-
const kind = typeof node['kind'] === 'string' ? node['kind'].trim() : '';
|
|
23336
|
-
if (kind === 'group') {
|
|
23337
|
-
const operator = typeof node['operator'] === 'string' ? node['operator'].trim() : '';
|
|
23338
|
-
if (!PRAXIS_QUERY_FILTER_GROUP_OPERATORS.has(operator))
|
|
23339
|
-
return null;
|
|
23340
|
-
const clauses = Array.isArray(node['clauses'])
|
|
23341
|
-
? node['clauses']
|
|
23342
|
-
.map((clause) => normalizePraxisQueryFilterNode(clause))
|
|
23343
|
-
.filter((clause) => !!clause)
|
|
23344
|
-
: [];
|
|
23345
|
-
if (!clauses.length)
|
|
23346
|
-
return null;
|
|
23347
|
-
return {
|
|
23348
|
-
kind: 'group',
|
|
23349
|
-
operator: operator,
|
|
23350
|
-
clauses,
|
|
23351
|
-
};
|
|
23352
|
-
}
|
|
23353
|
-
if (kind === 'predicate') {
|
|
23354
|
-
const field = typeof node['field'] === 'string' ? node['field'].trim() : '';
|
|
23355
|
-
const operator = typeof node['operator'] === 'string' ? node['operator'].trim() : '';
|
|
23356
|
-
if (!field || !PRAXIS_QUERY_FILTER_PREDICATE_OPERATORS.has(operator))
|
|
23357
|
-
return null;
|
|
23358
|
-
const values = Array.isArray(node['values'])
|
|
23359
|
-
? node['values'].filter((value) => isMeaningfulQueryFilterValue(value))
|
|
23360
|
-
: [];
|
|
23361
|
-
const hasValue = isMeaningfulQueryFilterValue(node['value']);
|
|
23362
|
-
const label = typeof node['label'] === 'string' && node['label'].trim()
|
|
23363
|
-
? node['label'].trim()
|
|
23364
|
-
: null;
|
|
23365
|
-
const source = normalizeQueryFilterSource(node['source']);
|
|
23366
|
-
return {
|
|
23367
|
-
kind: 'predicate',
|
|
23368
|
-
field,
|
|
23369
|
-
operator: operator,
|
|
23370
|
-
...(hasValue ? { value: node['value'] } : {}),
|
|
23371
|
-
...(values.length ? { values } : {}),
|
|
23372
|
-
...(label ? { label } : {}),
|
|
23373
|
-
...(source ? { source } : {}),
|
|
23374
|
-
};
|
|
23405
|
+
/**
|
|
23406
|
+
* Ensure that each widget has a stable id. If missing, assigns a new one.
|
|
23407
|
+
* Returns the new page definition (immutable) and an index by key/id.
|
|
23408
|
+
*/
|
|
23409
|
+
function ensurePageIds(page) {
|
|
23410
|
+
const widgets = (page.widgets || []).map((w) => ({
|
|
23411
|
+
id: w.id || generateId(),
|
|
23412
|
+
...w,
|
|
23413
|
+
}));
|
|
23414
|
+
const withIds = { ...page, widgets };
|
|
23415
|
+
const byKey = new Map();
|
|
23416
|
+
const byId = new Map();
|
|
23417
|
+
for (const w of widgets) {
|
|
23418
|
+
byKey.set(w.key, w);
|
|
23419
|
+
byId.set(w.id, w);
|
|
23375
23420
|
}
|
|
23376
|
-
return
|
|
23421
|
+
return { page: withIds, byKey, byId };
|
|
23377
23422
|
}
|
|
23378
|
-
|
|
23379
|
-
|
|
23380
|
-
|
|
23381
|
-
|
|
23382
|
-
|
|
23383
|
-
const
|
|
23384
|
-
|
|
23385
|
-
return null;
|
|
23386
|
-
const projection = expression.projection && typeof expression.projection === 'object'
|
|
23387
|
-
? {
|
|
23388
|
-
filters: normalizeRecord(expression.projection.filters),
|
|
23389
|
-
lossless: expression.projection.lossless === true,
|
|
23390
|
-
reason: typeof expression.projection.reason === 'string' && expression.projection.reason.trim()
|
|
23391
|
-
? expression.projection.reason.trim()
|
|
23392
|
-
: undefined,
|
|
23393
|
-
}
|
|
23394
|
-
: null;
|
|
23395
|
-
const governance = normalizeQueryFilterGovernance(expression.governance);
|
|
23423
|
+
/**
|
|
23424
|
+
* Create a persisted page record from an in-memory page definition and identity.
|
|
23425
|
+
*/
|
|
23426
|
+
function createPersistedPage(identity, page, opts) {
|
|
23427
|
+
const persistedPage = writeCompositionLinksToPersistedPage(page, page.composition?.links || []);
|
|
23428
|
+
const { page: pageWithIds } = ensurePageIds(persistedPage);
|
|
23429
|
+
const now = new Date().toISOString();
|
|
23396
23430
|
return {
|
|
23397
|
-
|
|
23398
|
-
|
|
23399
|
-
|
|
23400
|
-
|
|
23401
|
-
|
|
23402
|
-
|
|
23403
|
-
|
|
23431
|
+
id: opts?.id || generateId(),
|
|
23432
|
+
key: buildPageKey(identity),
|
|
23433
|
+
version: opts?.version || '1.0.0',
|
|
23434
|
+
title: opts?.title,
|
|
23435
|
+
description: opts?.description,
|
|
23436
|
+
tags: opts?.tags || [],
|
|
23437
|
+
identity,
|
|
23438
|
+
status: opts?.status || 'draft',
|
|
23439
|
+
page: pageWithIds,
|
|
23440
|
+
owner: opts?.owner,
|
|
23441
|
+
createdAt: now,
|
|
23442
|
+
updatedAt: now,
|
|
23443
|
+
parentId: opts?.parentId,
|
|
23444
|
+
};
|
|
23445
|
+
}
|
|
23446
|
+
|
|
23447
|
+
// Global configuration model for cross-library defaults
|
|
23448
|
+
// Designed to be minimal and avoid coupling to feature-library types
|
|
23449
|
+
|
|
23450
|
+
// Global Dialog domain types for GlobalConfig (kept independent of @praxisui/dialog types)
|
|
23451
|
+
|
|
23452
|
+
const DOMAIN_CATALOG_CONTEXT_HINT_SCHEMA_VERSION = 'praxis.ai.context-hints.domain-catalog/v0.2';
|
|
23453
|
+
|
|
23454
|
+
const DEFAULT_TITLE$1 = 'Governed knowledge timeline';
|
|
23455
|
+
const DEFAULT_EMPTY_TEXT$1 = 'No safe timeline events published for this change-set.';
|
|
23456
|
+
function domainKnowledgeTimelineToRichContentDocument(timeline, options = {}) {
|
|
23457
|
+
return {
|
|
23458
|
+
kind: 'praxis.rich-content',
|
|
23459
|
+
version: '1.0.0',
|
|
23460
|
+
nodes: [
|
|
23461
|
+
{
|
|
23462
|
+
type: 'timeline',
|
|
23463
|
+
id: `domain-knowledge-timeline:${timeline.changeSetId}`,
|
|
23464
|
+
title: options.title ?? DEFAULT_TITLE$1,
|
|
23465
|
+
emptyText: options.emptyText ?? DEFAULT_EMPTY_TEXT$1,
|
|
23466
|
+
orientation: 'vertical',
|
|
23467
|
+
position: 'right',
|
|
23468
|
+
connectorVariant: 'solid',
|
|
23469
|
+
connectorColor: 'neutral',
|
|
23470
|
+
markerVariant: 'icon',
|
|
23471
|
+
markerColor: 'info',
|
|
23472
|
+
markerStyle: 'filled',
|
|
23473
|
+
items: timeline.events
|
|
23474
|
+
.filter(isSafeTimelineEvent$1)
|
|
23475
|
+
.map((event, index) => mapTimelineEvent$1(event, index)),
|
|
23404
23476
|
},
|
|
23405
|
-
|
|
23406
|
-
...(governance ? { governance } : {}),
|
|
23477
|
+
],
|
|
23407
23478
|
};
|
|
23408
23479
|
}
|
|
23409
|
-
function
|
|
23410
|
-
|
|
23411
|
-
return null;
|
|
23412
|
-
const filters = normalizeRecord(context.filters);
|
|
23413
|
-
const filterExpression = normalizePraxisQueryFilterExpression(context.filterExpression);
|
|
23414
|
-
const meta = normalizeRecord(context.meta);
|
|
23415
|
-
const sort = Array.isArray(context.sort)
|
|
23416
|
-
? context.sort
|
|
23417
|
-
.map((item) => (typeof item === 'string' ? item.trim() : ''))
|
|
23418
|
-
.filter((item) => item.length > 0)
|
|
23419
|
-
: [];
|
|
23420
|
-
const limit = typeof context.limit === 'number' && Number.isFinite(context.limit)
|
|
23421
|
-
? Math.max(0, Math.trunc(context.limit))
|
|
23422
|
-
: null;
|
|
23423
|
-
const page = context.page && typeof context.page === 'object'
|
|
23424
|
-
? {
|
|
23425
|
-
index: typeof context.page.index === 'number' && Number.isFinite(context.page.index)
|
|
23426
|
-
? Math.max(0, Math.trunc(context.page.index))
|
|
23427
|
-
: null,
|
|
23428
|
-
size: typeof context.page.size === 'number' && Number.isFinite(context.page.size)
|
|
23429
|
-
? Math.max(0, Math.trunc(context.page.size))
|
|
23430
|
-
: null,
|
|
23431
|
-
}
|
|
23432
|
-
: null;
|
|
23433
|
-
const next = {};
|
|
23434
|
-
if (filters)
|
|
23435
|
-
next.filters = filters;
|
|
23436
|
-
if (filterExpression)
|
|
23437
|
-
next.filterExpression = filterExpression;
|
|
23438
|
-
if (sort.length)
|
|
23439
|
-
next.sort = sort;
|
|
23440
|
-
if (limit !== null)
|
|
23441
|
-
next.limit = limit;
|
|
23442
|
-
if (page && (page.index !== null || page.size !== null))
|
|
23443
|
-
next.page = page;
|
|
23444
|
-
if (meta)
|
|
23445
|
-
next.meta = meta;
|
|
23446
|
-
return Object.keys(next).length ? next : null;
|
|
23480
|
+
function isSafeTimelineEvent$1(event) {
|
|
23481
|
+
return event.visibility === 'safe';
|
|
23447
23482
|
}
|
|
23448
|
-
function
|
|
23449
|
-
const
|
|
23450
|
-
const
|
|
23483
|
+
function mapTimelineEvent$1(event, index) {
|
|
23484
|
+
const target = formatTarget$1(event);
|
|
23485
|
+
const operations = formatOperations(event);
|
|
23486
|
+
const meta = [target, operations].filter((value) => Boolean(value)).join(' | ');
|
|
23451
23487
|
return {
|
|
23452
|
-
|
|
23453
|
-
|
|
23488
|
+
id: `domain-knowledge-timeline-event:${index}:${event.eventType}`,
|
|
23489
|
+
title: event.summary || event.eventType,
|
|
23490
|
+
subtitle: event.actor ? `${event.actorType ?? 'actor'}: ${event.actor}` : event.actorType ?? undefined,
|
|
23491
|
+
opposite: event.occurredAt ?? undefined,
|
|
23492
|
+
meta: meta || undefined,
|
|
23493
|
+
badge: event.validationStatus ?? event.status ?? event.eventType,
|
|
23494
|
+
icon: iconForEvent$1(event.eventType),
|
|
23495
|
+
markerColor: markerColorForEvent$1(event.eventType),
|
|
23496
|
+
connectorColor: markerColorForEvent$1(event.eventType),
|
|
23454
23497
|
};
|
|
23455
23498
|
}
|
|
23499
|
+
function formatTarget$1(event) {
|
|
23500
|
+
const keys = event.targetConceptKeys?.filter(Boolean) ?? [];
|
|
23501
|
+
if (!keys.length) {
|
|
23502
|
+
return null;
|
|
23503
|
+
}
|
|
23504
|
+
return `${keys.length} governed concept${keys.length === 1 ? '' : 's'}`;
|
|
23505
|
+
}
|
|
23506
|
+
function formatOperations(event) {
|
|
23507
|
+
const operationTypes = event.operationTypes?.filter(Boolean) ?? [];
|
|
23508
|
+
if (!operationTypes.length && event.operationCount == null) {
|
|
23509
|
+
return null;
|
|
23510
|
+
}
|
|
23511
|
+
const count = event.operationCount == null ? null : `${event.operationCount} operation${event.operationCount === 1 ? '' : 's'}`;
|
|
23512
|
+
const types = operationTypes.length ? operationTypes.join(', ') : null;
|
|
23513
|
+
return [count, types].filter((value) => Boolean(value)).join(': ') || null;
|
|
23514
|
+
}
|
|
23515
|
+
function iconForEvent$1(eventType) {
|
|
23516
|
+
if (eventType.includes('applied')) {
|
|
23517
|
+
return 'published_with_changes';
|
|
23518
|
+
}
|
|
23519
|
+
if (eventType.includes('approved')) {
|
|
23520
|
+
return 'verified';
|
|
23521
|
+
}
|
|
23522
|
+
if (eventType.includes('rejected')) {
|
|
23523
|
+
return 'block';
|
|
23524
|
+
}
|
|
23525
|
+
if (eventType.includes('validation')) {
|
|
23526
|
+
return 'rule';
|
|
23527
|
+
}
|
|
23528
|
+
if (eventType.includes('created')) {
|
|
23529
|
+
return 'add_circle';
|
|
23530
|
+
}
|
|
23531
|
+
return 'timeline';
|
|
23532
|
+
}
|
|
23533
|
+
function markerColorForEvent$1(eventType) {
|
|
23534
|
+
if (eventType.includes('applied')) {
|
|
23535
|
+
return 'success';
|
|
23536
|
+
}
|
|
23537
|
+
if (eventType.includes('approved')) {
|
|
23538
|
+
return 'primary';
|
|
23539
|
+
}
|
|
23540
|
+
if (eventType.includes('rejected')) {
|
|
23541
|
+
return 'error';
|
|
23542
|
+
}
|
|
23543
|
+
if (eventType.includes('validation')) {
|
|
23544
|
+
return 'warning';
|
|
23545
|
+
}
|
|
23546
|
+
if (eventType.includes('created')) {
|
|
23547
|
+
return 'info';
|
|
23548
|
+
}
|
|
23549
|
+
return 'neutral';
|
|
23550
|
+
}
|
|
23456
23551
|
|
|
23457
|
-
const
|
|
23458
|
-
|
|
23552
|
+
const DEFAULT_TITLE = 'Governed decision timeline';
|
|
23553
|
+
const DEFAULT_EMPTY_TEXT = 'No safe timeline events published for this decision.';
|
|
23554
|
+
function domainRuleTimelineToRichContentDocument(timeline, options = {}) {
|
|
23555
|
+
return {
|
|
23556
|
+
kind: 'praxis.rich-content',
|
|
23557
|
+
version: '1.0.0',
|
|
23558
|
+
nodes: [
|
|
23559
|
+
{
|
|
23560
|
+
type: 'timeline',
|
|
23561
|
+
id: `domain-rule-timeline:${timeline.ruleDefinitionId}`,
|
|
23562
|
+
title: options.title ?? DEFAULT_TITLE,
|
|
23563
|
+
emptyText: options.emptyText ?? DEFAULT_EMPTY_TEXT,
|
|
23564
|
+
orientation: 'vertical',
|
|
23565
|
+
position: 'right',
|
|
23566
|
+
connectorVariant: 'solid',
|
|
23567
|
+
connectorColor: 'neutral',
|
|
23568
|
+
markerVariant: 'icon',
|
|
23569
|
+
markerColor: 'info',
|
|
23570
|
+
markerStyle: 'filled',
|
|
23571
|
+
items: timeline.events
|
|
23572
|
+
.filter(isSafeTimelineEvent)
|
|
23573
|
+
.map((event, index) => mapTimelineEvent(event, index)),
|
|
23574
|
+
},
|
|
23575
|
+
],
|
|
23576
|
+
};
|
|
23577
|
+
}
|
|
23578
|
+
function isSafeTimelineEvent(event) {
|
|
23579
|
+
return event.visibility === 'safe';
|
|
23580
|
+
}
|
|
23581
|
+
function mapTimelineEvent(event, index) {
|
|
23582
|
+
const target = formatTarget(event);
|
|
23583
|
+
const sourceHash = event.sourceHash ? `sourceHash: ${event.sourceHash}` : null;
|
|
23584
|
+
const meta = [target, sourceHash].filter((value) => Boolean(value)).join(' | ');
|
|
23585
|
+
return {
|
|
23586
|
+
id: `domain-rule-timeline-event:${index}:${event.eventType}`,
|
|
23587
|
+
title: event.summary || event.eventType,
|
|
23588
|
+
subtitle: event.actor ? `${event.actorType ?? 'actor'}: ${event.actor}` : event.actorType ?? undefined,
|
|
23589
|
+
opposite: event.occurredAt ?? undefined,
|
|
23590
|
+
meta: meta || undefined,
|
|
23591
|
+
badge: event.targetLayer ?? event.eventType,
|
|
23592
|
+
icon: iconForEvent(event.eventType),
|
|
23593
|
+
markerColor: markerColorForEvent(event.eventType),
|
|
23594
|
+
connectorColor: markerColorForEvent(event.eventType),
|
|
23595
|
+
};
|
|
23596
|
+
}
|
|
23597
|
+
function formatTarget(event) {
|
|
23598
|
+
const parts = [
|
|
23599
|
+
event.targetLayer,
|
|
23600
|
+
event.targetArtifactType,
|
|
23601
|
+
event.targetArtifactKey,
|
|
23602
|
+
].filter((value) => Boolean(value));
|
|
23603
|
+
return parts.length ? parts.join(' / ') : null;
|
|
23604
|
+
}
|
|
23605
|
+
function iconForEvent(eventType) {
|
|
23606
|
+
if (eventType.includes('materialization')) {
|
|
23607
|
+
return 'deployed_code';
|
|
23608
|
+
}
|
|
23609
|
+
if (eventType.includes('approved') || eventType.includes('activated')) {
|
|
23610
|
+
return 'verified';
|
|
23611
|
+
}
|
|
23612
|
+
if (eventType.includes('created')) {
|
|
23613
|
+
return 'add_circle';
|
|
23614
|
+
}
|
|
23615
|
+
return 'timeline';
|
|
23616
|
+
}
|
|
23617
|
+
function markerColorForEvent(eventType) {
|
|
23618
|
+
if (eventType.includes('materialization') || eventType.includes('activated')) {
|
|
23619
|
+
return 'success';
|
|
23620
|
+
}
|
|
23621
|
+
if (eventType.includes('approved')) {
|
|
23622
|
+
return 'primary';
|
|
23623
|
+
}
|
|
23624
|
+
if (eventType.includes('created')) {
|
|
23625
|
+
return 'info';
|
|
23626
|
+
}
|
|
23627
|
+
return 'neutral';
|
|
23628
|
+
}
|
|
23629
|
+
|
|
23630
|
+
const PRAXIS_QUERY_FILTER_EXPRESSION_SCHEMA_VERSION = 'praxis.query-filter-expression.v1';
|
|
23631
|
+
const PRAXIS_QUERY_FILTER_GROUP_OPERATORS = new Set(['all', 'any']);
|
|
23632
|
+
const PRAXIS_QUERY_FILTER_PREDICATE_OPERATORS = new Set([
|
|
23633
|
+
'equals',
|
|
23634
|
+
'notEquals',
|
|
23635
|
+
'in',
|
|
23636
|
+
'notIn',
|
|
23637
|
+
'contains',
|
|
23638
|
+
'startsWith',
|
|
23639
|
+
'between',
|
|
23640
|
+
'gte',
|
|
23641
|
+
'lte',
|
|
23642
|
+
'isNull',
|
|
23643
|
+
'isNotNull',
|
|
23644
|
+
]);
|
|
23645
|
+
const PRAXIS_QUERY_FILTER_PREDICATE_SOURCE_KINDS = new Set([
|
|
23646
|
+
'selected-records',
|
|
23647
|
+
'manual',
|
|
23648
|
+
'workflow',
|
|
23649
|
+
'current-context',
|
|
23650
|
+
]);
|
|
23651
|
+
const PRAXIS_QUERY_FILTER_GOVERNANCE_SOURCES = new Set([
|
|
23652
|
+
'selected-records',
|
|
23653
|
+
'manual',
|
|
23654
|
+
'workflow',
|
|
23655
|
+
'ai-authored',
|
|
23656
|
+
]);
|
|
23657
|
+
function normalizeRecord(record) {
|
|
23658
|
+
if (!record || typeof record !== 'object')
|
|
23659
|
+
return null;
|
|
23660
|
+
const next = Object.entries(record).reduce((acc, [key, value]) => {
|
|
23661
|
+
if (value === null || value === undefined)
|
|
23662
|
+
return acc;
|
|
23663
|
+
if (Array.isArray(value) && value.length === 0)
|
|
23664
|
+
return acc;
|
|
23665
|
+
if (typeof value === 'string' && value.trim() === '')
|
|
23666
|
+
return acc;
|
|
23667
|
+
acc[key] = value;
|
|
23668
|
+
return acc;
|
|
23669
|
+
}, {});
|
|
23670
|
+
return Object.keys(next).length ? next : null;
|
|
23671
|
+
}
|
|
23672
|
+
function isMeaningfulQueryFilterValue(value) {
|
|
23673
|
+
if (value === null || value === undefined)
|
|
23674
|
+
return false;
|
|
23675
|
+
if (Array.isArray(value))
|
|
23676
|
+
return value.some((item) => isMeaningfulQueryFilterValue(item));
|
|
23677
|
+
if (typeof value === 'string')
|
|
23678
|
+
return value.trim() !== '';
|
|
23679
|
+
return true;
|
|
23680
|
+
}
|
|
23681
|
+
function normalizeQueryFilterSource(source) {
|
|
23682
|
+
if (!source || typeof source !== 'object')
|
|
23683
|
+
return null;
|
|
23684
|
+
const kind = typeof source['kind'] === 'string' ? source['kind'].trim() : '';
|
|
23685
|
+
if (!PRAXIS_QUERY_FILTER_PREDICATE_SOURCE_KINDS.has(kind))
|
|
23686
|
+
return null;
|
|
23687
|
+
const field = typeof source['field'] === 'string' && source['field'].trim()
|
|
23688
|
+
? source['field'].trim()
|
|
23689
|
+
: null;
|
|
23690
|
+
const selectedIds = Array.isArray(source['selectedIds'])
|
|
23691
|
+
? source['selectedIds'].filter((id) => (typeof id === 'string' && id.trim() !== '') ||
|
|
23692
|
+
(typeof id === 'number' && Number.isFinite(id)))
|
|
23693
|
+
: [];
|
|
23694
|
+
return {
|
|
23695
|
+
kind: kind,
|
|
23696
|
+
...(field ? { field } : {}),
|
|
23697
|
+
...(selectedIds.length ? { selectedIds } : {}),
|
|
23698
|
+
};
|
|
23699
|
+
}
|
|
23700
|
+
function normalizeQueryFilterGovernance(governance) {
|
|
23701
|
+
if (!governance || typeof governance !== 'object')
|
|
23702
|
+
return null;
|
|
23703
|
+
const source = typeof governance['source'] === 'string' ? governance['source'].trim() : '';
|
|
23704
|
+
const decisionId = typeof governance['decisionId'] === 'string' && governance['decisionId'].trim()
|
|
23705
|
+
? governance['decisionId'].trim()
|
|
23706
|
+
: null;
|
|
23707
|
+
const explanation = typeof governance['explanation'] === 'string' && governance['explanation'].trim()
|
|
23708
|
+
? governance['explanation'].trim()
|
|
23709
|
+
: null;
|
|
23710
|
+
const next = {};
|
|
23711
|
+
if (PRAXIS_QUERY_FILTER_GOVERNANCE_SOURCES.has(source)) {
|
|
23712
|
+
next.source = source;
|
|
23713
|
+
}
|
|
23714
|
+
if (decisionId)
|
|
23715
|
+
next.decisionId = decisionId;
|
|
23716
|
+
if (explanation)
|
|
23717
|
+
next.explanation = explanation;
|
|
23718
|
+
return Object.keys(next).length ? next : null;
|
|
23719
|
+
}
|
|
23720
|
+
function normalizePraxisQueryFilterNode(node) {
|
|
23721
|
+
if (!node || typeof node !== 'object')
|
|
23722
|
+
return null;
|
|
23723
|
+
const kind = typeof node['kind'] === 'string' ? node['kind'].trim() : '';
|
|
23724
|
+
if (kind === 'group') {
|
|
23725
|
+
const operator = typeof node['operator'] === 'string' ? node['operator'].trim() : '';
|
|
23726
|
+
if (!PRAXIS_QUERY_FILTER_GROUP_OPERATORS.has(operator))
|
|
23727
|
+
return null;
|
|
23728
|
+
const clauses = Array.isArray(node['clauses'])
|
|
23729
|
+
? node['clauses']
|
|
23730
|
+
.map((clause) => normalizePraxisQueryFilterNode(clause))
|
|
23731
|
+
.filter((clause) => !!clause)
|
|
23732
|
+
: [];
|
|
23733
|
+
if (!clauses.length)
|
|
23734
|
+
return null;
|
|
23735
|
+
return {
|
|
23736
|
+
kind: 'group',
|
|
23737
|
+
operator: operator,
|
|
23738
|
+
clauses,
|
|
23739
|
+
};
|
|
23740
|
+
}
|
|
23741
|
+
if (kind === 'predicate') {
|
|
23742
|
+
const field = typeof node['field'] === 'string' ? node['field'].trim() : '';
|
|
23743
|
+
const operator = typeof node['operator'] === 'string' ? node['operator'].trim() : '';
|
|
23744
|
+
if (!field || !PRAXIS_QUERY_FILTER_PREDICATE_OPERATORS.has(operator))
|
|
23745
|
+
return null;
|
|
23746
|
+
const values = Array.isArray(node['values'])
|
|
23747
|
+
? node['values'].filter((value) => isMeaningfulQueryFilterValue(value))
|
|
23748
|
+
: [];
|
|
23749
|
+
const hasValue = isMeaningfulQueryFilterValue(node['value']);
|
|
23750
|
+
const label = typeof node['label'] === 'string' && node['label'].trim()
|
|
23751
|
+
? node['label'].trim()
|
|
23752
|
+
: null;
|
|
23753
|
+
const source = normalizeQueryFilterSource(node['source']);
|
|
23754
|
+
return {
|
|
23755
|
+
kind: 'predicate',
|
|
23756
|
+
field,
|
|
23757
|
+
operator: operator,
|
|
23758
|
+
...(hasValue ? { value: node['value'] } : {}),
|
|
23759
|
+
...(values.length ? { values } : {}),
|
|
23760
|
+
...(label ? { label } : {}),
|
|
23761
|
+
...(source ? { source } : {}),
|
|
23762
|
+
};
|
|
23763
|
+
}
|
|
23764
|
+
return null;
|
|
23765
|
+
}
|
|
23766
|
+
function normalizePraxisQueryFilterExpression(expression) {
|
|
23767
|
+
if (!expression || typeof expression !== 'object')
|
|
23768
|
+
return null;
|
|
23769
|
+
if (expression.schemaVersion !== PRAXIS_QUERY_FILTER_EXPRESSION_SCHEMA_VERSION)
|
|
23770
|
+
return null;
|
|
23771
|
+
const root = normalizePraxisQueryFilterNode(expression.root);
|
|
23772
|
+
if (!root)
|
|
23773
|
+
return null;
|
|
23774
|
+
const projection = expression.projection && typeof expression.projection === 'object'
|
|
23775
|
+
? {
|
|
23776
|
+
filters: normalizeRecord(expression.projection.filters),
|
|
23777
|
+
lossless: expression.projection.lossless === true,
|
|
23778
|
+
reason: typeof expression.projection.reason === 'string' && expression.projection.reason.trim()
|
|
23779
|
+
? expression.projection.reason.trim()
|
|
23780
|
+
: undefined,
|
|
23781
|
+
}
|
|
23782
|
+
: null;
|
|
23783
|
+
const governance = normalizeQueryFilterGovernance(expression.governance);
|
|
23784
|
+
return {
|
|
23785
|
+
schemaVersion: PRAXIS_QUERY_FILTER_EXPRESSION_SCHEMA_VERSION,
|
|
23786
|
+
root,
|
|
23787
|
+
...(projection ? {
|
|
23788
|
+
projection: {
|
|
23789
|
+
...(projection.filters ? { filters: projection.filters } : {}),
|
|
23790
|
+
lossless: projection.lossless,
|
|
23791
|
+
...(projection.reason ? { reason: projection.reason } : {}),
|
|
23792
|
+
},
|
|
23793
|
+
} : {}),
|
|
23794
|
+
...(governance ? { governance } : {}),
|
|
23795
|
+
};
|
|
23796
|
+
}
|
|
23797
|
+
function normalizePraxisDataQueryContext(context) {
|
|
23798
|
+
if (!context || typeof context !== 'object')
|
|
23799
|
+
return null;
|
|
23800
|
+
const filters = normalizeRecord(context.filters);
|
|
23801
|
+
const filterExpression = normalizePraxisQueryFilterExpression(context.filterExpression);
|
|
23802
|
+
const meta = normalizeRecord(context.meta);
|
|
23803
|
+
const sort = Array.isArray(context.sort)
|
|
23804
|
+
? context.sort
|
|
23805
|
+
.map((item) => (typeof item === 'string' ? item.trim() : ''))
|
|
23806
|
+
.filter((item) => item.length > 0)
|
|
23807
|
+
: [];
|
|
23808
|
+
const limit = typeof context.limit === 'number' && Number.isFinite(context.limit)
|
|
23809
|
+
? Math.max(0, Math.trunc(context.limit))
|
|
23810
|
+
: null;
|
|
23811
|
+
const page = context.page && typeof context.page === 'object'
|
|
23812
|
+
? {
|
|
23813
|
+
index: typeof context.page.index === 'number' && Number.isFinite(context.page.index)
|
|
23814
|
+
? Math.max(0, Math.trunc(context.page.index))
|
|
23815
|
+
: null,
|
|
23816
|
+
size: typeof context.page.size === 'number' && Number.isFinite(context.page.size)
|
|
23817
|
+
? Math.max(0, Math.trunc(context.page.size))
|
|
23818
|
+
: null,
|
|
23819
|
+
}
|
|
23820
|
+
: null;
|
|
23821
|
+
const next = {};
|
|
23822
|
+
if (filters)
|
|
23823
|
+
next.filters = filters;
|
|
23824
|
+
if (filterExpression)
|
|
23825
|
+
next.filterExpression = filterExpression;
|
|
23826
|
+
if (sort.length)
|
|
23827
|
+
next.sort = sort;
|
|
23828
|
+
if (limit !== null)
|
|
23829
|
+
next.limit = limit;
|
|
23830
|
+
if (page && (page.index !== null || page.size !== null))
|
|
23831
|
+
next.page = page;
|
|
23832
|
+
if (meta)
|
|
23833
|
+
next.meta = meta;
|
|
23834
|
+
return Object.keys(next).length ? next : null;
|
|
23835
|
+
}
|
|
23836
|
+
function resolvePraxisFilterCriteria(filterCriteria, queryContext) {
|
|
23837
|
+
const normalizedFilterCriteria = normalizeRecord(filterCriteria);
|
|
23838
|
+
const normalizedQueryContext = normalizePraxisDataQueryContext(queryContext);
|
|
23839
|
+
return {
|
|
23840
|
+
...(normalizedFilterCriteria || {}),
|
|
23841
|
+
...(normalizedQueryContext?.filters || {}),
|
|
23842
|
+
};
|
|
23843
|
+
}
|
|
23844
|
+
|
|
23845
|
+
const DEFAULT_FIELD_SELECTOR_CONTROL_TYPE_MAP = {
|
|
23846
|
+
'pdx-text-input': FieldControlType.INPUT,
|
|
23459
23847
|
'pdx-email-input': FieldControlType.EMAIL_INPUT,
|
|
23460
23848
|
'pdx-password-input': FieldControlType.PASSWORD,
|
|
23461
23849
|
'pdx-color-input': FieldControlType.COLOR_INPUT,
|
|
@@ -28973,457 +29361,175 @@ const DOMAIN_CATALOG_COMPONENT_CONTEXT_PACK = {
|
|
|
28973
29361
|
'domainCatalog.items[].payload.aiUsage.visibility': {
|
|
28974
29362
|
mode: 'suggested',
|
|
28975
29363
|
options: [
|
|
28976
|
-
{ value: 'public', label: 'Visible to public AI tasks' },
|
|
28977
|
-
{ value: 'internal', label: 'Visible to internal AI tasks' },
|
|
28978
|
-
{ value: 'restricted', label: 'Restricted AI visibility' },
|
|
28979
|
-
{ value: 'forbidden', label: 'Forbidden for AI use' },
|
|
28980
|
-
],
|
|
28981
|
-
},
|
|
28982
|
-
},
|
|
28983
|
-
actionCatalog: [
|
|
28984
|
-
{
|
|
28985
|
-
id: 'domainCatalog.release.list',
|
|
28986
|
-
operation: 'read',
|
|
28987
|
-
scope: 'GLOBAL',
|
|
28988
|
-
intentExamples: ['domain catalog releases', 'listar releases de dominio', 'catalogo semantico'],
|
|
28989
|
-
patchTemplate: {},
|
|
28990
|
-
safetyNotes: 'Read-only operation. Use DomainCatalogService.listReleases; do not write FormConfig or component config with returned governance rules.',
|
|
28991
|
-
},
|
|
28992
|
-
{
|
|
28993
|
-
id: 'domainCatalog.governanceContext.read',
|
|
28994
|
-
operation: 'read',
|
|
28995
|
-
scope: 'GLOBAL',
|
|
28996
|
-
valueType: 'OBJECT',
|
|
28997
|
-
intentExamples: ['governanca', 'LGPD', 'GDPR', 'dados sensiveis', 'ai visibility'],
|
|
28998
|
-
params: [
|
|
28999
|
-
{ name: 'resourceKey', type: 'STRING', description: 'Stable semantic resource key, for example human-resources.funcionarios.' },
|
|
29000
|
-
{ name: 'query', type: 'STRING', description: 'Field or concept probe, for example cpf, salario or status.' },
|
|
29001
|
-
],
|
|
29002
|
-
patchTemplate: {},
|
|
29003
|
-
safetyNotes: 'Read-only operation. Resolve governance through DomainCatalogService.getGovernanceContext(resourceKey, query) before proposing UI, rule or AI-use changes.',
|
|
29004
|
-
},
|
|
29005
|
-
{
|
|
29006
|
-
id: 'contextHints.domainCatalog.forward',
|
|
29007
|
-
operation: 'read',
|
|
29008
|
-
scope: 'GLOBAL',
|
|
29009
|
-
valueType: 'OBJECT',
|
|
29010
|
-
intentExamples: ['contextHints.domainCatalog', 'authoring hints', 'semantic retrieval hint', 'llm domain context'],
|
|
29011
|
-
params: [
|
|
29012
|
-
{ name: 'serviceKey', type: 'STRING', description: 'Semantic owner service, for example praxis-service.' },
|
|
29013
|
-
{ name: 'resourceKey', type: 'STRING', description: 'Stable semantic resource key, for example human-resources.funcionarios.' },
|
|
29014
|
-
{ name: 'type', type: 'STRING', description: 'Canonical item focus: context, node, edge, binding, evidence, governance, vocabulary or relationship.' },
|
|
29015
|
-
{ name: 'intent', type: 'STRING', description: 'Retrieval purpose: authoring, explain, validate or ai-access-control.' },
|
|
29016
|
-
{ name: 'query', type: 'STRING', description: 'Business query used to retrieve relevant domain context.' },
|
|
29017
|
-
],
|
|
29018
|
-
patchTemplate: {
|
|
29019
|
-
contextHints: {
|
|
29020
|
-
domainCatalog: {
|
|
29021
|
-
schemaVersion: 'praxis.ai.context-hints.domain-catalog/v0.2',
|
|
29022
|
-
recommendedAuthoringFlow: 'shared_rule_authoring',
|
|
29023
|
-
recommendedRuleType: 'privacy',
|
|
29024
|
-
serviceKey: '<serviceKey>',
|
|
29025
|
-
resourceKey: '<resourceKey>',
|
|
29026
|
-
type: 'governance',
|
|
29027
|
-
itemTypes: ['governance'],
|
|
29028
|
-
intent: 'authoring',
|
|
29029
|
-
query: '<business query>',
|
|
29030
|
-
limit: 12,
|
|
29031
|
-
relationships: {
|
|
29032
|
-
enabled: true,
|
|
29033
|
-
federated: true,
|
|
29034
|
-
query: '<business query>',
|
|
29035
|
-
limit: 8,
|
|
29036
|
-
},
|
|
29037
|
-
},
|
|
29038
|
-
},
|
|
29039
|
-
},
|
|
29040
|
-
safetyNotes: 'Forward these hints to AI authoring calls as runtime retrieval context. Do not convert them into executable rules or persist them as FormConfig unless an approved backend materialization flow says so.',
|
|
29041
|
-
},
|
|
29042
|
-
],
|
|
29043
|
-
fieldResolvers: {
|
|
29044
|
-
resourceKey: [
|
|
29045
|
-
'Prefer backend-provided resourceKey from surfaces, actions, capabilities or api_metadata.',
|
|
29046
|
-
'Do not derive resourceKey from resource.path when discovery already returned a stable semantic key.',
|
|
29047
|
-
],
|
|
29048
|
-
governanceProbe: [
|
|
29049
|
-
'Use the business field/concept name as query: cpf, salario, status, email, documento.',
|
|
29050
|
-
'Keep probes narrow; request more context instead of loading every governance item into a prompt.',
|
|
29051
|
-
],
|
|
29364
|
+
{ value: 'public', label: 'Visible to public AI tasks' },
|
|
29365
|
+
{ value: 'internal', label: 'Visible to internal AI tasks' },
|
|
29366
|
+
{ value: 'restricted', label: 'Restricted AI visibility' },
|
|
29367
|
+
{ value: 'forbidden', label: 'Forbidden for AI use' },
|
|
29368
|
+
],
|
|
29369
|
+
},
|
|
29052
29370
|
},
|
|
29053
|
-
|
|
29054
|
-
|
|
29055
|
-
|
|
29056
|
-
|
|
29057
|
-
|
|
29058
|
-
|
|
29059
|
-
|
|
29060
|
-
|
|
29061
|
-
|
|
29062
|
-
|
|
29063
|
-
|
|
29064
|
-
|
|
29065
|
-
|
|
29066
|
-
|
|
29067
|
-
|
|
29068
|
-
|
|
29069
|
-
|
|
29070
|
-
|
|
29071
|
-
|
|
29072
|
-
|
|
29073
|
-
|
|
29074
|
-
|
|
29075
|
-
|
|
29076
|
-
|
|
29077
|
-
|
|
29078
|
-
|
|
29079
|
-
|
|
29080
|
-
|
|
29081
|
-
|
|
29082
|
-
|
|
29083
|
-
|
|
29084
|
-
|
|
29085
|
-
|
|
29086
|
-
|
|
29087
|
-
|
|
29088
|
-
|
|
29089
|
-
|
|
29090
|
-
|
|
29091
|
-
|
|
29092
|
-
|
|
29093
|
-
|
|
29094
|
-
|
|
29095
|
-
|
|
29096
|
-
|
|
29097
|
-
|
|
29098
|
-
|
|
29099
|
-
|
|
29100
|
-
|
|
29101
|
-
|
|
29102
|
-
|
|
29103
|
-
|
|
29104
|
-
|
|
29105
|
-
|
|
29106
|
-
|
|
29107
|
-
const componentType = normalizeString(segment.componentType);
|
|
29108
|
-
const normalized = { kind };
|
|
29109
|
-
if (id) {
|
|
29110
|
-
normalized.id = id;
|
|
29111
|
-
}
|
|
29112
|
-
if (key) {
|
|
29113
|
-
normalized.key = key;
|
|
29114
|
-
}
|
|
29115
|
-
if (typeof segment.index === 'number' && Number.isFinite(segment.index)) {
|
|
29116
|
-
normalized.index = Math.trunc(segment.index);
|
|
29117
|
-
}
|
|
29118
|
-
if (componentType) {
|
|
29119
|
-
normalized.componentType = componentType;
|
|
29120
|
-
}
|
|
29121
|
-
return normalized;
|
|
29122
|
-
}
|
|
29123
|
-
function isOwnerEventSegment(segment, index, options) {
|
|
29124
|
-
if (index !== 0 || !OWNER_EVENT_SEGMENT_KINDS.has(segment.kind)) {
|
|
29125
|
-
return false;
|
|
29126
|
-
}
|
|
29127
|
-
const ownerComponentId = normalizeString(options.ownerComponentId);
|
|
29128
|
-
if (!ownerComponentId) {
|
|
29129
|
-
return true;
|
|
29130
|
-
}
|
|
29131
|
-
return segment.kind === ownerComponentId
|
|
29132
|
-
|| segment.id === ownerComponentId;
|
|
29133
|
-
}
|
|
29134
|
-
function stripEmptySegments(segments) {
|
|
29135
|
-
return segments.filter((segment) => !!segment.kind
|
|
29136
|
-
&& (segment.kind === 'widget'
|
|
29137
|
-
|| STRUCTURAL_NESTED_PATH_KINDS.has(segment.kind)
|
|
29138
|
-
|| !!segment.id
|
|
29139
|
-
|| !!segment.key
|
|
29140
|
-
|| typeof segment.index === 'number'
|
|
29141
|
-
|| !!segment.componentType));
|
|
29142
|
-
}
|
|
29143
|
-
function normalizeString(value) {
|
|
29144
|
-
return typeof value === 'string' ? value.trim() : '';
|
|
29145
|
-
}
|
|
29146
|
-
|
|
29147
|
-
class NestedWidgetConfigAccessor {
|
|
29148
|
-
listNestedWidgets(owner) {
|
|
29149
|
-
return this.listNestedWidgetsInDefinition(owner.key, owner.definition, []);
|
|
29150
|
-
}
|
|
29151
|
-
resolveNestedWidget(owner, nestedPath) {
|
|
29152
|
-
if (!nestedPath?.length) {
|
|
29153
|
-
return undefined;
|
|
29154
|
-
}
|
|
29155
|
-
return this.resolveNestedWidgetInDefinition(owner.definition, nestedPath);
|
|
29156
|
-
}
|
|
29157
|
-
setNestedWidgetInput(owner, nestedPath, inputName, value) {
|
|
29158
|
-
const normalizedInputName = String(inputName || '').trim();
|
|
29159
|
-
if (!nestedPath?.length || !normalizedInputName) {
|
|
29160
|
-
return { widget: this.clone(owner), changed: false };
|
|
29161
|
-
}
|
|
29162
|
-
const next = this.clone(owner);
|
|
29163
|
-
const changed = this.setNestedWidgetInputInDefinition(next.definition, nestedPath, normalizedInputName, this.clone(value));
|
|
29164
|
-
return { widget: next, changed };
|
|
29165
|
-
}
|
|
29166
|
-
listNestedWidgetsInDefinition(ownerWidgetKey, definition, basePath) {
|
|
29167
|
-
const results = [];
|
|
29168
|
-
for (const location of this.listChildWidgetLocations(definition)) {
|
|
29169
|
-
for (const [index, widget] of location.widgets.entries()) {
|
|
29170
|
-
if (!this.isWidgetDefinition(widget)) {
|
|
29171
|
-
continue;
|
|
29172
|
-
}
|
|
29173
|
-
const childWidgetKey = this.resolveChildWidgetKey(widget);
|
|
29174
|
-
const widgetSegment = {
|
|
29175
|
-
kind: 'widget',
|
|
29176
|
-
...(childWidgetKey ? { key: childWidgetKey } : { index }),
|
|
29177
|
-
componentType: widget.id,
|
|
29178
|
-
};
|
|
29179
|
-
const nestedPath = [
|
|
29180
|
-
...basePath,
|
|
29181
|
-
...location.path,
|
|
29182
|
-
widgetSegment,
|
|
29183
|
-
];
|
|
29184
|
-
results.push({
|
|
29185
|
-
ownerWidgetKey,
|
|
29186
|
-
nestedPath,
|
|
29187
|
-
widget: this.clone(widget),
|
|
29188
|
-
componentId: widget.id,
|
|
29189
|
-
childWidgetKey,
|
|
29190
|
-
});
|
|
29191
|
-
results.push(...this.listNestedWidgetsInDefinition(ownerWidgetKey, widget, nestedPath));
|
|
29192
|
-
}
|
|
29193
|
-
}
|
|
29194
|
-
return results;
|
|
29195
|
-
}
|
|
29196
|
-
resolveNestedWidgetInDefinition(definition, nestedPath) {
|
|
29197
|
-
const location = this.resolveWidgetArrayLocation(definition, nestedPath, 0);
|
|
29198
|
-
if (!location) {
|
|
29199
|
-
return undefined;
|
|
29200
|
-
}
|
|
29201
|
-
const widgetSegment = nestedPath[location.segmentCount];
|
|
29202
|
-
if (widgetSegment?.kind !== 'widget' || !widgetSegment.key) {
|
|
29203
|
-
return undefined;
|
|
29204
|
-
}
|
|
29205
|
-
const child = location.widgets.find((widget) => widget.childWidgetKey === widgetSegment.key);
|
|
29206
|
-
if (!this.isWidgetDefinition(child)) {
|
|
29207
|
-
return undefined;
|
|
29208
|
-
}
|
|
29209
|
-
const remaining = nestedPath.slice(location.segmentCount + 1);
|
|
29210
|
-
if (!remaining.length) {
|
|
29211
|
-
return this.clone(child);
|
|
29212
|
-
}
|
|
29213
|
-
return this.resolveNestedWidgetInDefinition(child, remaining);
|
|
29214
|
-
}
|
|
29215
|
-
setNestedWidgetInputInDefinition(definition, nestedPath, inputName, value) {
|
|
29216
|
-
const location = this.resolveWidgetArrayLocation(definition, nestedPath, 0);
|
|
29217
|
-
if (!location) {
|
|
29218
|
-
return false;
|
|
29219
|
-
}
|
|
29220
|
-
const widgetSegment = nestedPath[location.segmentCount];
|
|
29221
|
-
if (widgetSegment?.kind !== 'widget' || !widgetSegment.key) {
|
|
29222
|
-
return false;
|
|
29223
|
-
}
|
|
29224
|
-
const widgetIndex = location.widgets.findIndex((widget) => widget.childWidgetKey === widgetSegment.key);
|
|
29225
|
-
if (widgetIndex < 0) {
|
|
29226
|
-
return false;
|
|
29227
|
-
}
|
|
29228
|
-
const remaining = nestedPath.slice(location.segmentCount + 1);
|
|
29229
|
-
const child = location.widgets[widgetIndex];
|
|
29230
|
-
if (!this.isWidgetDefinition(child)) {
|
|
29231
|
-
return false;
|
|
29232
|
-
}
|
|
29233
|
-
if (remaining.length) {
|
|
29234
|
-
return this.setNestedWidgetInputInDefinition(child, remaining, inputName, value);
|
|
29235
|
-
}
|
|
29236
|
-
const currentInputs = child.inputs || {};
|
|
29237
|
-
const nextInputs = {
|
|
29238
|
-
...currentInputs,
|
|
29239
|
-
[inputName]: value,
|
|
29240
|
-
};
|
|
29241
|
-
if (this.isEqual(currentInputs, nextInputs)) {
|
|
29242
|
-
return false;
|
|
29243
|
-
}
|
|
29244
|
-
location.widgets[widgetIndex] = {
|
|
29245
|
-
...child,
|
|
29246
|
-
inputs: nextInputs,
|
|
29247
|
-
};
|
|
29248
|
-
return true;
|
|
29249
|
-
}
|
|
29250
|
-
listChildWidgetLocations(definition) {
|
|
29251
|
-
const config = definition.inputs?.['config'];
|
|
29252
|
-
if (!config || typeof config !== 'object') {
|
|
29253
|
-
return [];
|
|
29254
|
-
}
|
|
29255
|
-
if (definition.id === 'praxis-tabs') {
|
|
29256
|
-
return this.listTabsWidgetLocations(config);
|
|
29257
|
-
}
|
|
29258
|
-
if (definition.id === 'praxis-expansion') {
|
|
29259
|
-
return this.listExpansionWidgetLocations(config);
|
|
29260
|
-
}
|
|
29261
|
-
return [];
|
|
29262
|
-
}
|
|
29263
|
-
listTabsWidgetLocations(config) {
|
|
29264
|
-
const locations = [];
|
|
29265
|
-
const tabs = Array.isArray(config['tabs']) ? config['tabs'] : [];
|
|
29266
|
-
for (const [index, tab] of tabs.entries()) {
|
|
29267
|
-
if (!tab || typeof tab !== 'object') {
|
|
29268
|
-
continue;
|
|
29269
|
-
}
|
|
29270
|
-
const widgets = this.asWidgetDefinitions(tab['widgets']);
|
|
29271
|
-
if (!widgets.some((widget) => this.isWidgetDefinition(widget))) {
|
|
29272
|
-
continue;
|
|
29273
|
-
}
|
|
29274
|
-
locations.push({
|
|
29275
|
-
path: [{
|
|
29276
|
-
kind: 'tab',
|
|
29277
|
-
...this.segmentIdentity(tab, index),
|
|
29278
|
-
}],
|
|
29279
|
-
widgets,
|
|
29280
|
-
});
|
|
29281
|
-
}
|
|
29282
|
-
const nav = config['nav'];
|
|
29283
|
-
const links = nav && typeof nav === 'object' && Array.isArray(nav['links'])
|
|
29284
|
-
? nav['links']
|
|
29285
|
-
: [];
|
|
29286
|
-
for (const [index, link] of links.entries()) {
|
|
29287
|
-
if (!link || typeof link !== 'object') {
|
|
29288
|
-
continue;
|
|
29289
|
-
}
|
|
29290
|
-
const widgets = this.asWidgetDefinitions(link['widgets']);
|
|
29291
|
-
if (!widgets.some((widget) => this.isWidgetDefinition(widget))) {
|
|
29292
|
-
continue;
|
|
29293
|
-
}
|
|
29294
|
-
locations.push({
|
|
29295
|
-
path: [
|
|
29296
|
-
{ kind: 'nav' },
|
|
29297
|
-
{
|
|
29298
|
-
kind: 'link',
|
|
29299
|
-
...this.segmentIdentity(link, index),
|
|
29371
|
+
actionCatalog: [
|
|
29372
|
+
{
|
|
29373
|
+
id: 'domainCatalog.release.list',
|
|
29374
|
+
operation: 'read',
|
|
29375
|
+
scope: 'GLOBAL',
|
|
29376
|
+
intentExamples: ['domain catalog releases', 'listar releases de dominio', 'catalogo semantico'],
|
|
29377
|
+
patchTemplate: {},
|
|
29378
|
+
safetyNotes: 'Read-only operation. Use DomainCatalogService.listReleases; do not write FormConfig or component config with returned governance rules.',
|
|
29379
|
+
},
|
|
29380
|
+
{
|
|
29381
|
+
id: 'domainCatalog.governanceContext.read',
|
|
29382
|
+
operation: 'read',
|
|
29383
|
+
scope: 'GLOBAL',
|
|
29384
|
+
valueType: 'OBJECT',
|
|
29385
|
+
intentExamples: ['governanca', 'LGPD', 'GDPR', 'dados sensiveis', 'ai visibility'],
|
|
29386
|
+
params: [
|
|
29387
|
+
{ name: 'resourceKey', type: 'STRING', description: 'Stable semantic resource key, for example human-resources.funcionarios.' },
|
|
29388
|
+
{ name: 'query', type: 'STRING', description: 'Field or concept probe, for example cpf, salario or status.' },
|
|
29389
|
+
],
|
|
29390
|
+
patchTemplate: {},
|
|
29391
|
+
safetyNotes: 'Read-only operation. Resolve governance through DomainCatalogService.getGovernanceContext(resourceKey, query) before proposing UI, rule or AI-use changes.',
|
|
29392
|
+
},
|
|
29393
|
+
{
|
|
29394
|
+
id: 'contextHints.domainCatalog.forward',
|
|
29395
|
+
operation: 'read',
|
|
29396
|
+
scope: 'GLOBAL',
|
|
29397
|
+
valueType: 'OBJECT',
|
|
29398
|
+
intentExamples: ['contextHints.domainCatalog', 'authoring hints', 'semantic retrieval hint', 'llm domain context'],
|
|
29399
|
+
params: [
|
|
29400
|
+
{ name: 'serviceKey', type: 'STRING', description: 'Semantic owner service, for example praxis-service.' },
|
|
29401
|
+
{ name: 'resourceKey', type: 'STRING', description: 'Stable semantic resource key, for example human-resources.funcionarios.' },
|
|
29402
|
+
{ name: 'type', type: 'STRING', description: 'Canonical item focus: context, node, edge, binding, evidence, governance, vocabulary or relationship.' },
|
|
29403
|
+
{ name: 'intent', type: 'STRING', description: 'Retrieval purpose: authoring, explain, validate or ai-access-control.' },
|
|
29404
|
+
{ name: 'query', type: 'STRING', description: 'Business query used to retrieve relevant domain context.' },
|
|
29405
|
+
],
|
|
29406
|
+
patchTemplate: {
|
|
29407
|
+
contextHints: {
|
|
29408
|
+
domainCatalog: {
|
|
29409
|
+
schemaVersion: 'praxis.ai.context-hints.domain-catalog/v0.2',
|
|
29410
|
+
recommendedAuthoringFlow: 'shared_rule_authoring',
|
|
29411
|
+
recommendedRuleType: 'privacy',
|
|
29412
|
+
serviceKey: '<serviceKey>',
|
|
29413
|
+
resourceKey: '<resourceKey>',
|
|
29414
|
+
type: 'governance',
|
|
29415
|
+
itemTypes: ['governance'],
|
|
29416
|
+
intent: 'authoring',
|
|
29417
|
+
query: '<business query>',
|
|
29418
|
+
limit: 12,
|
|
29419
|
+
relationships: {
|
|
29420
|
+
enabled: true,
|
|
29421
|
+
federated: true,
|
|
29422
|
+
query: '<business query>',
|
|
29423
|
+
limit: 8,
|
|
29424
|
+
},
|
|
29300
29425
|
},
|
|
29301
|
-
|
|
29302
|
-
|
|
29303
|
-
|
|
29304
|
-
}
|
|
29305
|
-
|
|
29306
|
-
|
|
29307
|
-
|
|
29308
|
-
|
|
29309
|
-
|
|
29310
|
-
|
|
29311
|
-
|
|
29312
|
-
|
|
29313
|
-
|
|
29314
|
-
|
|
29315
|
-
|
|
29316
|
-
|
|
29317
|
-
|
|
29318
|
-
|
|
29319
|
-
|
|
29320
|
-
|
|
29321
|
-
|
|
29322
|
-
|
|
29323
|
-
|
|
29324
|
-
|
|
29325
|
-
|
|
29326
|
-
|
|
29327
|
-
|
|
29328
|
-
|
|
29329
|
-
|
|
29330
|
-
|
|
29426
|
+
},
|
|
29427
|
+
},
|
|
29428
|
+
safetyNotes: 'Forward these hints to AI authoring calls as runtime retrieval context. Do not convert them into executable rules or persist them as FormConfig unless an approved backend materialization flow says so.',
|
|
29429
|
+
},
|
|
29430
|
+
],
|
|
29431
|
+
fieldResolvers: {
|
|
29432
|
+
resourceKey: [
|
|
29433
|
+
'Prefer backend-provided resourceKey from surfaces, actions, capabilities or api_metadata.',
|
|
29434
|
+
'Do not derive resourceKey from resource.path when discovery already returned a stable semantic key.',
|
|
29435
|
+
],
|
|
29436
|
+
governanceProbe: [
|
|
29437
|
+
'Use the business field/concept name as query: cpf, salario, status, email, documento.',
|
|
29438
|
+
'Keep probes narrow; request more context instead of loading every governance item into a prompt.',
|
|
29439
|
+
],
|
|
29440
|
+
},
|
|
29441
|
+
hints: [
|
|
29442
|
+
'Domain Catalog is a runtime semantic/governance context source, not a FormConfig rule store.',
|
|
29443
|
+
'Use DomainCatalogService for read-only lookup of domain vocabulary, relationships and governance items.',
|
|
29444
|
+
'LLM tasks must treat aiUsage.visibility and complianceTags as prompt/data-access constraints before generating patches.',
|
|
29445
|
+
'Use contextHints.domainCatalog with schemaVersion praxis.ai.context-hints.domain-catalog/v0.2 to share runtime semantic retrieval intent between frontend and backend.',
|
|
29446
|
+
'Shared domain rules may be referenced by resourceKey and catalog release, but should not be copied into component JSON unless intentionally materialized by a backend policy.',
|
|
29447
|
+
],
|
|
29448
|
+
};
|
|
29449
|
+
|
|
29450
|
+
const OWNER_EVENT_SEGMENT_KINDS = new Set(['tabs', 'expansion', 'stepper']);
|
|
29451
|
+
const STRUCTURAL_NESTED_PATH_KINDS = new Set([
|
|
29452
|
+
'nav',
|
|
29453
|
+
]);
|
|
29454
|
+
function normalizeWidgetEventPath(event, options = {}) {
|
|
29455
|
+
const normalized = [];
|
|
29456
|
+
const sourceChildWidgetKey = normalizeString(event.sourceChildWidgetKey);
|
|
29457
|
+
const sourceComponentId = normalizeString(event.sourceComponentId);
|
|
29458
|
+
for (const [index, segment] of (event.path || []).entries()) {
|
|
29459
|
+
if (isOwnerEventSegment(segment, index, options)) {
|
|
29460
|
+
continue;
|
|
29331
29461
|
}
|
|
29332
|
-
|
|
29333
|
-
|
|
29462
|
+
const normalizedSegment = normalizeEventSegment(segment);
|
|
29463
|
+
if (normalizedSegment) {
|
|
29464
|
+
normalized.push(normalizedSegment);
|
|
29334
29465
|
}
|
|
29335
|
-
return undefined;
|
|
29336
29466
|
}
|
|
29337
|
-
|
|
29338
|
-
|
|
29339
|
-
if (!
|
|
29340
|
-
|
|
29341
|
-
}
|
|
29342
|
-
const first = nestedPath[offset];
|
|
29343
|
-
if (first?.kind === 'tab') {
|
|
29344
|
-
const tabs = Array.isArray(config['tabs'])
|
|
29345
|
-
? config['tabs']
|
|
29346
|
-
: [];
|
|
29347
|
-
const tab = this.findBySegment(tabs, first);
|
|
29348
|
-
const widgets = tab && typeof tab === 'object'
|
|
29349
|
-
? this.asWidgetDefinitions(tab['widgets'])
|
|
29350
|
-
: [];
|
|
29351
|
-
return widgets.length ? { widgets, segmentCount: offset + 1 } : undefined;
|
|
29467
|
+
const terminal = normalized[normalized.length - 1];
|
|
29468
|
+
if (terminal?.kind === 'widget') {
|
|
29469
|
+
if (!terminal.key && sourceChildWidgetKey) {
|
|
29470
|
+
terminal.key = sourceChildWidgetKey;
|
|
29352
29471
|
}
|
|
29353
|
-
|
|
29354
|
-
|
|
29355
|
-
: first;
|
|
29356
|
-
if (linkSegment?.kind !== 'link') {
|
|
29357
|
-
return undefined;
|
|
29472
|
+
if (!terminal.componentType && sourceComponentId) {
|
|
29473
|
+
terminal.componentType = sourceComponentId;
|
|
29358
29474
|
}
|
|
29359
|
-
|
|
29360
|
-
const links = nav && typeof nav === 'object' && Array.isArray(nav['links'])
|
|
29361
|
-
? nav['links']
|
|
29362
|
-
: [];
|
|
29363
|
-
const link = this.findBySegment(links, linkSegment);
|
|
29364
|
-
const widgets = link && typeof link === 'object'
|
|
29365
|
-
? this.asWidgetDefinitions(link['widgets'])
|
|
29366
|
-
: [];
|
|
29367
|
-
return widgets.length
|
|
29368
|
-
? { widgets, segmentCount: first?.kind === 'nav' ? offset + 2 : offset + 1 }
|
|
29369
|
-
: undefined;
|
|
29475
|
+
return stripEmptySegments(normalized);
|
|
29370
29476
|
}
|
|
29371
|
-
|
|
29372
|
-
|
|
29373
|
-
|
|
29374
|
-
|
|
29375
|
-
|
|
29376
|
-
}
|
|
29377
|
-
const panels = Array.isArray(config['panels'])
|
|
29378
|
-
? config['panels']
|
|
29379
|
-
: [];
|
|
29380
|
-
const panel = this.findBySegment(panels, panelSegment);
|
|
29381
|
-
const widgets = panel && typeof panel === 'object'
|
|
29382
|
-
? this.asWidgetDefinitions(panel['widgets'])
|
|
29383
|
-
: [];
|
|
29384
|
-
return widgets.length ? { widgets, segmentCount: offset + 1 } : undefined;
|
|
29477
|
+
if (sourceChildWidgetKey) {
|
|
29478
|
+
normalized.push({
|
|
29479
|
+
kind: 'widget',
|
|
29480
|
+
key: sourceChildWidgetKey,
|
|
29481
|
+
...(sourceComponentId ? { componentType: sourceComponentId } : {}),
|
|
29482
|
+
});
|
|
29385
29483
|
}
|
|
29386
|
-
|
|
29387
|
-
|
|
29388
|
-
|
|
29389
|
-
|
|
29390
|
-
|
|
29391
|
-
if (byId) {
|
|
29392
|
-
return byId;
|
|
29393
|
-
}
|
|
29394
|
-
}
|
|
29395
|
-
if (typeof segment.index === 'number') {
|
|
29396
|
-
return items[segment.index];
|
|
29397
|
-
}
|
|
29398
|
-
return undefined;
|
|
29484
|
+
return stripEmptySegments(normalized);
|
|
29485
|
+
}
|
|
29486
|
+
function normalizeEventSegment(segment) {
|
|
29487
|
+
if (segment.kind === 'tabs') {
|
|
29488
|
+
return null;
|
|
29399
29489
|
}
|
|
29400
|
-
|
|
29401
|
-
|
|
29402
|
-
|
|
29403
|
-
|
|
29404
|
-
|
|
29405
|
-
|
|
29490
|
+
const kind = segment.kind === 'widget'
|
|
29491
|
+
? 'widget'
|
|
29492
|
+
: segment.kind;
|
|
29493
|
+
const key = normalizeString(segment.key);
|
|
29494
|
+
const id = normalizeString(segment.id);
|
|
29495
|
+
const componentType = normalizeString(segment.componentType);
|
|
29496
|
+
const normalized = { kind };
|
|
29497
|
+
if (id) {
|
|
29498
|
+
normalized.id = id;
|
|
29406
29499
|
}
|
|
29407
|
-
|
|
29408
|
-
|
|
29500
|
+
if (key) {
|
|
29501
|
+
normalized.key = key;
|
|
29409
29502
|
}
|
|
29410
|
-
|
|
29411
|
-
|
|
29412
|
-
&& typeof value === 'object'
|
|
29413
|
-
&& typeof value.id === 'string';
|
|
29503
|
+
if (typeof segment.index === 'number' && Number.isFinite(segment.index)) {
|
|
29504
|
+
normalized.index = Math.trunc(segment.index);
|
|
29414
29505
|
}
|
|
29415
|
-
|
|
29416
|
-
|
|
29506
|
+
if (componentType) {
|
|
29507
|
+
normalized.componentType = componentType;
|
|
29417
29508
|
}
|
|
29418
|
-
|
|
29419
|
-
|
|
29420
|
-
|
|
29421
|
-
|
|
29422
|
-
return
|
|
29509
|
+
return normalized;
|
|
29510
|
+
}
|
|
29511
|
+
function isOwnerEventSegment(segment, index, options) {
|
|
29512
|
+
if (index !== 0 || !OWNER_EVENT_SEGMENT_KINDS.has(segment.kind)) {
|
|
29513
|
+
return false;
|
|
29423
29514
|
}
|
|
29424
|
-
|
|
29425
|
-
|
|
29515
|
+
const ownerComponentId = normalizeString(options.ownerComponentId);
|
|
29516
|
+
if (!ownerComponentId) {
|
|
29517
|
+
return true;
|
|
29426
29518
|
}
|
|
29519
|
+
return segment.kind === ownerComponentId
|
|
29520
|
+
|| segment.id === ownerComponentId;
|
|
29521
|
+
}
|
|
29522
|
+
function stripEmptySegments(segments) {
|
|
29523
|
+
return segments.filter((segment) => !!segment.kind
|
|
29524
|
+
&& (segment.kind === 'widget'
|
|
29525
|
+
|| STRUCTURAL_NESTED_PATH_KINDS.has(segment.kind)
|
|
29526
|
+
|| !!segment.id
|
|
29527
|
+
|| !!segment.key
|
|
29528
|
+
|| typeof segment.index === 'number'
|
|
29529
|
+
|| !!segment.componentType));
|
|
29530
|
+
}
|
|
29531
|
+
function normalizeString(value) {
|
|
29532
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
29427
29533
|
}
|
|
29428
29534
|
|
|
29429
29535
|
const EDITORIAL_ALLOWED_CONTENT_FORMATS = ['plain', 'markdown'];
|
|
@@ -38505,10 +38611,11 @@ class DynamicWidgetPageComponent {
|
|
|
38505
38611
|
this.pageState = runtime.state;
|
|
38506
38612
|
this.pageRuntime = runtime;
|
|
38507
38613
|
this.applyResponsivePresentation(hydrated, stateBoundWidgets, runtime);
|
|
38508
|
-
this.
|
|
38614
|
+
const canonicalPage = this.toPersistedCanonicalPage(hydrated);
|
|
38615
|
+
this.pageChange.emit(canonicalPage);
|
|
38509
38616
|
this.reportStateDiagnostics(runtime.diagnostics);
|
|
38510
38617
|
if (persist && this.autoPersist && !this.isHydrating) {
|
|
38511
|
-
this.savePage(
|
|
38618
|
+
this.savePage(canonicalPage);
|
|
38512
38619
|
}
|
|
38513
38620
|
}
|
|
38514
38621
|
applyLayout(layout, grouping) {
|