@praxisui/page-builder 8.0.0-beta.92 → 8.0.0-beta.93

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.
@@ -14307,13 +14307,14 @@ class PageBuilderAgenticAuthoringTurnFlow {
14307
14307
  };
14308
14308
  }
14309
14309
  const status = this.decorateDashboardReviewStatus(this.context.describePreviewStatus(preview), intentResolution, preview);
14310
+ const reviewCanApply = this.reviewCanApply(intentResolution, preview);
14310
14311
  return {
14311
14312
  state: 'review',
14312
14313
  phase: 'review',
14313
14314
  assistantMessage: status,
14314
- quickReplies: this.dashboardQualityQuickReplies(intentResolution, preview),
14315
- canApply: true,
14316
- statusText: this.reviewStatusText(status, true),
14315
+ quickReplies: this.reviewQuickReplies([], intentResolution, preview),
14316
+ canApply: reviewCanApply,
14317
+ statusText: this.reviewStatusText(status, reviewCanApply),
14317
14318
  errorText: '',
14318
14319
  preview,
14319
14320
  diagnostics: this.buildTurnDiagnostics(intentResolution, preview),
@@ -14445,8 +14446,848 @@ class PageBuilderAgenticAuthoringTurnFlow {
14445
14446
  currentPageSummary: {},
14446
14447
  contextHints,
14447
14448
  };
14449
+ const localDashboardRepair = this.buildLocalDashboardRepairPreview(prompt, contextHints, intentResolution);
14450
+ if (localDashboardRepair) {
14451
+ return this.applyDashboardRepairPreview(localDashboardRepair, intentResolution);
14452
+ }
14448
14453
  return this.completeExecutableStreamPreview(request, prompt, intentResolution, undefined);
14449
14454
  }
14455
+ async applyDashboardRepairPreview(preview, intentResolution) {
14456
+ const applied = await this.context.applyLocalPreview(preview);
14457
+ if (!applied.success) {
14458
+ const message = applied.error || this.context.tx('agentic.errors.applyLocal', 'Preview could not be applied.');
14459
+ return {
14460
+ state: 'error',
14461
+ phase: 'preview',
14462
+ assistantMessage: message,
14463
+ canApply: false,
14464
+ statusText: '',
14465
+ errorText: message,
14466
+ preview: null,
14467
+ diagnostics: this.buildTurnDiagnostics(intentResolution, preview),
14468
+ };
14469
+ }
14470
+ const status = this.decorateDashboardReviewStatus(this.context.describePreviewStatus(preview), intentResolution, preview);
14471
+ const reviewCanApply = this.reviewCanApply(intentResolution, preview);
14472
+ return {
14473
+ state: 'review',
14474
+ phase: 'review',
14475
+ assistantMessage: status,
14476
+ quickReplies: this.reviewQuickReplies([], intentResolution, preview),
14477
+ canApply: reviewCanApply,
14478
+ statusText: this.reviewStatusText(status, reviewCanApply),
14479
+ errorText: '',
14480
+ preview,
14481
+ diagnostics: this.buildTurnDiagnostics(intentResolution, preview),
14482
+ };
14483
+ }
14484
+ buildLocalDashboardRepairPreview(prompt, contextHints, intentResolution) {
14485
+ const changeKind = intentResolution.changeKind
14486
+ || this.readString(contextHints, 'changeKind')
14487
+ || this.dashboardQualityChangeKindFromActionText(prompt)
14488
+ || '';
14489
+ if (this.readString(contextHints, 'kind') !== 'dashboard-repair-action' && !changeKind) {
14490
+ return null;
14491
+ }
14492
+ if (![
14493
+ 'add_dashboard_kpis',
14494
+ 'bind_dashboard_kpis',
14495
+ 'add_dashboard_chart',
14496
+ 'add_dashboard_surfaces',
14497
+ 'connect_dashboard_widgets',
14498
+ ].includes(changeKind)) {
14499
+ return null;
14500
+ }
14501
+ const page = this.dashboardRepairBasePage(contextHints);
14502
+ if (!page) {
14503
+ return null;
14504
+ }
14505
+ const repairLog = [];
14506
+ if (changeKind === 'add_dashboard_kpis' || changeKind === 'bind_dashboard_kpis') {
14507
+ this.repairDashboardKpis(page, contextHints, repairLog);
14508
+ }
14509
+ if (changeKind === 'add_dashboard_chart') {
14510
+ this.repairDashboardChart(page, contextHints, repairLog);
14511
+ this.repairDashboardConnections(page, repairLog);
14512
+ }
14513
+ if (changeKind === 'add_dashboard_surfaces') {
14514
+ this.repairDashboardSurfaces(page, contextHints, repairLog);
14515
+ }
14516
+ if (changeKind === 'connect_dashboard_widgets') {
14517
+ this.repairDashboardConnections(page, repairLog);
14518
+ }
14519
+ if (!repairLog.length) {
14520
+ return null;
14521
+ }
14522
+ return {
14523
+ valid: true,
14524
+ failureCodes: [],
14525
+ warnings: [],
14526
+ minimalFormPlan: {},
14527
+ compiledFormPatch: {
14528
+ patch: { page: page },
14529
+ diagnostics: {
14530
+ dashboardQualityRepair: {
14531
+ schemaVersion: 'praxis-dashboard-quality-repair.v1',
14532
+ source: 'dashboard-quality-gate',
14533
+ mode: 'local-deterministic-repair',
14534
+ changeKind,
14535
+ prompt,
14536
+ actions: repairLog,
14537
+ },
14538
+ },
14539
+ },
14540
+ diagnostics: {
14541
+ dashboardQualityRepair: {
14542
+ schemaVersion: 'praxis-dashboard-quality-repair.v1',
14543
+ source: 'dashboard-quality-gate',
14544
+ mode: 'local-deterministic-repair',
14545
+ changeKind,
14546
+ actions: repairLog,
14547
+ },
14548
+ },
14549
+ };
14550
+ }
14551
+ dashboardRepairBasePage(contextHints) {
14552
+ const materializedPage = this.cloneJsonObject(this.toJsonObject(contextHints['materializedPage']));
14553
+ if (this.hasDashboardSnapshotWidgets(materializedPage)) {
14554
+ return materializedPage;
14555
+ }
14556
+ const currentPage = this.cloneJsonObject(this.toJsonObject(this.context.currentPage()));
14557
+ if (this.hasDashboardSnapshotWidgets(currentPage)) {
14558
+ return currentPage;
14559
+ }
14560
+ const plan = this.toJsonObject(contextHints['uiCompositionPlan']);
14561
+ const pageFromPlan = this.pageFromUiCompositionPlan(plan);
14562
+ return this.hasDashboardSnapshotWidgets(pageFromPlan) ? pageFromPlan : null;
14563
+ }
14564
+ pageFromUiCompositionPlan(plan) {
14565
+ if (!plan) {
14566
+ return null;
14567
+ }
14568
+ const widgets = this.arrayFromUnknown(plan['widgets'])
14569
+ .map((widget) => this.toJsonObject(widget))
14570
+ .filter((widget) => !!widget)
14571
+ .map((widget) => ({
14572
+ key: this.readString(widget, 'key') ?? this.readString(widget, 'id') ?? 'dashboard-widget',
14573
+ ...(this.toJsonObject(widget['shell']) ? { shell: this.cloneJsonObject(this.toJsonObject(widget['shell'])) } : {}),
14574
+ ...(this.readString(widget, 'className') ? { className: this.readString(widget, 'className') } : {}),
14575
+ definition: {
14576
+ id: this.readString(widget, 'componentId') ?? this.readString(widget, 'type') ?? 'praxis-rich-content',
14577
+ bindingOrder: this.arrayFromUnknown(widget['bindingOrder']).map((item) => `${item}`),
14578
+ inputs: this.cloneJsonObject(this.toJsonObject(widget['inputs'])) ?? {},
14579
+ },
14580
+ }));
14581
+ const links = this.arrayFromUnknown(plan['bindings'])
14582
+ .map((binding) => this.toJsonObject(binding))
14583
+ .filter((binding) => !!binding)
14584
+ .map((binding) => this.pageCompositionLinkFromBinding(binding))
14585
+ .filter((link) => !!link);
14586
+ return {
14587
+ title: this.readString(plan, 'title') ?? 'Dashboard',
14588
+ layoutPreset: this.readString(plan, 'layoutPreset'),
14589
+ themePreset: this.readString(plan, 'themePreset'),
14590
+ canvas: this.cloneJsonObject(this.toJsonObject(plan['canvas'])),
14591
+ state: this.cloneJsonObject(this.toJsonObject(plan['state'])),
14592
+ widgets,
14593
+ ...(links.length ? { composition: { version: '1.0.0', links } } : {}),
14594
+ };
14595
+ }
14596
+ pageCompositionLinkFromBinding(binding) {
14597
+ const from = this.pageCompositionEndpointFromPlanEndpoint(this.toJsonObject(binding['from']));
14598
+ const to = this.pageCompositionEndpointFromPlanEndpoint(this.toJsonObject(binding['to']));
14599
+ if (!from || !to) {
14600
+ return null;
14601
+ }
14602
+ return {
14603
+ id: this.readString(binding, 'id') ?? `${JSON.stringify(from)}->${JSON.stringify(to)}`,
14604
+ intent: this.readString(binding, 'intent') ?? 'filter',
14605
+ from,
14606
+ to,
14607
+ ...(this.toJsonObject(binding['transform']) ? { transform: this.cloneJsonObject(this.toJsonObject(binding['transform'])) } : {}),
14608
+ };
14609
+ }
14610
+ pageCompositionEndpointFromPlanEndpoint(endpoint) {
14611
+ if (!endpoint) {
14612
+ return null;
14613
+ }
14614
+ const kind = this.readString(endpoint, 'kind');
14615
+ if (kind === 'component-port') {
14616
+ return {
14617
+ kind,
14618
+ ref: {
14619
+ widget: this.readString(endpoint, 'widget'),
14620
+ port: this.readString(endpoint, 'port'),
14621
+ direction: this.readString(endpoint, 'direction'),
14622
+ componentType: this.readString(endpoint, 'componentType'),
14623
+ nestedPath: this.cloneJsonObject(this.toJsonObject(endpoint['nestedPath'])),
14624
+ },
14625
+ };
14626
+ }
14627
+ if (kind === 'global-action') {
14628
+ return {
14629
+ kind,
14630
+ ref: {
14631
+ actionId: this.readString(endpoint, 'actionId') ?? this.readString(this.toJsonObject(endpoint['ref']) ?? {}, 'actionId'),
14632
+ payload: this.cloneJsonObject(this.toJsonObject(endpoint['payload'])),
14633
+ },
14634
+ };
14635
+ }
14636
+ if (kind === 'state') {
14637
+ return {
14638
+ kind,
14639
+ ref: {
14640
+ path: this.readString(endpoint, 'path'),
14641
+ },
14642
+ };
14643
+ }
14644
+ return null;
14645
+ }
14646
+ repairDashboardKpis(page, contextHints, repairLog) {
14647
+ const widgets = this.dashboardPageWidgets(page);
14648
+ const detailKey = this.dashboardDetailWidgetKey(page) ?? this.dashboardDetailWidgetKeyFromRepairContext(contextHints);
14649
+ let repaired = false;
14650
+ for (const widget of widgets) {
14651
+ const componentId = this.dashboardWidgetComponentId(widget);
14652
+ const inputs = this.dashboardWidgetInputs(widget);
14653
+ if (!this.isDashboardKpiWidget(componentId, widget, inputs, this.toJsonObject(widget['shell']))) {
14654
+ continue;
14655
+ }
14656
+ const document = this.toJsonObject(inputs['document']);
14657
+ if (!document) {
14658
+ continue;
14659
+ }
14660
+ const kpiKey = this.dashboardWidgetKey(widget);
14661
+ repaired = this.repairRichContentKpiDocument(document) || repaired;
14662
+ const context = this.dashboardKpiInitialContext(inputs['context']);
14663
+ this.setDashboardWidgetInputs(widget, {
14664
+ ...inputs,
14665
+ context,
14666
+ document,
14667
+ });
14668
+ this.ensureDashboardWidgetBindingOrder(widget, ['document', 'context']);
14669
+ if (detailKey && this.ensureDashboardKpiContextLinks(page, detailKey, kpiKey)) {
14670
+ repaired = true;
14671
+ }
14672
+ }
14673
+ if (!repaired) {
14674
+ const resourcePath = this.dashboardRepairResourcePath(contextHints);
14675
+ const kpiKey = this.uniqueDashboardWidgetKey(page, 'dashboard-kpis');
14676
+ const kpiWidget = {
14677
+ key: kpiKey,
14678
+ shell: {
14679
+ kind: 'dashboard-card',
14680
+ title: 'Indicadores',
14681
+ subtitle: 'Metricas dinamicas do recurso selecionado',
14682
+ },
14683
+ definition: {
14684
+ id: 'praxis-rich-content',
14685
+ bindingOrder: ['document', 'context', 'resourcePath', 'queryContext'],
14686
+ inputs: {
14687
+ resourcePath,
14688
+ queryContext: { filters: {} },
14689
+ context: this.dashboardKpiInitialContext(),
14690
+ document: this.buildDashboardKpiDocument(),
14691
+ },
14692
+ },
14693
+ };
14694
+ this.insertDashboardWidget(page, kpiWidget, 1);
14695
+ if (detailKey) {
14696
+ this.ensureDashboardKpiContextLinks(page, detailKey, kpiKey);
14697
+ }
14698
+ repaired = true;
14699
+ }
14700
+ if (repaired) {
14701
+ repairLog.push('dashboard-kpis-bound');
14702
+ }
14703
+ }
14704
+ repairRichContentKpiDocument(document) {
14705
+ let repaired = false;
14706
+ for (const node of this.arrayFromUnknown(document['nodes'])) {
14707
+ repaired = this.repairRichContentKpiNode(this.toJsonObject(node)) || repaired;
14708
+ }
14709
+ return repaired;
14710
+ }
14711
+ repairRichContentKpiNode(node) {
14712
+ if (!node) {
14713
+ return false;
14714
+ }
14715
+ let repaired = false;
14716
+ const type = this.readString(node, 'type')?.toLowerCase();
14717
+ if (type === 'metric' || type === 'stat' || type === 'statitem' || type === 'stat-item') {
14718
+ repaired = this.bindKpiNode(node) || repaired;
14719
+ }
14720
+ if (type === 'statgroup' || type === 'stat-group') {
14721
+ if (this.dashboardKpiStatGroupNeedsCanonicalItems(node)) {
14722
+ node['items'] = this.buildDashboardKpiItems();
14723
+ repaired = true;
14724
+ }
14725
+ for (const item of this.arrayFromUnknown(node['items'])) {
14726
+ repaired = this.bindKpiNode(this.toJsonObject(item)) || repaired;
14727
+ }
14728
+ }
14729
+ for (const key of ['nodes', 'items', 'children', 'content']) {
14730
+ for (const child of this.arrayFromUnknown(node[key])) {
14731
+ repaired = this.repairRichContentKpiNode(this.toJsonObject(child)) || repaired;
14732
+ }
14733
+ }
14734
+ return repaired;
14735
+ }
14736
+ dashboardKpiStatGroupNeedsCanonicalItems(node) {
14737
+ const items = this.arrayFromUnknown(node['items'])
14738
+ .map((item) => this.toJsonObject(item))
14739
+ .filter((item) => !!item);
14740
+ if (!items.length) {
14741
+ return true;
14742
+ }
14743
+ const canonicalLabels = new Set(['total filtrado', 'itens na pagina', 'status da consulta']);
14744
+ const hasOnlyResolvableLabels = items.every((item) => canonicalLabels.has(this.normalizeText(this.readString(item, 'label') ?? this.readString(item, 'title') ?? '')));
14745
+ if (hasOnlyResolvableLabels) {
14746
+ return false;
14747
+ }
14748
+ return items.some((item) => !!this.readString(item, 'valuePath')
14749
+ || !this.readString(item, 'valueExpr')
14750
+ || ['-', '--', 'n/a'].includes((this.readString(item, 'value') || '').toLowerCase()));
14751
+ }
14752
+ bindKpiNode(node) {
14753
+ if (!node) {
14754
+ return false;
14755
+ }
14756
+ const value = this.readString(node, 'value')?.trim() ?? '';
14757
+ const hasRuntimeExpression = !!this.readString(node, 'valueExpr');
14758
+ if (hasRuntimeExpression && value !== '-' && value !== '--' && value.toLowerCase() !== 'n/a') {
14759
+ return false;
14760
+ }
14761
+ if (!hasRuntimeExpression && value && value !== '-' && value !== '--' && value.toLowerCase() !== 'n/a') {
14762
+ return false;
14763
+ }
14764
+ const label = this.readString(node, 'label') ?? this.readString(node, 'title') ?? '';
14765
+ node['valueExpr'] = this.dashboardKpiValueExpression(label);
14766
+ delete node['valuePath'];
14767
+ delete node['valueTemplate'];
14768
+ delete node['value'];
14769
+ node['format'] = node['format'] ?? 'integer';
14770
+ node['captionExpr'] = this.dashboardKpiCaptionExpression(label);
14771
+ delete node['caption'];
14772
+ return true;
14773
+ }
14774
+ dashboardKpiValueExpression(label) {
14775
+ const normalized = this.normalizeText(label);
14776
+ if (normalized.includes('pagina') || normalized.includes('carregad')) {
14777
+ return '${loadedItemsCount}';
14778
+ }
14779
+ if (normalized.includes('status')) {
14780
+ return '${statusLabel}';
14781
+ }
14782
+ return '${totalItems}';
14783
+ }
14784
+ dashboardKpiCaptionExpression(label) {
14785
+ const normalized = this.normalizeText(label);
14786
+ if (normalized.includes('pagina') || normalized.includes('carregad')) {
14787
+ return '${loadedItemsCaption}';
14788
+ }
14789
+ if (normalized.includes('status')) {
14790
+ return '${statusCaption}';
14791
+ }
14792
+ return '${totalCaption}';
14793
+ }
14794
+ hasDynamicKpiBinding(node) {
14795
+ return !!(this.readString(node, 'valueExpr') || this.readString(node, 'valueTemplate'));
14796
+ }
14797
+ buildDashboardKpiDocument() {
14798
+ return {
14799
+ kind: 'praxis.rich-content',
14800
+ version: '1.0.0',
14801
+ nodes: [
14802
+ {
14803
+ type: 'statGroup',
14804
+ title: 'Leitura executiva',
14805
+ layout: 'grid',
14806
+ items: this.buildDashboardKpiItems(),
14807
+ },
14808
+ ],
14809
+ };
14810
+ }
14811
+ buildDashboardKpiItems() {
14812
+ return [
14813
+ {
14814
+ label: 'Total filtrado',
14815
+ valueExpr: '${totalItems}',
14816
+ format: 'integer',
14817
+ icon: 'monitoring',
14818
+ captionExpr: '${totalCaption}',
14819
+ },
14820
+ {
14821
+ label: 'Itens na pagina',
14822
+ valueExpr: '${loadedItemsCount}',
14823
+ format: 'integer',
14824
+ icon: 'view_list',
14825
+ captionExpr: '${loadedItemsCaption}',
14826
+ },
14827
+ {
14828
+ label: 'Status da consulta',
14829
+ valueExpr: '${statusLabel}',
14830
+ icon: 'sync',
14831
+ captionExpr: '${statusCaption}',
14832
+ },
14833
+ ];
14834
+ }
14835
+ dashboardKpiInitialContext(current) {
14836
+ return {
14837
+ totalItems: 0,
14838
+ loadedItemsCount: 0,
14839
+ statusLabel: this.context.tx('agentic.dashboardQuality.kpiStatus.loading', 'Carregando'),
14840
+ totalCaption: this.context.tx('agentic.dashboardQuality.kpiCaption.total', 'Total retornado pela consulta filtrada'),
14841
+ loadedItemsCaption: this.context.tx('agentic.dashboardQuality.kpiCaption.loaded', 'Itens carregados nesta pagina'),
14842
+ statusCaption: this.context.tx('agentic.dashboardQuality.kpiCaption.status', 'Atualizado pelo runtime da tabela'),
14843
+ ...(this.cloneJsonObject(this.toJsonObject(current)) ?? {}),
14844
+ };
14845
+ }
14846
+ ensureDashboardKpiContextLinks(page, tableKey, kpiKey) {
14847
+ const links = this.dashboardCompositionLinks(page);
14848
+ const writeId = `${tableKey}.loadingStateChange->dashboardKpis`;
14849
+ const readId = `dashboardKpis->${kpiKey}.context`;
14850
+ let changed = false;
14851
+ if (!links.some((link) => this.readString(link, 'id') === writeId)) {
14852
+ links.push({
14853
+ id: writeId,
14854
+ intent: 'state-write',
14855
+ from: {
14856
+ kind: 'component-port',
14857
+ ref: { widget: tableKey, port: 'loadingStateChange', direction: 'output' },
14858
+ },
14859
+ to: {
14860
+ kind: 'state',
14861
+ ref: { path: 'dashboardKpis', layer: 'values', writable: true },
14862
+ },
14863
+ transform: {
14864
+ version: '2.0',
14865
+ phase: 'link-propagation',
14866
+ mode: 'object-fragment',
14867
+ sourceBindings: [{ source: 'event' }],
14868
+ steps: [
14869
+ {
14870
+ id: `${writeId}:summary`,
14871
+ kind: 'object-template',
14872
+ phase: 'link-propagation',
14873
+ input: { source: 'event' },
14874
+ config: {
14875
+ template: {
14876
+ totalItems: '${payload.totalItems}',
14877
+ loadedItemsCount: '${payload.loadedItemsCount}',
14878
+ statusLabel: '${payload.status}',
14879
+ totalCaption: 'Total retornado pela consulta filtrada',
14880
+ loadedItemsCaption: 'Itens carregados nesta pagina',
14881
+ statusCaption: '${payload.message}',
14882
+ },
14883
+ },
14884
+ },
14885
+ ],
14886
+ },
14887
+ metadata: { source: 'persisted-composition-link' },
14888
+ });
14889
+ changed = true;
14890
+ }
14891
+ if (!links.some((link) => this.readString(link, 'id') === readId)) {
14892
+ links.push({
14893
+ id: readId,
14894
+ intent: 'state-read',
14895
+ from: {
14896
+ kind: 'state',
14897
+ ref: { path: 'dashboardKpis', layer: 'values' },
14898
+ },
14899
+ to: {
14900
+ kind: 'component-port',
14901
+ ref: { widget: kpiKey, port: 'context', direction: 'input' },
14902
+ },
14903
+ metadata: { source: 'persisted-composition-link' },
14904
+ });
14905
+ changed = true;
14906
+ }
14907
+ if (changed) {
14908
+ const composition = this.toJsonObject(page['composition']) ?? {};
14909
+ page['composition'] = {
14910
+ ...composition,
14911
+ version: this.readString(composition, 'version') ?? '1.0.0',
14912
+ links,
14913
+ };
14914
+ }
14915
+ return changed;
14916
+ }
14917
+ repairDashboardChart(page, contextHints, repairLog) {
14918
+ const widgets = this.dashboardPageWidgets(page);
14919
+ if (widgets.some((widget) => this.dashboardWidgetComponentId(widget).includes('chart'))) {
14920
+ return;
14921
+ }
14922
+ const resourcePath = this.dashboardRepairResourcePath(contextHints);
14923
+ const categoryField = this.dashboardCategoryField(page);
14924
+ const chartKey = this.uniqueDashboardWidgetKey(page, 'dashboard-chart');
14925
+ const detailKey = this.dashboardDetailWidgetKey(page) ?? this.dashboardDetailWidgetKeyFromRepairContext(contextHints);
14926
+ this.insertDashboardWidget(page, {
14927
+ key: chartKey,
14928
+ shell: {
14929
+ kind: 'dashboard-card',
14930
+ title: `Distribuicao por ${this.humanizeFieldName(categoryField)}`,
14931
+ subtitle: 'Agrupamento analitico do mesmo recurso',
14932
+ },
14933
+ definition: {
14934
+ id: 'praxis-chart',
14935
+ bindingOrder: ['chartDocument', 'queryContext', 'enableCustomization'],
14936
+ inputs: {
14937
+ queryContext: { filters: {} },
14938
+ enableCustomization: true,
14939
+ chartDocument: {
14940
+ version: '1.0.0',
14941
+ chartId: chartKey,
14942
+ kind: 'bar',
14943
+ preset: 'dashboard-breakdown',
14944
+ title: `Distribuicao por ${this.humanizeFieldName(categoryField)}`,
14945
+ subtitle: 'Clique em uma barra para refinar os detalhes',
14946
+ source: {
14947
+ kind: 'praxis.stats',
14948
+ resource: resourcePath,
14949
+ operation: 'group-by',
14950
+ options: {
14951
+ groupBy: categoryField,
14952
+ metric: 'count',
14953
+ orderBy: 'value-desc',
14954
+ limit: 12,
14955
+ },
14956
+ },
14957
+ dimensions: [{ field: categoryField, label: this.humanizeFieldName(categoryField), role: 'category' }],
14958
+ metrics: [{ field: 'count', label: 'Registros', aggregation: 'count', seriesKind: 'bar' }],
14959
+ legend: false,
14960
+ labels: true,
14961
+ tooltip: true,
14962
+ events: {
14963
+ selectionChange: { action: 'emit' },
14964
+ pointClick: { action: 'emit' },
14965
+ },
14966
+ },
14967
+ },
14968
+ },
14969
+ }, Math.max(2, widgets.length - 1));
14970
+ if (detailKey) {
14971
+ this.addDashboardQueryContextLink(page, chartKey, 'selectionChange', detailKey);
14972
+ }
14973
+ repairLog.push('dashboard-chart-added');
14974
+ }
14975
+ repairDashboardSurfaces(page, contextHints, repairLog) {
14976
+ const resourcePath = this.dashboardRepairResourcePath(contextHints);
14977
+ let repaired = false;
14978
+ for (const widget of this.dashboardPageWidgets(page)) {
14979
+ const componentId = this.dashboardWidgetComponentId(widget);
14980
+ if (!componentId.includes('table') && !componentId.includes('list') && !componentId.includes('chart')) {
14981
+ continue;
14982
+ }
14983
+ const inputs = this.dashboardWidgetInputs(widget);
14984
+ const rowActions = this.arrayFromUnknown(inputs['rowActions'])
14985
+ .map((action) => this.cloneJsonObject(this.toJsonObject(action)))
14986
+ .filter((action) => !!action);
14987
+ const surfaces = this.arrayFromUnknown(inputs['surfaces'])
14988
+ .map((action) => this.cloneJsonObject(this.toJsonObject(action)))
14989
+ .filter((action) => !!action);
14990
+ const surfaceAction = {
14991
+ id: `${this.dashboardWidgetKey(widget)}-open-360`,
14992
+ action: 'surface.open',
14993
+ title: 'Abrir 360',
14994
+ icon: 'open_in_new',
14995
+ presentation: 'modal',
14996
+ resourceSurface: {
14997
+ id: `${this.dashboardWidgetKey(widget)}-record-360`,
14998
+ title: 'Detalhes 360',
14999
+ resourcePath,
15000
+ presentation: 'modal',
15001
+ },
15002
+ widget: {
15003
+ id: 'praxis-rich-content',
15004
+ inputs: {
15005
+ resourcePath,
15006
+ document: {
15007
+ kind: 'praxis.rich-content',
15008
+ version: '1.0.0',
15009
+ nodes: [
15010
+ {
15011
+ type: 'callout',
15012
+ tone: 'info',
15013
+ icon: 'badge',
15014
+ titleExpr: '${payload.item.nomeCompleto || payload.item.name || payload.label || "Registro"}',
15015
+ message: 'Surface 360 gerada pelo dashboard para explorar o registro selecionado.',
15016
+ },
15017
+ ],
15018
+ },
15019
+ },
15020
+ },
15021
+ };
15022
+ if (!rowActions.some((action) => this.readString(this.toJsonObject(action) ?? {}, 'action') === 'surface.open')) {
15023
+ rowActions.push(surfaceAction);
15024
+ repaired = true;
15025
+ }
15026
+ if (!surfaces.some((action) => this.readString(this.toJsonObject(action) ?? {}, 'action') === 'surface.open')) {
15027
+ surfaces.push(surfaceAction);
15028
+ repaired = true;
15029
+ }
15030
+ this.setDashboardWidgetInputs(widget, { ...inputs, rowActions, surfaces });
15031
+ }
15032
+ if (repaired) {
15033
+ repairLog.push('dashboard-surfaces-added');
15034
+ }
15035
+ }
15036
+ repairDashboardConnections(page, repairLog) {
15037
+ const widgets = this.dashboardPageWidgets(page);
15038
+ const detailWidget = widgets.find((widget) => {
15039
+ const componentId = this.dashboardWidgetComponentId(widget);
15040
+ return componentId.includes('table') || componentId.includes('list');
15041
+ });
15042
+ if (!detailWidget) {
15043
+ return;
15044
+ }
15045
+ const detailKey = this.dashboardWidgetKey(detailWidget);
15046
+ const links = this.dashboardCompositionLinks(page);
15047
+ let repaired = false;
15048
+ for (const widget of widgets) {
15049
+ const componentId = this.dashboardWidgetComponentId(widget);
15050
+ const widgetKey = this.dashboardWidgetKey(widget);
15051
+ if (widgetKey === detailKey) {
15052
+ continue;
15053
+ }
15054
+ const port = componentId.includes('filter')
15055
+ ? 'requestSearch'
15056
+ : componentId.includes('chart')
15057
+ ? 'selectionChange'
15058
+ : '';
15059
+ if (!port) {
15060
+ continue;
15061
+ }
15062
+ const exists = links.some((link) => {
15063
+ const from = this.summarizeEndpoint(this.toJsonObject(link)?.['from']);
15064
+ const to = this.summarizeEndpoint(this.toJsonObject(link)?.['to']);
15065
+ const fromEndpoint = this.toJsonObject(from);
15066
+ const toEndpoint = this.toJsonObject(to);
15067
+ return this.readString(fromEndpoint ?? {}, 'widget') === widgetKey
15068
+ && this.readString(toEndpoint ?? {}, 'widget') === detailKey
15069
+ && this.readString(toEndpoint ?? {}, 'port') === 'queryContext';
15070
+ });
15071
+ if (exists) {
15072
+ continue;
15073
+ }
15074
+ links.push({
15075
+ ...this.dashboardQueryContextLink(widgetKey, port, detailKey),
15076
+ });
15077
+ repaired = true;
15078
+ }
15079
+ if (repaired) {
15080
+ const composition = this.toJsonObject(page['composition']) ?? {};
15081
+ page['composition'] = {
15082
+ ...composition,
15083
+ version: this.readString(composition, 'version') ?? '1.0.0',
15084
+ links,
15085
+ };
15086
+ repairLog.push('dashboard-widgets-connected');
15087
+ }
15088
+ }
15089
+ dashboardDetailWidgetKey(page) {
15090
+ const detailWidget = this.dashboardPageWidgets(page).find((widget) => {
15091
+ const componentId = this.dashboardWidgetComponentId(widget);
15092
+ return componentId.includes('table') || componentId.includes('list');
15093
+ });
15094
+ return detailWidget ? this.dashboardWidgetKey(detailWidget) : null;
15095
+ }
15096
+ dashboardDetailWidgetKeyFromRepairContext(contextHints) {
15097
+ const dashboardQuality = this.toJsonObject(contextHints['dashboardQuality']);
15098
+ for (const widget of this.arrayFromUnknown(dashboardQuality?.['widgets'])) {
15099
+ const record = this.toJsonObject(widget);
15100
+ const componentId = (this.readString(record, 'componentId') ?? '').toLowerCase();
15101
+ if (componentId.includes('table') || componentId.includes('list')) {
15102
+ return this.readString(record, 'key');
15103
+ }
15104
+ }
15105
+ return null;
15106
+ }
15107
+ addDashboardQueryContextLink(page, fromWidgetKey, fromPort, toWidgetKey) {
15108
+ const links = this.dashboardCompositionLinks(page);
15109
+ const link = this.dashboardQueryContextLink(fromWidgetKey, fromPort, toWidgetKey);
15110
+ if (links.some((candidate) => this.readString(candidate, 'id') === link.id)) {
15111
+ return false;
15112
+ }
15113
+ links.push(link);
15114
+ const composition = this.toJsonObject(page['composition']) ?? {};
15115
+ page['composition'] = {
15116
+ ...composition,
15117
+ version: this.readString(composition, 'version') ?? '1.0.0',
15118
+ links,
15119
+ };
15120
+ return true;
15121
+ }
15122
+ dashboardQueryContextLink(fromWidgetKey, fromPort, toWidgetKey) {
15123
+ return {
15124
+ id: `${fromWidgetKey}.${fromPort}->${toWidgetKey}.queryContext`,
15125
+ intent: 'filter',
15126
+ from: {
15127
+ kind: 'component-port',
15128
+ ref: { widget: fromWidgetKey, port: fromPort, direction: 'output' },
15129
+ },
15130
+ to: {
15131
+ kind: 'component-port',
15132
+ ref: { widget: toWidgetKey, port: 'queryContext', direction: 'input' },
15133
+ },
15134
+ transform: { kind: 'query-context' },
15135
+ };
15136
+ }
15137
+ dashboardPageWidgets(page) {
15138
+ return this.arrayFromUnknown(page['widgets'])
15139
+ .map((widget) => this.toJsonObject(widget))
15140
+ .filter((widget) => !!widget);
15141
+ }
15142
+ dashboardCompositionLinks(page) {
15143
+ const composition = this.toJsonObject(page['composition']) ?? {};
15144
+ const links = this.arrayFromUnknown(composition['links'])
15145
+ .map((link) => this.toJsonObject(link))
15146
+ .filter((link) => !!link);
15147
+ if (!composition['links']) {
15148
+ page['composition'] = { ...composition, version: '1.0.0', links };
15149
+ }
15150
+ return links;
15151
+ }
15152
+ dashboardWidgetComponentId(widget) {
15153
+ return (this.readString(widget, 'componentId')
15154
+ || this.readString(this.toJsonObject(widget['definition']) ?? {}, 'id')
15155
+ || this.readString(widget, 'type')
15156
+ || '').toLowerCase();
15157
+ }
15158
+ dashboardWidgetKey(widget) {
15159
+ return this.readString(widget, 'key') || this.readString(widget, 'id') || 'dashboard-widget';
15160
+ }
15161
+ dashboardWidgetInputs(widget) {
15162
+ return this.cloneJsonObject(this.toJsonObject(widget['inputs'])
15163
+ ?? this.toJsonObject(this.toJsonObject(widget['definition'])?.['inputs'])
15164
+ ?? this.toJsonObject(widget['inputValues'])
15165
+ ?? this.toJsonObject(widget['props'])
15166
+ ?? this.toJsonObject(widget['config'])
15167
+ ?? {}) ?? {};
15168
+ }
15169
+ setDashboardWidgetInputs(widget, inputs) {
15170
+ const definition = this.toJsonObject(widget['definition']);
15171
+ if (definition) {
15172
+ definition['inputs'] = inputs;
15173
+ widget['definition'] = definition;
15174
+ return;
15175
+ }
15176
+ widget['inputs'] = inputs;
15177
+ }
15178
+ ensureDashboardWidgetBindingOrder(widget, required) {
15179
+ const definition = this.toJsonObject(widget['definition']);
15180
+ if (!definition) {
15181
+ return;
15182
+ }
15183
+ const current = this.arrayFromUnknown(definition['bindingOrder'])
15184
+ .map((item) => `${item}`.trim())
15185
+ .filter(Boolean);
15186
+ const next = [...current];
15187
+ for (const item of required) {
15188
+ if (!next.includes(item)) {
15189
+ next.push(item);
15190
+ }
15191
+ }
15192
+ definition['bindingOrder'] = next;
15193
+ widget['definition'] = definition;
15194
+ }
15195
+ insertDashboardWidget(page, widget, index) {
15196
+ const widgets = this.dashboardPageWidgets(page);
15197
+ widgets.splice(Math.max(0, Math.min(index, widgets.length)), 0, widget);
15198
+ page['widgets'] = widgets;
15199
+ this.ensureDashboardCanvasItem(page, this.dashboardWidgetKey(widget), this.dashboardWidgetComponentId(widget));
15200
+ }
15201
+ ensureDashboardCanvasItem(page, widgetKey, componentId) {
15202
+ if (!widgetKey) {
15203
+ return;
15204
+ }
15205
+ const canvas = this.toJsonObject(page['canvas']);
15206
+ if (!canvas) {
15207
+ return;
15208
+ }
15209
+ const items = this.toJsonObject(canvas['items']) ?? {};
15210
+ if (this.toJsonObject(items[widgetKey])) {
15211
+ return;
15212
+ }
15213
+ const columns = Math.max(1, Number(canvas['columns']) || 12);
15214
+ const existingItems = Object.values(items)
15215
+ .map((item) => this.toJsonObject(item))
15216
+ .filter((item) => !!item);
15217
+ const maxRowEnd = existingItems.reduce((max, item) => {
15218
+ const row = Math.max(1, Number(item['row']) || 1);
15219
+ const rowSpan = Math.max(1, Number(item['rowSpan']) || 1);
15220
+ return Math.max(max, row + rowSpan);
15221
+ }, 1);
15222
+ const isChart = componentId.includes('chart') || widgetKey.toLowerCase().includes('chart');
15223
+ const colSpan = Math.min(columns, isChart ? Math.max(6, Math.floor(columns / 2)) : columns);
15224
+ items[widgetKey] = {
15225
+ col: 1,
15226
+ row: maxRowEnd,
15227
+ colSpan,
15228
+ rowSpan: isChart ? 5 : 3,
15229
+ };
15230
+ canvas['items'] = items;
15231
+ page['canvas'] = canvas;
15232
+ }
15233
+ uniqueDashboardWidgetKey(page, baseKey) {
15234
+ const keys = new Set(this.dashboardPageWidgets(page).map((widget) => this.dashboardWidgetKey(widget)));
15235
+ if (!keys.has(baseKey)) {
15236
+ return baseKey;
15237
+ }
15238
+ let index = 2;
15239
+ while (keys.has(`${baseKey}-${index}`)) {
15240
+ index += 1;
15241
+ }
15242
+ return `${baseKey}-${index}`;
15243
+ }
15244
+ dashboardRepairResourcePath(contextHints) {
15245
+ return this.readString(contextHints, 'resourcePath')
15246
+ ?? this.readString(this.toJsonObject(this.toJsonObject(contextHints['dashboardQuality'])?.['dto']) ?? {}, 'resourcePath')
15247
+ ?? this.dashboardFirstResourcePath(this.toJsonObject(contextHints['materializedPage']))
15248
+ ?? '/api/resource';
15249
+ }
15250
+ dashboardFirstResourcePath(page) {
15251
+ if (!page) {
15252
+ return null;
15253
+ }
15254
+ for (const widget of this.dashboardPageWidgets(page)) {
15255
+ const resourcePath = this.readString(this.dashboardWidgetInputs(widget), 'resourcePath');
15256
+ if (resourcePath) {
15257
+ return resourcePath;
15258
+ }
15259
+ }
15260
+ return null;
15261
+ }
15262
+ dashboardCategoryField(page) {
15263
+ const preferred = ['departamentoId', 'departamentoNome', 'cargoId', 'cargoNome', 'status', 'ativo'];
15264
+ const fieldIds = this.dashboardPageWidgets(page)
15265
+ .flatMap((widget) => this.arrayFromUnknown(this.dashboardWidgetInputs(widget)['selectedFieldIds']).map((field) => `${field}`));
15266
+ return preferred.find((field) => fieldIds.includes(field))
15267
+ ?? fieldIds.find((field) => !/(^id$|nome|name|email|data|date)/i.test(field))
15268
+ ?? 'status';
15269
+ }
15270
+ humanizeFieldName(field) {
15271
+ return field
15272
+ .replace(/Id$/i, '')
15273
+ .replace(/Nome$/i, '')
15274
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
15275
+ .replace(/[_-]+/g, ' ')
15276
+ .trim()
15277
+ .replace(/^./, (value) => value.toUpperCase());
15278
+ }
15279
+ normalizeText(value) {
15280
+ return value
15281
+ .normalize('NFD')
15282
+ .replace(/[\u0300-\u036f]/g, '')
15283
+ .toLowerCase();
15284
+ }
15285
+ cloneJsonObject(value) {
15286
+ if (!value) {
15287
+ return null;
15288
+ }
15289
+ return JSON.parse(JSON.stringify(value));
15290
+ }
14450
15291
  async buildTurnStreamRequest(request, prompt) {
14451
15292
  const startedAt = Date.now();
14452
15293
  const capabilitiesStartedAt = Date.now();
@@ -14639,13 +15480,14 @@ class PageBuilderAgenticAuthoringTurnFlow {
14639
15480
  };
14640
15481
  }
14641
15482
  const status = this.decorateDashboardReviewStatus(assistantMessage || this.context.describePreviewStatus(preview), intentResolution, preview);
15483
+ const reviewCanApply = this.reviewCanApply(intentResolution, preview);
14642
15484
  return {
14643
15485
  state: 'review',
14644
15486
  phase: 'review',
14645
15487
  assistantMessage: status,
14646
- quickReplies: this.mergeDashboardQualityQuickReplies(quickReplies, intentResolution, preview),
14647
- canApply: true,
14648
- statusText: this.reviewStatusText(status, true),
15488
+ quickReplies: this.reviewQuickReplies(quickReplies, intentResolution, preview),
15489
+ canApply: reviewCanApply,
15490
+ statusText: this.reviewStatusText(status, reviewCanApply),
14649
15491
  errorText: '',
14650
15492
  preview,
14651
15493
  diagnostics: this.buildTurnDiagnostics(intentResolution, preview),
@@ -14713,13 +15555,14 @@ class PageBuilderAgenticAuthoringTurnFlow {
14713
15555
  };
14714
15556
  }
14715
15557
  const status = this.decorateDashboardReviewStatus(this.context.describePreviewStatus(preview), intentResolution, preview);
15558
+ const reviewCanApply = this.reviewCanApply(intentResolution, preview);
14716
15559
  return {
14717
15560
  state: 'review',
14718
15561
  phase: 'review',
14719
15562
  assistantMessage: status,
14720
- quickReplies: this.dashboardQualityQuickReplies(intentResolution, preview),
14721
- canApply: true,
14722
- statusText: this.reviewStatusText(status, true),
15563
+ quickReplies: this.reviewQuickReplies([], intentResolution, preview),
15564
+ canApply: reviewCanApply,
15565
+ statusText: this.reviewStatusText(status, reviewCanApply),
14723
15566
  errorText: '',
14724
15567
  preview,
14725
15568
  diagnostics: this.buildTurnDiagnostics(intentResolution, preview),
@@ -15014,7 +15857,13 @@ class PageBuilderAgenticAuthoringTurnFlow {
15014
15857
  return true;
15015
15858
  }
15016
15859
  if (componentId === 'praxis-rich-content') {
15017
- return this.richContentDocumentHasMetrics(this.toJsonObject(inputs['document']));
15860
+ if (this.richContentDocumentHasMetrics(this.toJsonObject(inputs['document']))) {
15861
+ return true;
15862
+ }
15863
+ const serializedDocument = JSON.stringify(inputs['document'] ?? '').toLowerCase();
15864
+ return serializedDocument.includes('statgroup')
15865
+ || serializedDocument.includes('total filtrado')
15866
+ || serializedDocument.includes('leitura executiva');
15018
15867
  }
15019
15868
  return false;
15020
15869
  }
@@ -15068,6 +15917,9 @@ class PageBuilderAgenticAuthoringTurnFlow {
15068
15917
  if (!node) {
15069
15918
  return;
15070
15919
  }
15920
+ if (this.hasDynamicKpiBinding(node)) {
15921
+ return;
15922
+ }
15071
15923
  const value = this.readString(node, 'value')?.trim() ?? '';
15072
15924
  if (!value || value === '-' || value === '--' || value.toLowerCase() === 'n/a') {
15073
15925
  const label = this.readString(node, 'label') ?? this.readString(node, 'id') ?? 'metric';
@@ -15228,6 +16080,24 @@ class PageBuilderAgenticAuthoringTurnFlow {
15228
16080
  const normalized = status.trim();
15229
16081
  return normalized ? `${normalized} ${suffix}` : suffix;
15230
16082
  }
16083
+ dashboardReviewCanApply(intentResolution, preview) {
16084
+ const diagnostics = this.buildDashboardAuthoringDiagnostics(intentResolution, preview);
16085
+ const validation = this.toJsonObject(diagnostics?.['validation']);
16086
+ const warnings = Array.isArray(validation?.['warnings'])
16087
+ ? validation?.['warnings'].map((warning) => `${warning}`)
16088
+ : [];
16089
+ return warnings.length === 0;
16090
+ }
16091
+ reviewCanApply(intentResolution, preview) {
16092
+ return intentResolution.artifactKind === 'dashboard'
16093
+ ? this.dashboardReviewCanApply(intentResolution, preview)
16094
+ : true;
16095
+ }
16096
+ reviewQuickReplies(quickReplies, intentResolution, preview) {
16097
+ return intentResolution.artifactKind === 'dashboard'
16098
+ ? this.mergeDashboardQualityQuickReplies(quickReplies, intentResolution, preview)
16099
+ : [...quickReplies];
16100
+ }
15231
16101
  describeDashboardQualityWarning(code) {
15232
16102
  switch (code) {
15233
16103
  case 'dashboard-without-chart-widget':
@@ -15264,7 +16134,9 @@ class PageBuilderAgenticAuthoringTurnFlow {
15264
16134
  ];
15265
16135
  }
15266
16136
  dashboardQualityQuickReplies(intentResolution, preview) {
15267
- if (!preview.uiCompositionPlan) {
16137
+ const patch = this.toJsonObject(preview.compiledFormPatch)?.['patch'];
16138
+ const materializedPage = this.toJsonObject(this.toJsonObject(patch)?.['page']);
16139
+ if (!preview.uiCompositionPlan && !this.hasDashboardSnapshotWidgets(materializedPage)) {
15268
16140
  return [];
15269
16141
  }
15270
16142
  const diagnostics = this.buildDashboardAuthoringDiagnostics(intentResolution, preview);
@@ -16069,7 +16941,26 @@ class PageBuilderAgenticAuthoringTurnFlow {
16069
16941
  }
16070
16942
  const actionId = request?.action?.id?.trim();
16071
16943
  if (!actionId) {
16072
- return null;
16944
+ return this.dashboardQualityActionContextFromPrompt(request);
16945
+ }
16946
+ if (actionId.startsWith('dashboard-quality-')) {
16947
+ const changeKind = this.dashboardQualityChangeKindFromActionId(actionId);
16948
+ if (changeKind) {
16949
+ const currentPage = this.cloneJsonObject(this.toJsonObject(this.context.currentPage()));
16950
+ return {
16951
+ source: 'dashboard-quality-gate',
16952
+ kind: 'dashboard-repair-action',
16953
+ operationKind: 'modify',
16954
+ artifactKind: 'dashboard',
16955
+ changeKind,
16956
+ resourcePath: this.dashboardFirstResourcePath(currentPage) ?? '',
16957
+ ...(currentPage ? { materializedPage: currentPage } : {}),
16958
+ };
16959
+ }
16960
+ }
16961
+ const dashboardQualityContext = this.dashboardQualityActionContextFromPrompt(request);
16962
+ if (dashboardQualityContext) {
16963
+ return dashboardQualityContext;
16073
16964
  }
16074
16965
  const base = {
16075
16966
  source: 'component-capability-catalog',
@@ -16116,6 +17007,90 @@ class PageBuilderAgenticAuthoringTurnFlow {
16116
17007
  }
16117
17008
  return null;
16118
17009
  }
17010
+ dashboardQualityActionContextFromPrompt(request) {
17011
+ const text = [
17012
+ request?.prompt,
17013
+ typeof request?.action?.value === 'string' ? request.action.value : undefined,
17014
+ request?.action?.displayPrompt,
17015
+ ]
17016
+ .map((value) => value?.trim().toLowerCase())
17017
+ .find((value) => !!value) ?? '';
17018
+ const changeKind = this.dashboardQualityChangeKindFromActionText(text);
17019
+ if (!changeKind) {
17020
+ return null;
17021
+ }
17022
+ const currentPage = this.cloneJsonObject(this.toJsonObject(this.context.currentPage()));
17023
+ if (!currentPage || this.dashboardPageWidgets(currentPage).length === 0) {
17024
+ return null;
17025
+ }
17026
+ return {
17027
+ source: 'dashboard-quality-gate',
17028
+ kind: 'dashboard-repair-action',
17029
+ operationKind: 'modify',
17030
+ artifactKind: 'dashboard',
17031
+ changeKind,
17032
+ resourcePath: this.dashboardFirstResourcePath(currentPage) ?? '',
17033
+ materializedPage: currentPage,
17034
+ };
17035
+ }
17036
+ dashboardQualityChangeKindFromActionId(actionId) {
17037
+ switch (actionId) {
17038
+ case 'dashboard-quality-add-kpis':
17039
+ return 'add_dashboard_kpis';
17040
+ case 'dashboard-quality-bind-kpis':
17041
+ return 'bind_dashboard_kpis';
17042
+ case 'dashboard-quality-add-chart':
17043
+ return 'add_dashboard_chart';
17044
+ case 'dashboard-quality-add-surfaces':
17045
+ return 'add_dashboard_surfaces';
17046
+ case 'dashboard-quality-add-details':
17047
+ return 'add_dashboard_detail_widget';
17048
+ case 'dashboard-quality-connect-widgets':
17049
+ return 'connect_dashboard_widgets';
17050
+ default:
17051
+ return '';
17052
+ }
17053
+ }
17054
+ dashboardQualityChangeKindFromActionText(text) {
17055
+ const normalized = text.trim().toLowerCase();
17056
+ if (normalized.includes('placeholder') && normalized.includes('kpi')) {
17057
+ return 'bind_dashboard_kpis';
17058
+ }
17059
+ if (normalized.includes('surface.open')
17060
+ || (normalized.includes('surface') && (normalized.includes('modal') || normalized.includes('drawer')))
17061
+ || (normalized.includes('drill') && (normalized.includes('modal') || normalized.includes('drawer')))) {
17062
+ return 'add_dashboard_surfaces';
17063
+ }
17064
+ if (normalized.includes('analytical chart')
17065
+ || normalized.includes('most relevant') && normalized.includes('chart')
17066
+ || normalized.includes('grafico') && normalized.includes('analitico')
17067
+ || normalized.includes('gráfico') && normalized.includes('analítico')) {
17068
+ return 'add_dashboard_chart';
17069
+ }
17070
+ switch (normalized) {
17071
+ case 'add kpis':
17072
+ case 'bind kpi values':
17073
+ case 'vincular valores dos kpis':
17074
+ return normalized === 'add kpis' ? 'add_dashboard_kpis' : 'bind_dashboard_kpis';
17075
+ case 'add chart':
17076
+ case 'adicionar grafico':
17077
+ case 'adicionar gráfico':
17078
+ return 'add_dashboard_chart';
17079
+ case 'add surfaces':
17080
+ case 'adicionar surfaces':
17081
+ case 'adicionar superficies':
17082
+ case 'adicionar superfícies':
17083
+ return 'add_dashboard_surfaces';
17084
+ case 'add details':
17085
+ case 'adicionar detalhes':
17086
+ return 'add_dashboard_detail_widget';
17087
+ case 'connect widgets':
17088
+ case 'conectar widgets':
17089
+ return 'connect_dashboard_widgets';
17090
+ default:
17091
+ return '';
17092
+ }
17093
+ }
16119
17094
  contextualActionCandidate(contextHints) {
16120
17095
  const resourcePath = this.readString(contextHints, 'resourcePath');
16121
17096
  if (!resourcePath) {
@@ -16975,6 +17950,7 @@ class DynamicPageBuilderComponent {
16975
17950
  pageLifecycleBusy = false;
16976
17951
  pageLifecycleResetRevision = null;
16977
17952
  pageChange = new EventEmitter();
17953
+ widgetEvent = new EventEmitter();
16978
17954
  pageSaveRequested = new EventEmitter();
16979
17955
  agenticAuthoringApplied = new EventEmitter();
16980
17956
  agenticAuthoringSharedRuleHandoff = new EventEmitter();
@@ -17057,6 +18033,7 @@ class DynamicPageBuilderComponent {
17057
18033
  this.pageChange.emit(cloned);
17058
18034
  }
17059
18035
  onRuntimeWidgetEvent(event) {
18036
+ this.widgetEvent.emit(event);
17060
18037
  if (event.output !== AGENTIC_PAGE_COMPOSITION_REQUEST_OUTPUT) {
17061
18038
  return;
17062
18039
  }
@@ -17152,12 +18129,19 @@ class DynamicPageBuilderComponent {
17152
18129
  this.runtime?.openPageSettings();
17153
18130
  }
17154
18131
  saveCurrentPage() {
18132
+ if (!this.canSaveCurrentPage()) {
18133
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.reviewNeedsAttention', 'Review the pending points before saving.'));
18134
+ return;
18135
+ }
17155
18136
  const runtimeSnapshot = this.runtime?.getPageSnapshot();
17156
18137
  const cloned = this.clonePage(runtimeSnapshot || this.currentPage());
17157
18138
  this.currentPage.set(cloned);
17158
18139
  this.pageChange.emit(cloned);
17159
18140
  this.pageSaveRequested.emit(this.clonePage(cloned));
17160
18141
  }
18142
+ canSaveCurrentPage() {
18143
+ return this.hasPageWidgets() && !this.hasBlockingAgenticReview();
18144
+ }
17161
18145
  applyConfigFromAdapter(config) {
17162
18146
  if (!config.page)
17163
18147
  return;
@@ -17349,6 +18333,9 @@ class DynamicPageBuilderComponent {
17349
18333
  const widgets = this.currentPage().widgets;
17350
18334
  return !Array.isArray(widgets) || widgets.length === 0;
17351
18335
  }
18336
+ hasBlockingAgenticReview() {
18337
+ return !!this.agenticAuthoringPreviewResult()?.valid && !this.agenticAuthoringCanApply();
18338
+ }
17352
18339
  agenticAuthoringSubmitAction() {
17353
18340
  const label = this.tx('agentic.preview', 'Generate preview');
17354
18341
  return {
@@ -18102,11 +19089,34 @@ class DynamicPageBuilderComponent {
18102
19089
  ? contextHints['kind'].trim()
18103
19090
  : '';
18104
19091
  const id = (reply.id || '').trim();
19092
+ const actionText = (reply.label || reply.prompt || '').trim().toLowerCase();
18105
19093
  return source === 'component-capability-catalog'
19094
+ || source === 'dashboard-quality-gate'
19095
+ || kind === 'dashboard-repair-action'
18106
19096
  || kind === 'contextual-preview-action'
19097
+ || id.startsWith('dashboard-quality-')
19098
+ || this.isDashboardQualityQuickReplyText(actionText)
18107
19099
  || id.startsWith('chart-')
18108
19100
  || id.startsWith('table-export-');
18109
19101
  }
19102
+ isDashboardQualityQuickReplyText(text) {
19103
+ const normalized = text.trim().toLowerCase();
19104
+ return normalized === 'add kpis'
19105
+ || normalized === 'bind kpi values'
19106
+ || normalized === 'add chart'
19107
+ || normalized === 'add surfaces'
19108
+ || normalized === 'add details'
19109
+ || normalized === 'connect widgets'
19110
+ || normalized === 'adicionar kpis'
19111
+ || normalized === 'vincular valores dos kpis'
19112
+ || normalized === 'adicionar gráfico'
19113
+ || normalized === 'adicionar grafico'
19114
+ || normalized === 'adicionar surfaces'
19115
+ || normalized === 'adicionar superfícies'
19116
+ || normalized === 'adicionar superficies'
19117
+ || normalized === 'adicionar detalhes'
19118
+ || normalized === 'conectar widgets';
19119
+ }
18110
19120
  isGovernedConfirmationQuickReply(reply, contextHints) {
18111
19121
  return this.isConfirmationQuickReply(reply)
18112
19122
  && this.hasResourceContextHint(contextHints);
@@ -19574,7 +20584,7 @@ class DynamicPageBuilderComponent {
19574
20584
  return resolvePraxisPageBuilderText(this.i18n, key, fallback);
19575
20585
  }
19576
20586
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicPageBuilderComponent, deps: [{ token: i1.MatDialog }, { token: SETTINGS_PANEL_BRIDGE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
19577
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicPageBuilderComponent, isStandalone: true, selector: "praxis-dynamic-page-builder", inputs: { page: "page", context: "context", strictValidation: "strictValidation", autoPersist: "autoPersist", enableCustomization: "enableCustomization", showSettingsButton: "showSettingsButton", pageIdentity: "pageIdentity", componentInstanceId: "componentInstanceId", pageEditorComponent: "pageEditorComponent", enableAgenticAuthoring: "enableAgenticAuthoring", agenticAuthoringProvider: "agenticAuthoringProvider", agenticAuthoringModel: "agenticAuthoringModel", agenticAuthoringApiKey: "agenticAuthoringApiKey", agenticAuthoringComponentId: "agenticAuthoringComponentId", agenticAuthoringScope: "agenticAuthoringScope", agenticAuthoringEtag: "agenticAuthoringEtag", agenticAuthoringIncludeLlmDiagnostics: "agenticAuthoringIncludeLlmDiagnostics", agenticAuthoringEnableStreaming: "agenticAuthoringEnableStreaming", agenticAuthoringContextHints: "agenticAuthoringContextHints", showPageLifecycleActions: "showPageLifecycleActions", canDeleteSavedPage: "canDeleteSavedPage", pageLifecycleBusy: "pageLifecycleBusy", pageLifecycleResetRevision: "pageLifecycleResetRevision" }, outputs: { pageChange: "pageChange", pageSaveRequested: "pageSaveRequested", agenticAuthoringApplied: "agenticAuthoringApplied", agenticAuthoringSharedRuleHandoff: "agenticAuthoringSharedRuleHandoff", pageRestart: "pageRestart", savedPageDeleteRequested: "savedPageDeleteRequested" }, providers: [
20587
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicPageBuilderComponent, isStandalone: true, selector: "praxis-dynamic-page-builder", inputs: { page: "page", context: "context", strictValidation: "strictValidation", autoPersist: "autoPersist", enableCustomization: "enableCustomization", showSettingsButton: "showSettingsButton", pageIdentity: "pageIdentity", componentInstanceId: "componentInstanceId", pageEditorComponent: "pageEditorComponent", enableAgenticAuthoring: "enableAgenticAuthoring", agenticAuthoringProvider: "agenticAuthoringProvider", agenticAuthoringModel: "agenticAuthoringModel", agenticAuthoringApiKey: "agenticAuthoringApiKey", agenticAuthoringComponentId: "agenticAuthoringComponentId", agenticAuthoringScope: "agenticAuthoringScope", agenticAuthoringEtag: "agenticAuthoringEtag", agenticAuthoringIncludeLlmDiagnostics: "agenticAuthoringIncludeLlmDiagnostics", agenticAuthoringEnableStreaming: "agenticAuthoringEnableStreaming", agenticAuthoringContextHints: "agenticAuthoringContextHints", showPageLifecycleActions: "showPageLifecycleActions", canDeleteSavedPage: "canDeleteSavedPage", pageLifecycleBusy: "pageLifecycleBusy", pageLifecycleResetRevision: "pageLifecycleResetRevision" }, outputs: { pageChange: "pageChange", widgetEvent: "widgetEvent", pageSaveRequested: "pageSaveRequested", agenticAuthoringApplied: "agenticAuthoringApplied", agenticAuthoringSharedRuleHandoff: "agenticAuthoringSharedRuleHandoff", pageRestart: "pageRestart", savedPageDeleteRequested: "savedPageDeleteRequested" }, providers: [
19578
20588
  providePraxisPageBuilderI18n(),
19579
20589
  { provide: DYNAMIC_PAGE_SHELL_EDITOR, useValue: WidgetShellEditorComponent },
19580
20590
  ], viewQueries: [{ propertyName: "runtime", first: true, predicate: ["runtime"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
@@ -19935,7 +20945,7 @@ class DynamicPageBuilderComponent {
19935
20945
  [visible]="showSettings()"
19936
20946
  [canUndo]="false"
19937
20947
  [canRedo]="false"
19938
- [showSave]="hasPageWidgets()"
20948
+ [showSave]="canSaveCurrentPage()"
19939
20949
  [showPreview]="hasPageWidgets()"
19940
20950
  (add)="onAddComponent()"
19941
20951
  (settings)="openPageSettings()"
@@ -20376,7 +21386,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
20376
21386
  [visible]="showSettings()"
20377
21387
  [canUndo]="false"
20378
21388
  [canRedo]="false"
20379
- [showSave]="hasPageWidgets()"
21389
+ [showSave]="canSaveCurrentPage()"
20380
21390
  [showPreview]="hasPageWidgets()"
20381
21391
  (add)="onAddComponent()"
20382
21392
  (settings)="openPageSettings()"
@@ -20500,6 +21510,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
20500
21510
  type: Input
20501
21511
  }], pageChange: [{
20502
21512
  type: Output
21513
+ }], widgetEvent: [{
21514
+ type: Output
20503
21515
  }], pageSaveRequested: [{
20504
21516
  type: Output
20505
21517
  }], agenticAuthoringApplied: [{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisui/page-builder",
3
- "version": "8.0.0-beta.92",
3
+ "version": "8.0.0-beta.93",
4
4
  "description": "Page and widget builder utilities for Praxis UI (grid, dynamic widgets, editors).",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
@@ -8,9 +8,9 @@
8
8
  "@angular/forms": "^21.0.0",
9
9
  "@angular/cdk": "^21.0.0",
10
10
  "@angular/material": "^21.0.0",
11
- "@praxisui/ai": "^8.0.0-beta.92",
12
- "@praxisui/core": "^8.0.0-beta.92",
13
- "@praxisui/settings-panel": "^8.0.0-beta.92",
11
+ "@praxisui/ai": "^8.0.0-beta.93",
12
+ "@praxisui/core": "^8.0.0-beta.93",
13
+ "@praxisui/settings-panel": "^8.0.0-beta.93",
14
14
  "rxjs": "~7.8.0"
15
15
  },
16
16
  "dependencies": {
@@ -1,7 +1,7 @@
1
1
  import { MatDialogRef, MatDialog } from '@angular/material/dialog';
2
2
  import * as _angular_core from '@angular/core';
3
3
  import { EventEmitter, OnInit, WritableSignal, InjectionToken, Provider, OnChanges, Type, SimpleChanges } from '@angular/core';
4
- import { ComponentDocMeta, ComponentMetadataRegistry, WidgetShellConfig, WidgetShellAction, EndpointRef, ComponentPortPathSegment, LinkIntent, CompositionLink, WidgetPageDefinition, TransformKind, SurfaceOpenPayload, SettingsValueProvider as SettingsValueProvider$1, WidgetPageGroupingDefinition, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, PageIdentity, WidgetStateNode, WidgetDerivedStateNode, AiCapability, AiCapabilityCategory, AiCapabilityCatalog, AiValueKind, DomainKnowledgeChangeSetRequest, DomainKnowledgeChangeSet, DomainKnowledgeChangeSetTimelineResponse, DomainKnowledgeChangeSetFilters, DomainKnowledgeValidationResponse, DomainKnowledgeStatusTransitionRequest, DomainRuleIntakeRequest, DomainRuleIntakeResponse, DomainRuleDefinitionRequest, DomainRuleDefinition, DomainRuleSimulationRequest, DomainRuleSimulationResponse, DomainRuleStatusTransitionRequest, DomainRulePublicationRequest, DomainRulePublicationResponse, DomainRuleMaterializationFilters, DomainRuleMaterialization, DomainRuleTimelineResponse, WidgetPageCanvasLayout, WidgetPageDeviceLayouts, WidgetPageSlotAssignments, WidgetPageStateInput, WidgetInstance, ComponentContextPack, ComponentAuthoringManifest, DynamicWidgetPageComponent, SettingsPanelBridge, WidgetEventEnvelope, RichTimelineItem } from '@praxisui/core';
4
+ import { ComponentDocMeta, ComponentMetadataRegistry, WidgetShellConfig, WidgetShellAction, EndpointRef, ComponentPortPathSegment, LinkIntent, CompositionLink, WidgetPageDefinition, TransformKind, SurfaceOpenPayload, SettingsValueProvider as SettingsValueProvider$1, WidgetPageGroupingDefinition, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, PageIdentity, WidgetStateNode, WidgetDerivedStateNode, AiCapability, AiCapabilityCategory, AiCapabilityCatalog, AiValueKind, DomainKnowledgeChangeSetRequest, DomainKnowledgeChangeSet, DomainKnowledgeChangeSetTimelineResponse, DomainKnowledgeChangeSetFilters, DomainKnowledgeValidationResponse, DomainKnowledgeStatusTransitionRequest, DomainRuleIntakeRequest, DomainRuleIntakeResponse, DomainRuleDefinitionRequest, DomainRuleDefinition, DomainRuleSimulationRequest, DomainRuleSimulationResponse, DomainRuleStatusTransitionRequest, DomainRulePublicationRequest, DomainRulePublicationResponse, DomainRuleMaterializationFilters, DomainRuleMaterialization, DomainRuleTimelineResponse, WidgetPageCanvasLayout, WidgetPageDeviceLayouts, WidgetPageSlotAssignments, WidgetPageStateInput, WidgetInstance, ComponentContextPack, ComponentAuthoringManifest, DynamicWidgetPageComponent, WidgetEventEnvelope, SettingsPanelBridge, RichTimelineItem } from '@praxisui/core';
5
5
  export { WidgetShellComponent } from '@praxisui/core';
6
6
  import * as rxjs from 'rxjs';
7
7
  import { BehaviorSubject, Observable } from 'rxjs';
@@ -1670,6 +1670,7 @@ declare class DynamicPageBuilderComponent implements OnChanges {
1670
1670
  pageLifecycleBusy: boolean;
1671
1671
  pageLifecycleResetRevision: number | string | null;
1672
1672
  pageChange: EventEmitter<WidgetPageDefinition>;
1673
+ widgetEvent: EventEmitter<WidgetEventEnvelope>;
1673
1674
  pageSaveRequested: EventEmitter<WidgetPageDefinition>;
1674
1675
  agenticAuthoringApplied: EventEmitter<PageBuilderApplyResult>;
1675
1676
  agenticAuthoringSharedRuleHandoff: EventEmitter<PageBuilderAgenticAuthoringSharedRuleHandoff>;
@@ -1734,6 +1735,7 @@ declare class DynamicPageBuilderComponent implements OnChanges {
1734
1735
  addWidget(selection: string | ComponentPaletteSelection): void;
1735
1736
  openPageSettings(): void;
1736
1737
  saveCurrentPage(): void;
1738
+ canSaveCurrentPage(): boolean;
1737
1739
  applyConfigFromAdapter(config: PageBuilderConfig): void;
1738
1740
  private createAdapterHost;
1739
1741
  toggleAgenticAuthoring(): void;
@@ -1753,6 +1755,7 @@ declare class DynamicPageBuilderComponent implements OnChanges {
1753
1755
  private agenticAuthoringEmptyConversationMessage;
1754
1756
  private resolveAgenticAuthoredOpeningMessage;
1755
1757
  private isAgenticAuthoringPageBlank;
1758
+ private hasBlockingAgenticReview;
1756
1759
  agenticAuthoringSubmitAction(): PraxisAssistantShellAction;
1757
1760
  agenticAuthoringDockIcon(): string;
1758
1761
  agenticAuthoringDockBadge(): string;
@@ -1796,6 +1799,7 @@ declare class DynamicPageBuilderComponent implements OnChanges {
1796
1799
  private agenticQuickReplyGovernedConfirmationPrompt;
1797
1800
  private isResourceQuickReply;
1798
1801
  private isContextualPreviewActionQuickReply;
1802
+ private isDashboardQualityQuickReplyText;
1799
1803
  private isGovernedConfirmationQuickReply;
1800
1804
  private isConfirmationQuickReply;
1801
1805
  private hasResourceContextHint;
@@ -1905,7 +1909,7 @@ declare class DynamicPageBuilderComponent implements OnChanges {
1905
1909
  private cloneValue;
1906
1910
  tx(key: string, fallback: string): string;
1907
1911
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DynamicPageBuilderComponent, [null, { optional: true; }]>;
1908
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DynamicPageBuilderComponent, "praxis-dynamic-page-builder", never, { "page": { "alias": "page"; "required": false; }; "context": { "alias": "context"; "required": false; }; "strictValidation": { "alias": "strictValidation"; "required": false; }; "autoPersist": { "alias": "autoPersist"; "required": false; }; "enableCustomization": { "alias": "enableCustomization"; "required": false; }; "showSettingsButton": { "alias": "showSettingsButton"; "required": false; }; "pageIdentity": { "alias": "pageIdentity"; "required": false; }; "componentInstanceId": { "alias": "componentInstanceId"; "required": false; }; "pageEditorComponent": { "alias": "pageEditorComponent"; "required": false; }; "enableAgenticAuthoring": { "alias": "enableAgenticAuthoring"; "required": false; }; "agenticAuthoringProvider": { "alias": "agenticAuthoringProvider"; "required": false; }; "agenticAuthoringModel": { "alias": "agenticAuthoringModel"; "required": false; }; "agenticAuthoringApiKey": { "alias": "agenticAuthoringApiKey"; "required": false; }; "agenticAuthoringComponentId": { "alias": "agenticAuthoringComponentId"; "required": false; }; "agenticAuthoringScope": { "alias": "agenticAuthoringScope"; "required": false; }; "agenticAuthoringEtag": { "alias": "agenticAuthoringEtag"; "required": false; }; "agenticAuthoringIncludeLlmDiagnostics": { "alias": "agenticAuthoringIncludeLlmDiagnostics"; "required": false; }; "agenticAuthoringEnableStreaming": { "alias": "agenticAuthoringEnableStreaming"; "required": false; }; "agenticAuthoringContextHints": { "alias": "agenticAuthoringContextHints"; "required": false; }; "showPageLifecycleActions": { "alias": "showPageLifecycleActions"; "required": false; }; "canDeleteSavedPage": { "alias": "canDeleteSavedPage"; "required": false; }; "pageLifecycleBusy": { "alias": "pageLifecycleBusy"; "required": false; }; "pageLifecycleResetRevision": { "alias": "pageLifecycleResetRevision"; "required": false; }; }, { "pageChange": "pageChange"; "pageSaveRequested": "pageSaveRequested"; "agenticAuthoringApplied": "agenticAuthoringApplied"; "agenticAuthoringSharedRuleHandoff": "agenticAuthoringSharedRuleHandoff"; "pageRestart": "pageRestart"; "savedPageDeleteRequested": "savedPageDeleteRequested"; }, never, never, true, never>;
1912
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DynamicPageBuilderComponent, "praxis-dynamic-page-builder", never, { "page": { "alias": "page"; "required": false; }; "context": { "alias": "context"; "required": false; }; "strictValidation": { "alias": "strictValidation"; "required": false; }; "autoPersist": { "alias": "autoPersist"; "required": false; }; "enableCustomization": { "alias": "enableCustomization"; "required": false; }; "showSettingsButton": { "alias": "showSettingsButton"; "required": false; }; "pageIdentity": { "alias": "pageIdentity"; "required": false; }; "componentInstanceId": { "alias": "componentInstanceId"; "required": false; }; "pageEditorComponent": { "alias": "pageEditorComponent"; "required": false; }; "enableAgenticAuthoring": { "alias": "enableAgenticAuthoring"; "required": false; }; "agenticAuthoringProvider": { "alias": "agenticAuthoringProvider"; "required": false; }; "agenticAuthoringModel": { "alias": "agenticAuthoringModel"; "required": false; }; "agenticAuthoringApiKey": { "alias": "agenticAuthoringApiKey"; "required": false; }; "agenticAuthoringComponentId": { "alias": "agenticAuthoringComponentId"; "required": false; }; "agenticAuthoringScope": { "alias": "agenticAuthoringScope"; "required": false; }; "agenticAuthoringEtag": { "alias": "agenticAuthoringEtag"; "required": false; }; "agenticAuthoringIncludeLlmDiagnostics": { "alias": "agenticAuthoringIncludeLlmDiagnostics"; "required": false; }; "agenticAuthoringEnableStreaming": { "alias": "agenticAuthoringEnableStreaming"; "required": false; }; "agenticAuthoringContextHints": { "alias": "agenticAuthoringContextHints"; "required": false; }; "showPageLifecycleActions": { "alias": "showPageLifecycleActions"; "required": false; }; "canDeleteSavedPage": { "alias": "canDeleteSavedPage"; "required": false; }; "pageLifecycleBusy": { "alias": "pageLifecycleBusy"; "required": false; }; "pageLifecycleResetRevision": { "alias": "pageLifecycleResetRevision"; "required": false; }; }, { "pageChange": "pageChange"; "widgetEvent": "widgetEvent"; "pageSaveRequested": "pageSaveRequested"; "agenticAuthoringApplied": "agenticAuthoringApplied"; "agenticAuthoringSharedRuleHandoff": "agenticAuthoringSharedRuleHandoff"; "pageRestart": "pageRestart"; "savedPageDeleteRequested": "savedPageDeleteRequested"; }, never, never, true, never>;
1909
1913
  }
1910
1914
 
1911
1915
  export { ComponentPaletteDialogComponent, ConfirmDialogComponent, ConnectionEditorComponent, DynamicPageBuilderComponent, DynamicPageConfigEditorComponent, FloatingToolbarComponent, PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS, PAGE_BUILDER_AI_CAPABILITIES, PAGE_BUILDER_COMPONENT_CONTEXT_PACK, PAGE_BUILDER_WIDGET_AI_CATALOGS, PLACEHOLDER, PRAXIS_PAGE_BUILDER_AUTHORING_MANIFEST, PageBuilderAgenticAuthoringService, PageConfigEditorComponent, TileToolbarComponent, WidgetShellEditorComponent, clearWidgetAiCatalogs, compileUiCompositionPlan, getPageAiCatalog, getWidgetAiCapabilities, providePageBuilderWidgetAiCatalogs, registerWidgetAiCatalog, registerWidgetAiCatalogs, validateUiCompositionPlan };