@praxisui/page-builder 8.0.0-beta.103 → 8.0.0-beta.105

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.
@@ -7,7 +7,7 @@ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
7
7
  import * as i2$1 from '@angular/material/icon';
8
8
  import { MatIconModule } from '@angular/material/icon';
9
9
  import * as i2$2 from '@praxisui/core';
10
- import { PraxisIconDirective, BUILTIN_SHELL_PRESETS, providePraxisI18n, PraxisI18nService, GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, PRAXIS_GLOBAL_ACTION_CATALOG, SurfaceOpenActionEditorComponent, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, deepMerge, generateId, ComponentMetadataRegistry, domainKnowledgeTimelineToRichContentDocument, DomainRuleService, DomainKnowledgeService, SETTINGS_PANEL_BRIDGE, DynamicWidgetPageComponent, DYNAMIC_PAGE_SHELL_EDITOR } from '@praxisui/core';
10
+ import { PraxisIconDirective, BUILTIN_SHELL_PRESETS, providePraxisI18n, PraxisI18nService, GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, PRAXIS_GLOBAL_ACTION_CATALOG, SurfaceOpenActionEditorComponent, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, deepMerge, generateId, ComponentMetadataRegistry, PraxisRuntimeComponentObservationRegistryService, domainKnowledgeTimelineToRichContentDocument, DomainRuleService, DomainKnowledgeService, SETTINGS_PANEL_BRIDGE, DynamicWidgetPageComponent, DYNAMIC_PAGE_SHELL_EDITOR } from '@praxisui/core';
11
11
  export { WidgetShellComponent } from '@praxisui/core';
12
12
  import * as i3 from '@angular/material/tooltip';
13
13
  import { MatTooltipModule } from '@angular/material/tooltip';
@@ -25,7 +25,7 @@ import * as i6 from '@angular/material/divider';
25
25
  import { MatDividerModule } from '@angular/material/divider';
26
26
  import * as i6$1 from '@angular/material/select';
27
27
  import { MatSelectModule } from '@angular/material/select';
28
- import { BehaviorSubject, merge, timeout, map, catchError, throwError, from, firstValueFrom, share, concatMap, of, timer, takeUntil, filter, take } from 'rxjs';
28
+ import { BehaviorSubject, merge, timeout, map, catchError, throwError, from, firstValueFrom, share, concatMap, of, timer, takeUntil, Subject, filter, take } from 'rxjs';
29
29
  import { SETTINGS_PANEL_DATA } from '@praxisui/settings-panel';
30
30
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
31
31
  import * as i7 from '@angular/material/tabs';
@@ -181,6 +181,12 @@ class FloatingToolbarComponent {
181
181
  canRedo = false;
182
182
  showSave = true;
183
183
  showPreview = true;
184
+ editingEnabled = true;
185
+ previewActive = false;
186
+ connectionMode = false;
187
+ modeLabel = '';
188
+ previewLabel = 'Pre-visualizar';
189
+ exitPreviewLabel = 'Voltar para edicao';
184
190
  add = new EventEmitter();
185
191
  undo = new EventEmitter();
186
192
  redo = new EventEmitter();
@@ -188,79 +194,107 @@ class FloatingToolbarComponent {
188
194
  preview = new EventEmitter();
189
195
  save = new EventEmitter();
190
196
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FloatingToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
191
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: FloatingToolbarComponent, isStandalone: true, selector: "praxis-floating-toolbar", inputs: { visible: "visible", canUndo: "canUndo", canRedo: "canRedo", showSave: "showSave", showPreview: "showPreview" }, outputs: { add: "add", undo: "undo", redo: "redo", settings: "settings", preview: "preview", save: "save" }, ngImport: i0, template: `
197
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: FloatingToolbarComponent, isStandalone: true, selector: "praxis-floating-toolbar", inputs: { visible: "visible", canUndo: "canUndo", canRedo: "canRedo", showSave: "showSave", showPreview: "showPreview", editingEnabled: "editingEnabled", previewActive: "previewActive", connectionMode: "connectionMode", modeLabel: "modeLabel", previewLabel: "previewLabel", exitPreviewLabel: "exitPreviewLabel" }, outputs: { add: "add", undo: "undo", redo: "redo", settings: "settings", preview: "preview", save: "save" }, ngImport: i0, template: `
192
198
  @if (visible) {
193
- <div class="pdx-floating-toolbar">
199
+ <div
200
+ class="pdx-floating-toolbar"
201
+ [class.pdx-floating-toolbar--connections]="connectionMode"
202
+ [class.pdx-floating-toolbar--preview]="previewActive"
203
+ >
204
+ @if (modeLabel) {
205
+ <span class="pdx-mode-chip" [attr.data-testid]="'page-builder-toolbar-mode'">{{ modeLabel }}</span>
206
+ }
194
207
  <div class="pdx-actions">
195
- <button mat-mini-fab color="primary" (click)="add.emit()" [matTooltip]="'Inserir componente'" aria-label="Inserir componente">
208
+ <button mat-mini-fab color="primary" (click)="add.emit()" [disabled]="!editingEnabled" [matTooltip]="'Inserir componente'" aria-label="Inserir componente">
196
209
  <mat-icon [praxisIcon]="'add'"></mat-icon>
197
210
  </button>
198
211
  @if (showSave) {
199
- <button mat-mini-fab color="accent" (click)="save.emit()" [matTooltip]="'Salvar pagina'" aria-label="Salvar pagina">
212
+ <button mat-mini-fab color="accent" (click)="save.emit()" [disabled]="!editingEnabled" [matTooltip]="'Salvar pagina'" aria-label="Salvar pagina">
200
213
  <mat-icon [praxisIcon]="'save'"></mat-icon>
201
214
  </button>
202
215
  }
203
216
  @if (canUndo) {
204
- <button mat-mini-fab (click)="undo.emit()" [matTooltip]="'Desfazer'" aria-label="Desfazer">
217
+ <button mat-mini-fab (click)="undo.emit()" [disabled]="!editingEnabled" [matTooltip]="'Desfazer'" aria-label="Desfazer">
205
218
  <mat-icon [praxisIcon]="'undo'"></mat-icon>
206
219
  </button>
207
220
  }
208
221
  @if (canRedo) {
209
- <button mat-mini-fab (click)="redo.emit()" [matTooltip]="'Refazer'" aria-label="Refazer">
222
+ <button mat-mini-fab (click)="redo.emit()" [disabled]="!editingEnabled" [matTooltip]="'Refazer'" aria-label="Refazer">
210
223
  <mat-icon [praxisIcon]="'redo'"></mat-icon>
211
224
  </button>
212
225
  }
213
- <button mat-mini-fab (click)="settings.emit()" [matTooltip]="'Configuracoes da pagina'" aria-label="Configuracoes da pagina">
226
+ <button mat-mini-fab (click)="settings.emit()" [disabled]="!editingEnabled" [matTooltip]="'Configuracoes da pagina'" aria-label="Configuracoes da pagina">
214
227
  <mat-icon [praxisIcon]="'settings'"></mat-icon>
215
228
  </button>
216
229
  @if (showPreview) {
217
- <button mat-mini-fab (click)="preview.emit()" [matTooltip]="'Pre-visualizar'" aria-label="Pre-visualizar">
218
- <mat-icon [praxisIcon]="'visibility'"></mat-icon>
230
+ <button
231
+ mat-mini-fab
232
+ (click)="preview.emit()"
233
+ [class.pdx-preview-toggle--active]="previewActive"
234
+ [matTooltip]="previewActive ? exitPreviewLabel : previewLabel"
235
+ [attr.aria-label]="previewActive ? exitPreviewLabel : previewLabel"
236
+ [attr.aria-pressed]="previewActive"
237
+ >
238
+ <mat-icon [praxisIcon]="previewActive ? 'edit' : 'visibility'"></mat-icon>
219
239
  </button>
220
240
  }
221
241
  <ng-content select="[pdx-toolbar-extra]"></ng-content>
222
242
  </div>
223
243
  </div>
224
244
  }
225
- `, isInline: true, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-floating-toolbar{position:absolute;right:16px;bottom:16px;display:flex;gap:8px;align-items:center;pointer-events:auto}.pdx-actions{display:flex;gap:8px}@media(max-width:720px){.pdx-actions{gap:6px}.pdx-floating-toolbar{right:12px;bottom:12px}}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
245
+ `, isInline: true, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-floating-toolbar{position:absolute;right:16px;bottom:16px;display:flex;gap:8px;align-items:center;pointer-events:auto}.pdx-floating-toolbar--connections{top:16px;bottom:auto}.pdx-mode-chip{display:inline-flex;align-items:center;min-height:28px;max-width:148px;padding:3px 9px;border:1px solid rgba(103,80,164,.22);border-radius:999px;background:#ffffffeb;color:#3f2d75;font-size:11px;font-weight:700;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-shadow:0 8px 22px #0f172a1f}.pdx-actions{display:flex;gap:8px}.pdx-preview-toggle--active{outline:2px solid rgba(103,80,164,.48);outline-offset:2px}@media(max-width:720px){.pdx-actions{gap:6px}.pdx-floating-toolbar{right:12px;bottom:12px}.pdx-floating-toolbar--connections{top:12px;bottom:auto}.pdx-mode-chip{max-width:112px}}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
226
246
  }
227
247
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FloatingToolbarComponent, decorators: [{
228
248
  type: Component,
229
249
  args: [{ selector: 'praxis-floating-toolbar', standalone: true, imports: [MatButtonModule, MatIconModule, MatTooltipModule, PraxisIconDirective], template: `
230
250
  @if (visible) {
231
- <div class="pdx-floating-toolbar">
251
+ <div
252
+ class="pdx-floating-toolbar"
253
+ [class.pdx-floating-toolbar--connections]="connectionMode"
254
+ [class.pdx-floating-toolbar--preview]="previewActive"
255
+ >
256
+ @if (modeLabel) {
257
+ <span class="pdx-mode-chip" [attr.data-testid]="'page-builder-toolbar-mode'">{{ modeLabel }}</span>
258
+ }
232
259
  <div class="pdx-actions">
233
- <button mat-mini-fab color="primary" (click)="add.emit()" [matTooltip]="'Inserir componente'" aria-label="Inserir componente">
260
+ <button mat-mini-fab color="primary" (click)="add.emit()" [disabled]="!editingEnabled" [matTooltip]="'Inserir componente'" aria-label="Inserir componente">
234
261
  <mat-icon [praxisIcon]="'add'"></mat-icon>
235
262
  </button>
236
263
  @if (showSave) {
237
- <button mat-mini-fab color="accent" (click)="save.emit()" [matTooltip]="'Salvar pagina'" aria-label="Salvar pagina">
264
+ <button mat-mini-fab color="accent" (click)="save.emit()" [disabled]="!editingEnabled" [matTooltip]="'Salvar pagina'" aria-label="Salvar pagina">
238
265
  <mat-icon [praxisIcon]="'save'"></mat-icon>
239
266
  </button>
240
267
  }
241
268
  @if (canUndo) {
242
- <button mat-mini-fab (click)="undo.emit()" [matTooltip]="'Desfazer'" aria-label="Desfazer">
269
+ <button mat-mini-fab (click)="undo.emit()" [disabled]="!editingEnabled" [matTooltip]="'Desfazer'" aria-label="Desfazer">
243
270
  <mat-icon [praxisIcon]="'undo'"></mat-icon>
244
271
  </button>
245
272
  }
246
273
  @if (canRedo) {
247
- <button mat-mini-fab (click)="redo.emit()" [matTooltip]="'Refazer'" aria-label="Refazer">
274
+ <button mat-mini-fab (click)="redo.emit()" [disabled]="!editingEnabled" [matTooltip]="'Refazer'" aria-label="Refazer">
248
275
  <mat-icon [praxisIcon]="'redo'"></mat-icon>
249
276
  </button>
250
277
  }
251
- <button mat-mini-fab (click)="settings.emit()" [matTooltip]="'Configuracoes da pagina'" aria-label="Configuracoes da pagina">
278
+ <button mat-mini-fab (click)="settings.emit()" [disabled]="!editingEnabled" [matTooltip]="'Configuracoes da pagina'" aria-label="Configuracoes da pagina">
252
279
  <mat-icon [praxisIcon]="'settings'"></mat-icon>
253
280
  </button>
254
281
  @if (showPreview) {
255
- <button mat-mini-fab (click)="preview.emit()" [matTooltip]="'Pre-visualizar'" aria-label="Pre-visualizar">
256
- <mat-icon [praxisIcon]="'visibility'"></mat-icon>
282
+ <button
283
+ mat-mini-fab
284
+ (click)="preview.emit()"
285
+ [class.pdx-preview-toggle--active]="previewActive"
286
+ [matTooltip]="previewActive ? exitPreviewLabel : previewLabel"
287
+ [attr.aria-label]="previewActive ? exitPreviewLabel : previewLabel"
288
+ [attr.aria-pressed]="previewActive"
289
+ >
290
+ <mat-icon [praxisIcon]="previewActive ? 'edit' : 'visibility'"></mat-icon>
257
291
  </button>
258
292
  }
259
293
  <ng-content select="[pdx-toolbar-extra]"></ng-content>
260
294
  </div>
261
295
  </div>
262
296
  }
263
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-floating-toolbar{position:absolute;right:16px;bottom:16px;display:flex;gap:8px;align-items:center;pointer-events:auto}.pdx-actions{display:flex;gap:8px}@media(max-width:720px){.pdx-actions{gap:6px}.pdx-floating-toolbar{right:12px;bottom:12px}}\n"] }]
297
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-floating-toolbar{position:absolute;right:16px;bottom:16px;display:flex;gap:8px;align-items:center;pointer-events:auto}.pdx-floating-toolbar--connections{top:16px;bottom:auto}.pdx-mode-chip{display:inline-flex;align-items:center;min-height:28px;max-width:148px;padding:3px 9px;border:1px solid rgba(103,80,164,.22);border-radius:999px;background:#ffffffeb;color:#3f2d75;font-size:11px;font-weight:700;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-shadow:0 8px 22px #0f172a1f}.pdx-actions{display:flex;gap:8px}.pdx-preview-toggle--active{outline:2px solid rgba(103,80,164,.48);outline-offset:2px}@media(max-width:720px){.pdx-actions{gap:6px}.pdx-floating-toolbar{right:12px;bottom:12px}.pdx-floating-toolbar--connections{top:12px;bottom:auto}.pdx-mode-chip{max-width:112px}}\n"] }]
264
298
  }], propDecorators: { visible: [{
265
299
  type: Input
266
300
  }], canUndo: [{
@@ -271,6 +305,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
271
305
  type: Input
272
306
  }], showPreview: [{
273
307
  type: Input
308
+ }], editingEnabled: [{
309
+ type: Input
310
+ }], previewActive: [{
311
+ type: Input
312
+ }], connectionMode: [{
313
+ type: Input
314
+ }], modeLabel: [{
315
+ type: Input
316
+ }], previewLabel: [{
317
+ type: Input
318
+ }], exitPreviewLabel: [{
319
+ type: Input
274
320
  }], add: [{
275
321
  type: Output
276
322
  }], undo: [{
@@ -337,6 +383,7 @@ class ComponentPaletteDialogComponent {
337
383
  const q = (this.query() || '').toLowerCase();
338
384
  const allowIds = new Set((this.data?.allowedWidgetIds || []).map((s) => s.toLowerCase()));
339
385
  const allowTags = new Set((this.data?.allowedWidgetTags || []).map((s) => s.toLowerCase()));
386
+ const allowPresets = new Set((this.data?.allowedPresetIds || []).map((s) => s.toLowerCase()));
340
387
  const metadataById = new Map(this.registry.getAll().map((meta) => [meta.id, meta]));
341
388
  return list.filter((entry) => {
342
389
  const meta = metadataById.get(entry.componentId);
@@ -349,6 +396,8 @@ class ComponentPaletteDialogComponent {
349
396
  return false;
350
397
  if (allowTags.size > 0 && !meta.tags?.some(t => allowTags.has(t.toLowerCase())))
351
398
  return false;
399
+ if (entry.presetId && allowPresets.size > 0 && !allowPresets.has(entry.presetId.toLowerCase()))
400
+ return false;
352
401
  if (typeof this.data?.predicate === 'function' && !this.data.predicate(meta))
353
402
  return false;
354
403
  return true;
@@ -2390,8 +2439,22 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2390
2439
  'praxis.pageBuilder.editor.hints.schemaInitial': 'Define the initial value of this state path. This helps the page start in a consistent state even before remote connections and data.',
2391
2440
  'praxis.pageBuilder.editor.hints.templateJson': 'JSON templates are useful to generate complete derived objects, such as texts, summary cards or shell settings.',
2392
2441
  'praxis.pageBuilder.editor.hints.transformerOptions': 'Pass the registered transformer options here. Prefer lean JSON with only the parameters actually used by the runtime.',
2442
+ 'praxis.pageBuilder.toolbar.preview': 'Preview',
2443
+ 'praxis.pageBuilder.toolbar.exitPreview': 'Back to editing',
2444
+ 'praxis.pageBuilder.builderMode.editing': 'Editing',
2445
+ 'praxis.pageBuilder.builderMode.connections': 'Connections',
2446
+ 'praxis.pageBuilder.builderMode.ai': 'AI',
2447
+ 'praxis.pageBuilder.builderMode.preview': 'Preview',
2448
+ 'praxis.pageBuilder.builderMode.presentation': 'Presentation',
2449
+ 'praxis.pageBuilder.premiumReadiness.actions.openPageSettings': 'Open page settings',
2450
+ 'praxis.pageBuilder.premiumReadiness.actions.reviewTheme': 'Review theme',
2451
+ 'praxis.pageBuilder.premiumReadiness.actions.openDeviceLayouts': 'Open layouts',
2452
+ 'praxis.pageBuilder.premiumReadiness.actions.openConnections': 'Open connections',
2453
+ 'praxis.pageBuilder.premiumReadiness.actions.openWidgetConfig': 'Open widget',
2454
+ 'praxis.pageBuilder.premiumReadiness.actions.focusChart': 'Focus chart',
2393
2455
  'praxis.pageBuilder.connections.toggle': 'Edit connections',
2394
2456
  'praxis.pageBuilder.connections.toggleAria': 'Edit connections',
2457
+ 'praxis.pageBuilder.connections.close': 'Close connections',
2395
2458
  'praxis.pageBuilder.connections.title': 'Connections',
2396
2459
  'praxis.pageBuilder.connections.editor.panelAria': 'Connection editor',
2397
2460
  'praxis.pageBuilder.connections.editor.eyebrow': 'Radial connection studio',
@@ -2549,12 +2612,12 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2549
2612
  'praxis.pageBuilder.agentic.header.title.widget': 'Praxis widget copilot',
2550
2613
  'praxis.pageBuilder.agentic.header.title.review': 'Praxis review copilot',
2551
2614
  'praxis.pageBuilder.agentic.header.title.governed': 'Praxis governed copilot',
2552
- 'praxis.pageBuilder.agentic.header.subtitle.page': 'Turn intent into layout, widgets, and governed materializations.',
2553
- 'praxis.pageBuilder.agentic.header.subtitle.route': 'Authoring page route {route}.',
2615
+ 'praxis.pageBuilder.agentic.header.subtitle.page': 'Turn a domain need into a table, form, or dashboard.',
2616
+ 'praxis.pageBuilder.agentic.header.subtitle.route': 'Creating or adjusting page {route}.',
2554
2617
  'praxis.pageBuilder.agentic.header.subtitle.widget': 'Focused on {target}.',
2555
- 'praxis.pageBuilder.agentic.header.subtitle.reviewBlocked': 'Preview ready for governed review.',
2556
- 'praxis.pageBuilder.agentic.header.subtitle.review': 'Preview ready for review and persistence.',
2557
- 'praxis.pageBuilder.agentic.header.subtitle.governed': 'Continue the governed semantic-decision flow.',
2618
+ 'praxis.pageBuilder.agentic.header.subtitle.reviewBlocked': 'Preview ready, with points to review.',
2619
+ 'praxis.pageBuilder.agentic.header.subtitle.review': 'Preview ready to review and save.',
2620
+ 'praxis.pageBuilder.agentic.header.subtitle.governed': 'Continue the rule review before creating the screen.',
2558
2621
  'praxis.pageBuilder.agentic.header.mode.page': 'Page',
2559
2622
  'praxis.pageBuilder.agentic.header.mode.widget': 'Widget',
2560
2623
  'praxis.pageBuilder.agentic.header.mode.governed': 'Governed',
@@ -2570,13 +2633,13 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2570
2633
  'praxis.pageBuilder.agentic.dock.badgeGoverned': 'Governed',
2571
2634
  'praxis.pageBuilder.agentic.dock.badgeReady': 'Ready',
2572
2635
  'praxis.pageBuilder.agentic.dock.summaryReview': 'Preview ready. Reopen to review or save.',
2573
- 'praxis.pageBuilder.agentic.dock.summaryGoverned': 'Governed handoff preserved. Continue the semantic decision flow.',
2636
+ 'praxis.pageBuilder.agentic.dock.summaryGoverned': 'Review preserved. Continue where you left off.',
2574
2637
  'praxis.pageBuilder.agentic.dock.summaryIdle': 'Conversation preserved. Continue where you stopped.',
2575
2638
  'praxis.pageBuilder.agentic.promptLabel': 'Message',
2576
2639
  'praxis.pageBuilder.agentic.promptPlaceholder': 'Describe the page, dashboard, form, or change you need.',
2577
2640
  'praxis.pageBuilder.agentic.emptyConversation': 'Describe the outcome you want. I will ground the context, prepare a governed preview, and wait for review before applying anything.',
2578
- 'praxis.pageBuilder.agentic.emptyConversation.blankGeneric': 'This host page is still blank. Tell me what decision or activity this app needs to support. I can suggest a dashboard, table, form, or review flow, then turn it into a governed preview for you to review before anything changes.',
2579
- 'praxis.pageBuilder.agentic.emptyConversation.existingPage': 'Tell me what you want to improve here. I can read the current layout, widgets, route, and governed context, then prepare a preview for you to review before anything changes.',
2641
+ 'praxis.pageBuilder.agentic.emptyConversation.blankGeneric': 'This screen is still empty. Tell me which domain activity it should support. I can suggest a dashboard, table, or form and prepare a preview for you to review before saving.',
2642
+ 'praxis.pageBuilder.agentic.emptyConversation.existingPage': 'Tell me what you want to improve on this screen. I will read what already exists and prepare a preview for you to review before saving.',
2580
2643
  'praxis.pageBuilder.agentic.conversationAria': 'AI conversation',
2581
2644
  'praxis.pageBuilder.agentic.quickRepliesAria': 'Quick replies',
2582
2645
  'praxis.pageBuilder.agentic.contextAria': 'Active context',
@@ -2666,6 +2729,7 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2666
2729
  'praxis.pageBuilder.agentic.dragHandleAria': 'Move AI assistant',
2667
2730
  'praxis.pageBuilder.agentic.resizeHandleAria': 'Resize AI assistant',
2668
2731
  'praxis.pageBuilder.agentic.resizeHandleTooltip': 'Resize',
2732
+ 'praxis.pageBuilder.agentic.submit': 'Send request',
2669
2733
  'praxis.pageBuilder.agentic.preview': 'Generate preview',
2670
2734
  'praxis.pageBuilder.agentic.persist': 'Save',
2671
2735
  'praxis.pageBuilder.pageLifecycle.restart': 'Restart page',
@@ -2692,8 +2756,39 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2692
2756
  'praxis.pageBuilder.agentic.status.acceptedRelabelField': 'Field label updated.',
2693
2757
  'praxis.pageBuilder.agentic.status.saving': 'Saving page...',
2694
2758
  'praxis.pageBuilder.agentic.status.saved': 'Page saved.',
2695
- 'praxis.pageBuilder.agentic.status.sharedRuleTargetSelected': 'Shared-rule target selected. Continue by creating the governed definition.',
2696
- 'praxis.pageBuilder.agentic.sharedRuleCockpit.targetSelected': 'Shared-rule target selected. The next safe step is creating the governed definition.',
2759
+ 'praxis.pageBuilder.agentic.status.sharedRuleTargetSelected': 'Continue this request in the rule review.',
2760
+ 'praxis.pageBuilder.agentic.governedRoute.streamUnavailable': 'This request needs to continue through governed business-rule review. I will not create a local preview while that review is unavailable.',
2761
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.title': 'Governed rule review',
2762
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.description': 'Review the business rule before creating or saving screen changes.',
2763
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.expand': 'Expand',
2764
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.collapse': 'Collapse',
2765
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.targetSelected': 'Rule identified. The next safe step is reviewing the rule before creating the screen.',
2766
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.running': 'Running review step',
2767
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.definitionId': 'Rule',
2768
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.simulation': 'Simulation',
2769
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.publication': 'Publication',
2770
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.materializations': 'Created screens',
2771
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.timeline': 'History',
2772
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.enforcementState': 'Validation',
2773
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.enforcementMatrix': 'Change validation',
2774
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.enforcementMatrixDescription': 'Changes the platform can apply after publication.',
2775
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.pending': 'pending',
2776
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.applied': 'applied',
2777
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.waiting': 'waiting',
2778
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_definition.label': 'Review rule',
2779
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_definition.description': 'Open or create the governed rule review.',
2780
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.simulate.label': 'Simulate',
2781
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.simulate.description': 'Test the result before publishing.',
2782
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.approve.label': 'Approve',
2783
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.approve.description': 'Approve the rule after review.',
2784
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.publish.label': 'Publish changes',
2785
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.publish.description': 'Publish the rule and prepare derived screens.',
2786
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.materialize.label': 'View created screens',
2787
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.materialize.description': 'View the screens generated from the approved rule.',
2788
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.validate_enforcement.label': 'Validate application',
2789
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.validate_enforcement.description': 'Check whether published changes are ready to use.',
2790
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_timeline.label': 'View history',
2791
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_timeline.description': 'Open the safe history for this decision.',
2697
2792
  'praxis.pageBuilder.agentic.projectKnowledgeCockpit.timeline': 'Safe timeline',
2698
2793
  'praxis.pageBuilder.agentic.projectKnowledgeCockpit.timelineEmpty': 'No safe timeline events published for this change-set yet.',
2699
2794
  'praxis.pageBuilder.agentic.projectKnowledgeCockpit.rejected': 'Project Knowledge change-set rejected. No governed knowledge projection was applied.',
@@ -2704,7 +2799,6 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2704
2799
  'praxis.pageBuilder.agentic.errors.streamTimeout': 'The assistant took too long to finish this request. Try again with a narrower request or review the active context.',
2705
2800
  'praxis.pageBuilder.agentic.errors.streamProcessing': 'The assistant could not finish this authoring request. Try again or ask support to review the diagnostics.',
2706
2801
  'praxis.pageBuilder.agentic.errors.streamConnection': 'The assistant stream was interrupted before the turn finished. Try again or ask support to check the stream connection.',
2707
- 'praxis.pageBuilder.agentic.governedRoute.streamUnavailable': 'This request must continue through the governed semantic-decision flow in /api/praxis/config/domain-rules. The backend stream is unavailable, so local preview/apply is blocked.',
2708
2802
  'praxis.pageBuilder.agentic.errors.duplicateField': 'This field already exists in the selected form.',
2709
2803
  'praxis.pageBuilder.agentic.errors.nonLocalFieldRemoval': 'Only local fields created by AI can be removed in this flow.',
2710
2804
  'praxis.pageBuilder.agentic.errors.invalidTableContract': 'I found the data source, but the generated plan used properties that are incompatible with the table component. I will adjust it to use only supported fields.',
@@ -2834,8 +2928,22 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
2834
2928
  'praxis.pageBuilder.editor.hints.schemaInitial': 'Defina o valor inicial desse caminho de estado. Isso ajuda a página a nascer em um estado consistente mesmo antes de conexões e dados remotos.',
2835
2929
  'praxis.pageBuilder.editor.hints.templateJson': 'Modelos em JSON são úteis para gerar objetos derivados completos, como textos, cartões de resumo ou configurações de shell.',
2836
2930
  'praxis.pageBuilder.editor.hints.transformerOptions': 'Passe aqui as opções do transformador registrado. Prefira JSON enxuto com os parâmetros realmente usados pelo runtime.',
2931
+ 'praxis.pageBuilder.toolbar.preview': 'Pré-visualizar',
2932
+ 'praxis.pageBuilder.toolbar.exitPreview': 'Voltar para edição',
2933
+ 'praxis.pageBuilder.builderMode.editing': 'Edição',
2934
+ 'praxis.pageBuilder.builderMode.connections': 'Conexões',
2935
+ 'praxis.pageBuilder.builderMode.ai': 'IA',
2936
+ 'praxis.pageBuilder.builderMode.preview': 'Prévia',
2937
+ 'praxis.pageBuilder.builderMode.presentation': 'Apresentação',
2938
+ 'praxis.pageBuilder.premiumReadiness.actions.openPageSettings': 'Abrir configurações da página',
2939
+ 'praxis.pageBuilder.premiumReadiness.actions.reviewTheme': 'Revisar tema',
2940
+ 'praxis.pageBuilder.premiumReadiness.actions.openDeviceLayouts': 'Abrir layouts',
2941
+ 'praxis.pageBuilder.premiumReadiness.actions.openConnections': 'Abrir conexões',
2942
+ 'praxis.pageBuilder.premiumReadiness.actions.openWidgetConfig': 'Abrir widget',
2943
+ 'praxis.pageBuilder.premiumReadiness.actions.focusChart': 'Focar gráfico',
2837
2944
  'praxis.pageBuilder.connections.toggle': 'Editar conexões',
2838
2945
  'praxis.pageBuilder.connections.toggleAria': 'Editar conexões',
2946
+ 'praxis.pageBuilder.connections.close': 'Fechar conexões',
2839
2947
  'praxis.pageBuilder.connections.title': 'Conexões',
2840
2948
  'praxis.pageBuilder.connections.editor.panelAria': 'Editor de conexões',
2841
2949
  'praxis.pageBuilder.connections.editor.eyebrow': 'Estúdio radial de conexões',
@@ -2993,12 +3101,12 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
2993
3101
  'praxis.pageBuilder.agentic.header.title.widget': 'Copiloto de componente Praxis',
2994
3102
  'praxis.pageBuilder.agentic.header.title.review': 'Copiloto de revisão Praxis',
2995
3103
  'praxis.pageBuilder.agentic.header.title.governed': 'Copiloto governado Praxis',
2996
- 'praxis.pageBuilder.agentic.header.subtitle.page': 'Transforme intenção em layout, widgets e materializações governadas.',
2997
- 'praxis.pageBuilder.agentic.header.subtitle.route': 'Autoria da rota {route}.',
3104
+ 'praxis.pageBuilder.agentic.header.subtitle.page': 'Transforme uma necessidade do domínio em tabela, formulário ou painel.',
3105
+ 'praxis.pageBuilder.agentic.header.subtitle.route': 'Criando ou ajustando a página {route}.',
2998
3106
  'praxis.pageBuilder.agentic.header.subtitle.widget': 'Foco em {target}.',
2999
- 'praxis.pageBuilder.agentic.header.subtitle.reviewBlocked': 'Prévia pronta para revisão governada.',
3000
- 'praxis.pageBuilder.agentic.header.subtitle.review': 'Prévia pronta para revisão e persistência.',
3001
- 'praxis.pageBuilder.agentic.header.subtitle.governed': 'Continue o fluxo governado de decisão semântica.',
3107
+ 'praxis.pageBuilder.agentic.header.subtitle.reviewBlocked': 'Prévia pronta, com pontos para revisar.',
3108
+ 'praxis.pageBuilder.agentic.header.subtitle.review': 'Prévia pronta para revisar e salvar.',
3109
+ 'praxis.pageBuilder.agentic.header.subtitle.governed': 'Continue a revisão da regra antes de criar a tela.',
3002
3110
  'praxis.pageBuilder.agentic.header.mode.page': 'Página',
3003
3111
  'praxis.pageBuilder.agentic.header.mode.widget': 'Widget',
3004
3112
  'praxis.pageBuilder.agentic.header.mode.governed': 'Governado',
@@ -3014,13 +3122,13 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
3014
3122
  'praxis.pageBuilder.agentic.dock.badgeGoverned': 'Governado',
3015
3123
  'praxis.pageBuilder.agentic.dock.badgeReady': 'Pronto',
3016
3124
  'praxis.pageBuilder.agentic.dock.summaryReview': 'Prévia pronta. Reabra para revisar ou salvar.',
3017
- 'praxis.pageBuilder.agentic.dock.summaryGoverned': 'Handoff governado preservado. Continue o fluxo de decisão semântica.',
3125
+ 'praxis.pageBuilder.agentic.dock.summaryGoverned': 'Revisão preservada. Continue de onde parou.',
3018
3126
  'praxis.pageBuilder.agentic.dock.summaryIdle': 'Conversa preservada. Continue de onde parou.',
3019
3127
  'praxis.pageBuilder.agentic.promptLabel': 'Mensagem',
3020
3128
  'praxis.pageBuilder.agentic.promptPlaceholder': 'Descreva a página, dashboard, formulário ou alteração que você precisa.',
3021
3129
  'praxis.pageBuilder.agentic.emptyConversation': 'Descreva o resultado que você quer. Vou fundamentar o contexto, preparar uma prévia governada e aguardar revisão antes de aplicar qualquer mudança.',
3022
- 'praxis.pageBuilder.agentic.emptyConversation.blankGeneric': 'Esta página do host ainda está em branco. Conte qual decisão ou atividade este app precisa apoiar. Posso sugerir um dashboard, tabela, formulário ou fluxo de revisão e transformar isso em uma prévia governada para você revisar antes de qualquer mudança.',
3023
- 'praxis.pageBuilder.agentic.emptyConversation.existingPage': 'Conte o que você quer melhorar aqui. Posso ler o layout atual, widgets, rota e contexto governado, depois preparar uma prévia para você revisar antes de qualquer mudança.',
3130
+ 'praxis.pageBuilder.agentic.emptyConversation.blankGeneric': 'Esta tela ainda está vazia. Diga qual atividade do domínio ela precisa apoiar. Posso sugerir um painel, tabela ou formulário e montar uma prévia para você revisar antes de salvar.',
3131
+ 'praxis.pageBuilder.agentic.emptyConversation.existingPage': 'Diga o que você quer melhorar nesta tela. Eu leio o que existe e preparo uma prévia para você revisar antes de salvar.',
3024
3132
  'praxis.pageBuilder.agentic.conversationAria': 'Conversa com IA',
3025
3133
  'praxis.pageBuilder.agentic.quickRepliesAria': 'Respostas rápidas',
3026
3134
  'praxis.pageBuilder.agentic.contextAria': 'Contexto ativo',
@@ -3101,7 +3209,7 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
3101
3209
  'praxis.pageBuilder.agentic.resourceDiscovery.useResource': 'Usar {resourcePath}',
3102
3210
  'praxis.pageBuilder.agentic.resourceDiscovery.defaultRecommendedLabel': 'a primeira opção',
3103
3211
  'praxis.pageBuilder.agentic.resourceDiscovery.cardDescription': 'Fonte recomendada para transformar {label} em painel: ajuda a escolher gráficos, listas, filtros e formatos antes de materializar a tela.',
3104
- 'praxis.pageBuilder.agentic.resourceDiscovery.cardBestFor': 'Quando você quer entender se {label} responde ao objetivo de negócio antes de criar widgets.',
3212
+ 'praxis.pageBuilder.agentic.resourceDiscovery.cardBestFor': 'Quando você precisa decidir se {label} é a melhor fonte para a experiência que está criando.',
3105
3213
  'praxis.pageBuilder.agentic.resourceDiscovery.cardReturns': 'Sugere métricas, dimensões, filtros, formatos de valor, gráficos e listas de detalhe compatíveis com a fonte.',
3106
3214
  'praxis.pageBuilder.agentic.resourceDiscovery.cardNextStep': 'Selecione para eu propor uma pré-visualização governada com cards ricos, drill-down e formatos adequados por padrão.',
3107
3215
  'praxis.pageBuilder.agentic.diagnostics.title': 'Diagnóstico do LLM',
@@ -3110,6 +3218,7 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
3110
3218
  'praxis.pageBuilder.agentic.dragHandleAria': 'Mover assistente de IA',
3111
3219
  'praxis.pageBuilder.agentic.resizeHandleAria': 'Redimensionar assistente de IA',
3112
3220
  'praxis.pageBuilder.agentic.resizeHandleTooltip': 'Redimensionar',
3221
+ 'praxis.pageBuilder.agentic.submit': 'Enviar pedido',
3113
3222
  'praxis.pageBuilder.agentic.preview': 'Gerar prévia',
3114
3223
  'praxis.pageBuilder.agentic.persist': 'Salvar',
3115
3224
  'praxis.pageBuilder.pageLifecycle.restart': 'Recomeçar tela',
@@ -3136,8 +3245,39 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
3136
3245
  'praxis.pageBuilder.agentic.status.acceptedRelabelField': 'Rótulo do campo atualizado.',
3137
3246
  'praxis.pageBuilder.agentic.status.saving': 'Salvando página...',
3138
3247
  'praxis.pageBuilder.agentic.status.saved': 'Página salva.',
3139
- 'praxis.pageBuilder.agentic.status.sharedRuleTargetSelected': 'Alvo de regra compartilhada selecionado. Continue criando a definição governada.',
3140
- 'praxis.pageBuilder.agentic.sharedRuleCockpit.targetSelected': 'Alvo de regra compartilhada selecionado. O próximo passo seguro é criar a definição governada.',
3248
+ 'praxis.pageBuilder.agentic.status.sharedRuleTargetSelected': 'Continue este pedido na revisão da regra.',
3249
+ 'praxis.pageBuilder.agentic.governedRoute.streamUnavailable': 'Este pedido precisa continuar pela revisão governada da regra de negócio. Não vou criar uma prévia local enquanto essa revisão não estiver disponível.',
3250
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.title': 'Revisão governada da regra',
3251
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.description': 'Revise a regra de negócio antes de criar ou salvar alterações na tela.',
3252
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.expand': 'Expandir',
3253
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.collapse': 'Recolher',
3254
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.targetSelected': 'Regra identificada. O próximo passo seguro é revisar a regra antes de criar a tela.',
3255
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.running': 'Executando etapa de revisão',
3256
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.definitionId': 'Regra',
3257
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.simulation': 'Simulação',
3258
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.publication': 'Publicação',
3259
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.materializations': 'Telas criadas',
3260
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.timeline': 'Histórico',
3261
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.enforcementState': 'Validação',
3262
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.enforcementMatrix': 'Validação das alterações',
3263
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.enforcementMatrixDescription': 'Alterações que a plataforma poderá aplicar depois da publicação.',
3264
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.pending': 'pendente',
3265
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.applied': 'aplicadas',
3266
+ 'praxis.pageBuilder.agentic.sharedRuleCockpit.waiting': 'aguardando',
3267
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_definition.label': 'Revisar regra',
3268
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_definition.description': 'Abrir ou criar a revisão governada da regra.',
3269
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.simulate.label': 'Simular',
3270
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.simulate.description': 'Testar o resultado antes de publicar.',
3271
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.approve.label': 'Aprovar',
3272
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.approve.description': 'Aprovar a regra depois da revisão.',
3273
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.publish.label': 'Publicar alterações',
3274
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.publish.description': 'Publicar a regra e preparar as telas derivadas.',
3275
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.materialize.label': 'Ver telas criadas',
3276
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.materialize.description': 'Ver as telas geradas a partir da regra aprovada.',
3277
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.validate_enforcement.label': 'Validar aplicação',
3278
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.validate_enforcement.description': 'Verificar se as alterações publicadas já podem ser usadas.',
3279
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_timeline.label': 'Ver histórico',
3280
+ 'praxis.pageBuilder.agentic.governedContinuation.sharedRule.open_timeline.description': 'Abrir o histórico seguro desta decisão.',
3141
3281
  'praxis.pageBuilder.agentic.projectKnowledgeCockpit.timeline': 'Timeline segura',
3142
3282
  'praxis.pageBuilder.agentic.projectKnowledgeCockpit.timelineEmpty': 'Ainda não há eventos seguros de timeline publicados para este change-set.',
3143
3283
  'praxis.pageBuilder.agentic.projectKnowledgeCockpit.rejected': 'Change-set de Project Knowledge rejeitado. Nenhuma projeção de conhecimento governado foi aplicada.',
@@ -3148,7 +3288,6 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
3148
3288
  'praxis.pageBuilder.agentic.errors.streamTimeout': 'Ainda não consegui concluir este pedido. Tente novamente com um pedido mais específico ou revise o contexto ativo.',
3149
3289
  'praxis.pageBuilder.agentic.errors.streamProcessing': 'Não consegui concluir este pedido de autoria. Tente novamente ou peça ao suporte para revisar o diagnóstico.',
3150
3290
  'praxis.pageBuilder.agentic.errors.streamConnection': 'O stream do assistente foi interrompido antes de concluir o turno. Tente novamente ou acione o suporte para verificar a conexão do stream.',
3151
- 'praxis.pageBuilder.agentic.governedRoute.streamUnavailable': 'Este pedido deve continuar pelo fluxo governado de decisão semântica em /api/praxis/config/domain-rules. O stream do backend está indisponível, então pré-visualização/aplicação local fica bloqueada.',
3152
3291
  'praxis.pageBuilder.agentic.errors.duplicateField': 'Este campo já existe no formulário selecionado.',
3153
3292
  'praxis.pageBuilder.agentic.errors.nonLocalFieldRemoval': 'Somente campos locais criados pela IA podem ser removidos neste fluxo.',
3154
3293
  'praxis.pageBuilder.agentic.errors.invalidTableContract': 'Encontrei a fonte de dados, mas o plano gerado usou propriedades incompatíveis com o componente de tabela. Vou ajustar para usar apenas os campos suportados.',
@@ -12055,7 +12194,7 @@ const PAGE_BUILDER_COMPONENT_CONTEXT_PACK = {
12055
12194
  const DEFAULT_AGENTIC_AUTHORING_REQUEST_TIMEOUT_MS = 120000;
12056
12195
  const DEFAULT_TURN_STREAM_START_TIMEOUT_MS = 10000;
12057
12196
  const DEFAULT_TURN_STREAM_TIMEOUT_MS = 240000;
12058
- const DEFAULT_TURN_STREAM_RESULT_FALLBACK_MS = 90000;
12197
+ const DEFAULT_TURN_STREAM_RESULT_FALLBACK_MS = 210000;
12059
12198
  const DEFAULT_TURN_STREAM_SILENCE_STATUS_MS = 20000;
12060
12199
  const PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS = new InjectionToken('PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS');
12061
12200
  class PageBuilderAgenticAuthoringService {
@@ -13864,6 +14003,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
13864
14003
  service;
13865
14004
  context;
13866
14005
  mode = 'agentic-authoring';
14006
+ runtimeRelatedSurfaceDisambiguationContext = null;
13867
14007
  constructor(service, context) {
13868
14008
  this.service = service;
13869
14009
  this.context = context;
@@ -13919,6 +14059,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
13919
14059
  state: 'success',
13920
14060
  phase: 'summarize',
13921
14061
  assistantMessage: intentAssistantMessage,
14062
+ assistantContent: this.toJsonObject(intentResolution.assistantContent),
13922
14063
  quickReplies,
13923
14064
  canApply: false,
13924
14065
  statusText: '',
@@ -13933,6 +14074,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
13933
14074
  state: 'clarification',
13934
14075
  phase: 'clarify',
13935
14076
  assistantMessage: intentAssistantMessage,
14077
+ assistantContent: this.toJsonObject(intentResolution.assistantContent),
13936
14078
  quickReplies,
13937
14079
  canApply: false,
13938
14080
  statusText: '',
@@ -13947,6 +14089,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
13947
14089
  state: 'clarification',
13948
14090
  phase: 'clarify',
13949
14091
  assistantMessage: intentAssistantMessage,
14092
+ assistantContent: this.toJsonObject(intentResolution.assistantContent),
13950
14093
  quickReplies,
13951
14094
  canApply: false,
13952
14095
  statusText: '',
@@ -14071,7 +14214,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
14071
14214
  phase: 'contextualize',
14072
14215
  assistantMessage: undefined,
14073
14216
  canApply: false,
14074
- statusText: this.context.tx('agentic.status.preparingTurnStream', 'Preparing the AI authoring context...'),
14217
+ statusText: this.context.tx('agentic.status.preparingTurnStream', 'Organizando as informações do pedido...'),
14075
14218
  errorText: '',
14076
14219
  preview: null,
14077
14220
  };
@@ -14082,7 +14225,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
14082
14225
  phase: 'contextualize',
14083
14226
  assistantMessage: undefined,
14084
14227
  canApply: false,
14085
- statusText: this.context.tx('agentic.status.turnStreamContextReady', 'AI authoring context is ready. Starting backend stream...'),
14228
+ statusText: this.context.tx('agentic.status.turnStreamContextReady', 'Informações prontas. Preparando a resposta...'),
14086
14229
  errorText: '',
14087
14230
  preview: null,
14088
14231
  diagnostics: {
@@ -14096,7 +14239,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
14096
14239
  phase: 'contextualize',
14097
14240
  assistantMessage: undefined,
14098
14241
  canApply: false,
14099
- statusText: this.context.tx('agentic.status.preparingTurnStreamWaiting', 'Still preparing the AI authoring stream. Checking catalog, context, and backend availability...'),
14242
+ statusText: this.context.tx('agentic.status.preparingTurnStreamWaiting', 'Ainda conferindo domínio, tela atual e fontes disponíveis...'),
14100
14243
  errorText: '',
14101
14244
  preview: null,
14102
14245
  diagnostics: {
@@ -14112,7 +14255,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
14112
14255
  return {
14113
14256
  state: 'listening',
14114
14257
  phase: 'capture',
14115
- assistantMessage: this.context.tx('agentic.status.cancelled', 'Request cancelled.'),
14258
+ assistantMessage: this.context.tx('agentic.status.cancelled', 'Pedido cancelado.'),
14116
14259
  quickReplies: [],
14117
14260
  canApply: false,
14118
14261
  statusText: '',
@@ -15008,15 +15151,86 @@ class PageBuilderAgenticAuthoringTurnFlow {
15008
15151
  }
15009
15152
  return JSON.parse(JSON.stringify(value));
15010
15153
  }
15154
+ captureRuntimeRelatedSurfaceDisambiguationContext(payload, event) {
15155
+ const disambiguation = this.findRuntimeRelatedSurfaceDisambiguation(payload);
15156
+ const rawOptions = Array.isArray(disambiguation?.['options'])
15157
+ ? disambiguation['options']
15158
+ : [];
15159
+ const options = rawOptions
15160
+ .map((option) => this.toJsonObject(option))
15161
+ .filter((option) => !!option)
15162
+ .filter((option) => !!this.readString(option, 'surfaceRef')
15163
+ && this.readString(option, 'optionRef') === `runtime-surface-option:${this.readString(option, 'surfaceRef')}`
15164
+ && this.readString(option, 'candidateRef').startsWith('runtime-surface-candidate:'))
15165
+ .slice(0, 4)
15166
+ .map((option) => ({
15167
+ surfaceRef: this.readString(option, 'surfaceRef'),
15168
+ optionRef: this.readString(option, 'optionRef'),
15169
+ candidateRef: this.readString(option, 'candidateRef'),
15170
+ label: this.readString(option, 'label') || this.readString(option, 'surfaceRef'),
15171
+ semanticAliases: Array.isArray(option['semanticAliases'])
15172
+ ? option['semanticAliases']
15173
+ .filter((alias) => typeof alias === 'string' && !!alias.trim())
15174
+ .map((alias) => alias.trim())
15175
+ .slice(0, 12)
15176
+ : [],
15177
+ }));
15178
+ if (options.length < 2) {
15179
+ return;
15180
+ }
15181
+ const evidenceBundle = this.toJsonObject(payload['evidenceBundle']);
15182
+ const runtimeContext = this.toJsonObject(evidenceBundle?.['runtimeConsultableContext'])
15183
+ ?? this.toJsonObject(evidenceBundle?.['runtimeContext'])
15184
+ ?? null;
15185
+ this.runtimeRelatedSurfaceDisambiguationContext = {
15186
+ schemaVersion: 'praxis-runtime-related-surface-disambiguation-context.v1',
15187
+ source: 'runtimeRelatedSurfaceDisambiguation',
15188
+ authority: 'grounding_only',
15189
+ sessionId: event?.threadId ?? '',
15190
+ sourceTurnId: event?.turnId ?? '',
15191
+ pageId: this.readString(runtimeContext, 'pageId'),
15192
+ capturedAt: new Date().toISOString(),
15193
+ ttlMs: 300000,
15194
+ optionCount: options.length,
15195
+ options,
15196
+ rawRuntimeValuesCopied: false,
15197
+ };
15198
+ }
15199
+ findRuntimeRelatedSurfaceDisambiguation(value) {
15200
+ const root = this.toJsonObject(value);
15201
+ if (!root) {
15202
+ return null;
15203
+ }
15204
+ if (root['schemaVersion'] === 'praxis-runtime-related-surface-disambiguation.v1') {
15205
+ return root;
15206
+ }
15207
+ for (const child of Object.values(root)) {
15208
+ if (Array.isArray(child)) {
15209
+ for (const item of child) {
15210
+ const found = this.findRuntimeRelatedSurfaceDisambiguation(item);
15211
+ if (found) {
15212
+ return found;
15213
+ }
15214
+ }
15215
+ }
15216
+ else {
15217
+ const found = this.findRuntimeRelatedSurfaceDisambiguation(child);
15218
+ if (found) {
15219
+ return found;
15220
+ }
15221
+ }
15222
+ }
15223
+ return null;
15224
+ }
15011
15225
  async buildTurnStreamRequest(request, prompt) {
15012
15226
  const startedAt = Date.now();
15013
- const capabilitiesStartedAt = Date.now();
15014
- const componentCapabilities = await this.context.loadComponentCapabilities();
15015
- const capabilitiesElapsedMs = Math.max(0, Date.now() - capabilitiesStartedAt);
15016
15227
  const authoringContextStartedAt = Date.now();
15017
15228
  const selectedWidgetKey = this.context.selectedWidgetKey();
15018
15229
  const authoringContext = this.buildAuthoringContext(request);
15019
15230
  const authoringContextElapsedMs = Math.max(0, Date.now() - authoringContextStartedAt);
15231
+ const runtimeObservationsStartedAt = Date.now();
15232
+ const runtimeObservationResult = await this.collectRuntimeComponentObservations(request);
15233
+ const runtimeObservationsElapsedMs = Math.max(0, Date.now() - runtimeObservationsStartedAt);
15020
15234
  const streamRequest = {
15021
15235
  userPrompt: prompt,
15022
15236
  targetApp: this.context.targetApp,
@@ -15027,8 +15241,20 @@ class PageBuilderAgenticAuthoringTurnFlow {
15027
15241
  provider: this.context.provider(),
15028
15242
  model: this.context.model(),
15029
15243
  apiKey: this.context.apiKey(),
15030
- componentCapabilities,
15031
15244
  ...authoringContext,
15245
+ ...(this.runtimeRelatedSurfaceDisambiguationContext
15246
+ ? {
15247
+ diagnostics: {
15248
+ runtimeRelatedSurfaceDisambiguationContext: this.cloneJsonObject(this.runtimeRelatedSurfaceDisambiguationContext),
15249
+ },
15250
+ }
15251
+ : {}),
15252
+ ...(runtimeObservationResult.observations.length
15253
+ ? {
15254
+ runtimeComponentObservations: runtimeObservationResult.observations,
15255
+ runtimeComponentObservationTrustBoundary: 'untrusted_frontend_observation',
15256
+ }
15257
+ : {}),
15032
15258
  };
15033
15259
  return {
15034
15260
  streamRequest,
@@ -15036,21 +15262,48 @@ class PageBuilderAgenticAuthoringTurnFlow {
15036
15262
  schemaVersion: 'praxis-turn-stream-preparation-diagnostics.v1',
15037
15263
  source: 'page-builder-agentic-authoring-turn-flow',
15038
15264
  totalElapsedMs: Math.max(0, Date.now() - startedAt),
15039
- capabilitiesElapsedMs,
15265
+ componentCapabilitiesSource: 'server-resolved',
15040
15266
  authoringContextElapsedMs,
15041
- catalogCount: componentCapabilities.catalogs?.length ?? 0,
15042
- capabilityCount: componentCapabilities.catalogs
15043
- .reduce((count, catalog) => count + (catalog.capabilities?.length ?? 0), 0),
15267
+ runtimeObservationsElapsedMs,
15044
15268
  attachmentCount: authoringContext.attachmentSummaries?.length ?? 0,
15045
15269
  hasPendingClarification: !!authoringContext.pendingClarification,
15046
15270
  hasContextHints: !!authoringContext.contextHints,
15271
+ runtimeObservationCount: runtimeObservationResult.observations.length,
15272
+ runtimeObservationSource: runtimeObservationResult.source,
15273
+ runtimeObservationUnavailable: runtimeObservationResult.unavailable,
15047
15274
  },
15048
15275
  };
15049
15276
  }
15277
+ async collectRuntimeComponentObservations(request) {
15278
+ try {
15279
+ const collected = await this.context.collectRuntimeComponentObservations?.();
15280
+ if (collected?.length) {
15281
+ return {
15282
+ observations: collected,
15283
+ source: 'page-builder-explicit',
15284
+ unavailable: false,
15285
+ };
15286
+ }
15287
+ }
15288
+ catch {
15289
+ const fallback = request.runtimeComponentObservations || [];
15290
+ return {
15291
+ observations: fallback,
15292
+ source: fallback.length ? 'assistant-request' : 'none',
15293
+ unavailable: true,
15294
+ };
15295
+ }
15296
+ const fallback = request.runtimeComponentObservations || [];
15297
+ return {
15298
+ observations: fallback,
15299
+ source: fallback.length ? 'assistant-request' : 'none',
15300
+ unavailable: false,
15301
+ };
15302
+ }
15050
15303
  async toTurnResultFromStreamEvent(event, request, prompt) {
15051
15304
  const payload = this.toJsonObject(event.payload) ?? {};
15052
15305
  if (event.type === 'result') {
15053
- return this.toResultTurnFromStreamPayload(payload, request, prompt);
15306
+ return this.toResultTurnFromStreamPayload(payload, request, prompt, event);
15054
15307
  }
15055
15308
  if (event.type === 'error') {
15056
15309
  const message = this.describeStreamError(payload);
@@ -15069,7 +15322,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
15069
15322
  return {
15070
15323
  state: 'listening',
15071
15324
  phase: 'capture',
15072
- assistantMessage: this.context.tx('agentic.status.cancelled', 'Request cancelled.'),
15325
+ assistantMessage: this.context.tx('agentic.status.cancelled', 'Pedido cancelado.'),
15073
15326
  quickReplies: [],
15074
15327
  canApply: false,
15075
15328
  statusText: '',
@@ -15088,7 +15341,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
15088
15341
  preview: null,
15089
15342
  };
15090
15343
  }
15091
- async toResultTurnFromStreamPayload(payload, request, prompt) {
15344
+ async toResultTurnFromStreamPayload(payload, request, prompt, event) {
15092
15345
  const intentResolution = this.normalizeIntentResolutionResult(payload['intentResolution']);
15093
15346
  const preview = payload['preview'];
15094
15347
  if (!intentResolution) {
@@ -15110,7 +15363,11 @@ class PageBuilderAgenticAuthoringTurnFlow {
15110
15363
  ? payload['quickReplies']
15111
15364
  : intentResolution.quickReplies ?? [];
15112
15365
  const quickReplies = this.resolveShellQuickReplies(intentResolution, rawQuickReplies);
15366
+ this.captureRuntimeRelatedSurfaceDisambiguationContext(payload, event);
15113
15367
  const assistantMessage = this.normalizeAssistantMessageForQuickReplies(rawAssistantMessage, quickReplies);
15368
+ const assistantContent = this.toJsonObject(payload['assistantContent'])
15369
+ ?? this.toJsonObject(intentResolution.assistantContent)
15370
+ ?? null;
15114
15371
  const canApply = payload['canApply'] === true && !!preview?.valid;
15115
15372
  const contextualExecutableIntent = request
15116
15373
  ? this.toExecutableContextualComponentIntent(intentResolution, request)
@@ -15149,7 +15406,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
15149
15406
  state: 'review',
15150
15407
  phase: 'review',
15151
15408
  assistantMessage: status,
15152
- quickReplies: this.mergeDashboardQualityQuickReplies(quickReplies, intentResolution, preview),
15409
+ quickReplies: this.governedBlockedReviewQuickReplies(quickReplies, intentResolution, preview),
15153
15410
  canApply: false,
15154
15411
  statusText: this.reviewStatusText(status, false),
15155
15412
  errorText: '',
@@ -15176,6 +15433,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
15176
15433
  state: pendingClarification || requiresChoice ? 'clarification' : 'success',
15177
15434
  phase: pendingClarification || requiresChoice ? 'clarify' : 'summarize',
15178
15435
  assistantMessage,
15436
+ assistantContent,
15179
15437
  quickReplies,
15180
15438
  canApply: false,
15181
15439
  statusText: '',
@@ -15818,26 +16076,35 @@ class PageBuilderAgenticAuthoringTurnFlow {
15818
16076
  ? this.mergeDashboardQualityQuickReplies(quickReplies, intentResolution, preview)
15819
16077
  : [...quickReplies];
15820
16078
  }
16079
+ governedBlockedReviewQuickReplies(quickReplies, intentResolution, preview) {
16080
+ const replies = this.reviewQuickReplies(quickReplies, intentResolution, preview);
16081
+ if (intentResolution.artifactKind === 'dashboard'
16082
+ && !this.dashboardReviewCanApply(intentResolution, preview)
16083
+ && replies.length === 0) {
16084
+ return [this.dashboardQualityFallbackQuickReply(intentResolution, preview)];
16085
+ }
16086
+ return replies;
16087
+ }
15821
16088
  describeDashboardQualityWarning(code) {
15822
16089
  switch (code) {
15823
16090
  case 'dashboard-without-chart-widget':
15824
- return this.context.tx('agentic.dashboardQuality.warning.chart', 'chart widget missing');
16091
+ return this.context.tx('agentic.dashboardQuality.warning.chart', 'faltou um gráfico');
15825
16092
  case 'dashboard-without-kpi-widget':
15826
- return this.context.tx('agentic.dashboardQuality.warning.kpi', 'KPI block missing');
16093
+ return this.context.tx('agentic.dashboardQuality.warning.kpi', 'faltaram indicadores');
15827
16094
  case 'dashboard-kpi-placeholder-values':
15828
- return this.context.tx('agentic.dashboardQuality.warning.kpiValues', 'KPI values are placeholders');
16095
+ return this.context.tx('agentic.dashboardQuality.warning.kpiValues', 'indicadores ainda estão sem dados reais');
15829
16096
  case 'dashboard-without-filter-widget':
15830
- return this.context.tx('agentic.dashboardQuality.warning.filter', 'filter widget missing');
16097
+ return this.context.tx('agentic.dashboardQuality.warning.filter', 'faltaram filtros');
15831
16098
  case 'dashboard-without-record-detail-widget':
15832
- return this.context.tx('agentic.dashboardQuality.warning.details', 'record detail widget missing');
16099
+ return this.context.tx('agentic.dashboardQuality.warning.details', 'faltou uma área de detalhe');
15833
16100
  case 'dashboard-without-composition-links':
15834
- return this.context.tx('agentic.dashboardQuality.warning.links', 'widget interactions missing');
16101
+ return this.context.tx('agentic.dashboardQuality.warning.links', 'faltou conectar as partes do painel');
15835
16102
  case 'dashboard-filter-not-connected':
15836
- return this.context.tx('agentic.dashboardQuality.warning.filterConnection', 'filter is not connected');
16103
+ return this.context.tx('agentic.dashboardQuality.warning.filterConnection', 'o filtro ainda não controla o painel');
15837
16104
  case 'dashboard-chart-not-interactive':
15838
- return this.context.tx('agentic.dashboardQuality.warning.chartInteraction', 'chart interaction missing');
16105
+ return this.context.tx('agentic.dashboardQuality.warning.chartInteraction', 'o gráfico ainda não abre detalhes');
15839
16106
  case 'dashboard-without-surface-actions':
15840
- return this.context.tx('agentic.dashboardQuality.warning.surfaces', 'surface actions missing');
16107
+ return this.context.tx('agentic.dashboardQuality.warning.surfaces', 'faltaram ações para consultar detalhes');
15841
16108
  default:
15842
16109
  return code;
15843
16110
  }
@@ -15883,8 +16150,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
15883
16150
  if (warnings.includes('dashboard-without-kpi-widget')) {
15884
16151
  replies.push(this.dashboardQualityQuickReply({
15885
16152
  id: 'dashboard-quality-add-kpis',
15886
- label: this.context.tx('agentic.dashboardQuality.quickReply.addKpis', 'Add KPIs'),
15887
- prompt: this.context.tx('agentic.dashboardQuality.prompt.addKpis', 'Add a compact KPI block with the most useful metrics for this dashboard, preferably using praxis-rich-content statGroup or metric nodes.'),
16153
+ label: this.context.tx('agentic.dashboardQuality.quickReply.addKpis', 'Adicionar indicadores'),
16154
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.addKpis', 'Inclua um bloco compacto com os indicadores mais úteis para acompanhar esse painel.'),
15888
16155
  icon: 'monitoring',
15889
16156
  changeKind: 'add_dashboard_kpis',
15890
16157
  contextHints,
@@ -15893,8 +16160,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
15893
16160
  if (warnings.includes('dashboard-kpi-placeholder-values')) {
15894
16161
  replies.push(this.dashboardQualityQuickReply({
15895
16162
  id: 'dashboard-quality-bind-kpis',
15896
- label: this.context.tx('agentic.dashboardQuality.quickReply.bindKpis', 'Bind KPI values'),
15897
- prompt: this.context.tx('agentic.dashboardQuality.prompt.bindKpis', 'Replace placeholder KPI values with real metric bindings from the dashboard DTO/source, keeping labels and formatting human-readable.'),
16163
+ label: this.context.tx('agentic.dashboardQuality.quickReply.bindKpis', 'Usar dados reais nos indicadores'),
16164
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.bindKpis', 'Substitua valores de exemplo dos indicadores por dados reais da fonte escolhida, mantendo nomes e formatos fáceis de entender.'),
15898
16165
  icon: 'data_object',
15899
16166
  changeKind: 'bind_dashboard_kpis',
15900
16167
  contextHints,
@@ -15903,8 +16170,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
15903
16170
  if (warnings.includes('dashboard-without-filter-widget')) {
15904
16171
  replies.push(this.dashboardQualityQuickReply({
15905
16172
  id: 'dashboard-quality-add-filters',
15906
- label: this.context.tx('agentic.dashboardQuality.quickReply.addFilters', 'Add filters'),
15907
- prompt: this.context.tx('agentic.dashboardQuality.prompt.addFilters', 'Add canonical dashboard filters from the DTO fields and connect their requestSearch output to charts and detail widgets through queryContext.'),
16173
+ label: this.context.tx('agentic.dashboardQuality.quickReply.addFilters', 'Adicionar filtros'),
16174
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.addFilters', 'Adicione filtros úteis para o analista refinar os dados do painel.'),
15908
16175
  icon: 'filter_alt',
15909
16176
  changeKind: 'add_dashboard_filters',
15910
16177
  contextHints,
@@ -15913,8 +16180,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
15913
16180
  if (warnings.includes('dashboard-without-chart-widget')) {
15914
16181
  replies.push(this.dashboardQualityQuickReply({
15915
16182
  id: 'dashboard-quality-add-chart',
15916
- label: this.context.tx('agentic.dashboardQuality.quickReply.addChart', 'Add chart'),
15917
- prompt: this.context.tx('agentic.dashboardQuality.prompt.addChart', 'Add the most relevant analytical chart to this dashboard, using the same data source and connecting it to the detail widgets.'),
16183
+ label: this.context.tx('agentic.dashboardQuality.quickReply.addChart', 'Adicionar gráfico'),
16184
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.addChart', 'Adicione o gráfico mais útil para explicar os dados desse painel e conecte-o aos detalhes quando possível.'),
15918
16185
  icon: 'insert_chart',
15919
16186
  changeKind: 'add_dashboard_chart',
15920
16187
  contextHints,
@@ -15923,8 +16190,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
15923
16190
  if (warnings.includes('dashboard-without-record-detail-widget')) {
15924
16191
  replies.push(this.dashboardQualityQuickReply({
15925
16192
  id: 'dashboard-quality-add-details',
15926
- label: this.context.tx('agentic.dashboardQuality.quickReply.addDetails', 'Add details'),
15927
- prompt: this.context.tx('agentic.dashboardQuality.prompt.addDetails', 'Add a rich record detail widget, preferably a Praxis list or table, using the same dashboard data source.'),
16193
+ label: this.context.tx('agentic.dashboardQuality.quickReply.addDetails', 'Adicionar detalhes'),
16194
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.addDetails', 'Inclua uma área de detalhes para o analista consultar os registros por trás dos indicadores.'),
15928
16195
  icon: 'view_list',
15929
16196
  changeKind: 'add_dashboard_detail_widget',
15930
16197
  contextHints,
@@ -15935,8 +16202,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
15935
16202
  || warnings.includes('dashboard-chart-not-interactive')) {
15936
16203
  replies.push(this.dashboardQualityQuickReply({
15937
16204
  id: 'dashboard-quality-connect-widgets',
15938
- label: this.context.tx('agentic.dashboardQuality.quickReply.connectWidgets', 'Connect widgets'),
15939
- prompt: this.context.tx('agentic.dashboardQuality.prompt.connectWidgets', 'Connect the dashboard widgets so filter and chart selections update the detail widgets through queryContext.'),
16205
+ label: this.context.tx('agentic.dashboardQuality.quickReply.connectWidgets', 'Conectar painel e detalhes'),
16206
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.connectWidgets', 'Faça filtros e escolhas no gráfico atualizarem a área de detalhes do painel.'),
15940
16207
  icon: 'hub',
15941
16208
  changeKind: 'connect_dashboard_widgets',
15942
16209
  contextHints,
@@ -15945,8 +16212,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
15945
16212
  if (warnings.includes('dashboard-without-surface-actions')) {
15946
16213
  replies.push(this.dashboardQualityQuickReply({
15947
16214
  id: 'dashboard-quality-add-surfaces',
15948
- label: this.context.tx('agentic.dashboardQuality.quickReply.addSurfaces', 'Add surfaces'),
15949
- prompt: this.context.tx('agentic.dashboardQuality.prompt.addSurfaces', 'Add surface.open actions so dashboard selections can open richer drill-down details in a modal or drawer.'),
16215
+ label: this.context.tx('agentic.dashboardQuality.quickReply.addSurfaces', 'Abrir detalhes relacionados'),
16216
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.addSurfaces', 'Permita abrir detalhes relacionados a partir das seleções do painel, sem expor termos técnicos ao usuário.'),
15950
16217
  icon: 'open_in_new',
15951
16218
  changeKind: 'add_dashboard_surfaces',
15952
16219
  contextHints,
@@ -16049,6 +16316,34 @@ class PageBuilderAgenticAuthoringTurnFlow {
16049
16316
  },
16050
16317
  };
16051
16318
  }
16319
+ dashboardQualityFallbackQuickReply(intentResolution, preview) {
16320
+ const diagnostics = this.buildDashboardAuthoringDiagnostics(intentResolution, preview);
16321
+ const validation = this.toJsonObject(diagnostics?.['validation']);
16322
+ const warnings = this.arrayFromUnknown(validation?.['warnings']).map((warning) => `${warning}`);
16323
+ const selectedCandidate = this.toJsonObject(intentResolution.selectedCandidate);
16324
+ const target = this.toJsonObject(intentResolution.target);
16325
+ const resourcePath = this.readString(this.toJsonObject(diagnostics?.['dto']) ?? {}, 'resourcePath')
16326
+ || this.readString(selectedCandidate, 'resourcePath')
16327
+ || this.readString(target, 'resourcePath')
16328
+ || '';
16329
+ const dashboardQuality = this.toDashboardQualityRepairContext(diagnostics);
16330
+ return this.dashboardQualityQuickReply({
16331
+ id: 'dashboard-quality-refine',
16332
+ label: this.context.tx('agentic.dashboardQuality.quickReply.refine', 'Refinar painel'),
16333
+ prompt: this.context.tx('agentic.dashboardQuality.prompt.refine', 'Ajuste o painel para resolver os pontos pendentes e manter apenas decisões compatíveis com os dados confirmados.'),
16334
+ icon: 'auto_fix_high',
16335
+ changeKind: 'refine_dashboard_quality',
16336
+ contextHints: {
16337
+ source: 'dashboard-quality-gate',
16338
+ kind: 'dashboard-repair-action',
16339
+ artifactKind: 'dashboard',
16340
+ resourcePath,
16341
+ warnings,
16342
+ ...(dashboardQuality ? { dashboardQuality } : {}),
16343
+ ...this.dashboardRepairSnapshot(preview),
16344
+ },
16345
+ });
16346
+ }
16052
16347
  phaseForStreamPayload(payload) {
16053
16348
  const phase = this.readString(payload, 'phase');
16054
16349
  if (phase === 'intent.resolve')
@@ -16068,45 +16363,45 @@ class PageBuilderAgenticAuthoringTurnFlow {
16068
16363
  let status = null;
16069
16364
  switch (phase) {
16070
16365
  case 'context.bundle':
16071
- status = this.context.tx('agentic.status.contextBundle', 'Preparing context...');
16366
+ status = this.context.tx('agentic.status.contextBundle', 'Organizando informações...');
16072
16367
  break;
16073
16368
  case 'intent.resolve':
16074
16369
  if (this.isSecondPassStreamPayload(payload)) {
16075
- status = this.context.tx('agentic.status.refinedCandidates', 'Reviewing the retrieved resources with the AI...');
16370
+ status = this.context.tx('agentic.status.refinedCandidates', 'Conferindo as fontes encontradas...');
16076
16371
  break;
16077
16372
  }
16078
- status = this.context.tx('agentic.status.resolvingIntent', 'Resolving intent...');
16373
+ status = this.context.tx('agentic.status.resolvingIntent', 'Entendendo o pedido...');
16079
16374
  break;
16080
16375
  case 'resource.discovery':
16081
16376
  if (this.isBackendResourceDiscoveryPayload(payload)) {
16082
- status = this.context.tx('agentic.status.resourceDiscoveryBackend', 'Found API resources in the backend catalog.');
16377
+ status = this.context.tx('agentic.status.resourceDiscoveryBackend', 'Encontrei fontes de dados no catálogo do domínio.');
16083
16378
  break;
16084
16379
  }
16085
- status = this.context.tx('agentic.status.resourceDiscovery', 'Finding API resources...');
16380
+ status = this.context.tx('agentic.status.resourceDiscovery', 'Buscando fontes de dados...');
16086
16381
  break;
16087
16382
  case 'projectKnowledge.retrieve':
16088
16383
  status = this.projectKnowledgeStatusForStreamPayload(payload);
16089
16384
  break;
16090
16385
  case 'preview.plan':
16091
- status = this.context.tx('agentic.status.previewing', 'Generating preview...');
16386
+ status = this.context.tx('agentic.status.previewing', 'Criando prévia...');
16092
16387
  break;
16093
16388
  case 'preview.compile':
16094
- status = this.context.tx('agentic.status.previewCompile', 'Compiling preview...');
16389
+ status = this.context.tx('agentic.status.previewCompile', 'Montando a tela...');
16095
16390
  break;
16096
16391
  case 'stream.waiting':
16097
- status = this.context.tx('agentic.status.streamWaiting', 'The backend is still working on this dashboard. Keeping the request alive...');
16392
+ status = this.context.tx('agentic.status.streamWaiting', 'Ainda estou montando este painel. Mantendo o pedido em andamento...');
16098
16393
  break;
16099
16394
  case 'stream.start.accepted':
16100
- status = this.context.tx('agentic.status.streamStartAccepted', 'Backend accepted the authoring stream. Opening live progress...');
16395
+ status = this.context.tx('agentic.status.streamStartAccepted', 'Pedido recebido. Abrindo o acompanhamento da criação...');
16101
16396
  break;
16102
16397
  case 'stream.probe.ready':
16103
- status = this.context.tx('agentic.status.streamProbeReady', 'Authoring stream endpoint is reachable.');
16398
+ status = this.context.tx('agentic.status.streamProbeReady', 'Acompanhamento da criação disponível.');
16104
16399
  break;
16105
16400
  case 'stream.transport.opening':
16106
- status = this.context.tx('agentic.status.streamTransportOpening', 'Opening the live authoring stream...');
16401
+ status = this.context.tx('agentic.status.streamTransportOpening', 'Abrindo acompanhamento em tempo real...');
16107
16402
  break;
16108
16403
  case 'stream.first-event.received':
16109
- status = this.context.tx('agentic.status.streamFirstEventReceived', 'Live authoring progress started.');
16404
+ status = this.context.tx('agentic.status.streamFirstEventReceived', 'Criação iniciada.');
16110
16405
  break;
16111
16406
  default:
16112
16407
  status = this.readString(payload, 'summary') || this.readString(payload, 'message');
@@ -16123,17 +16418,17 @@ class PageBuilderAgenticAuthoringTurnFlow {
16123
16418
  return status;
16124
16419
  }
16125
16420
  return this.context
16126
- .tx('agentic.status.backendProgressElapsed', '{status} Backend still working for {seconds}s.')
16421
+ .tx('agentic.status.backendProgressElapsed', '{status} Ainda trabalhando nisso {seconds}s.')
16127
16422
  .replace('{status}', status)
16128
16423
  .replace('{seconds}', `${Math.round(elapsedSeconds)}`);
16129
16424
  }
16130
16425
  projectKnowledgeStatusForStreamPayload(payload) {
16131
16426
  const diagnostics = this.toJsonObject(payload['diagnostics']);
16132
16427
  const influenceCount = this.readNumber(diagnostics ?? {}, 'influenceCount');
16133
- const base = this.context.tx('agentic.status.projectKnowledgeRetrieved', 'Retrieved governed project knowledge for this authoring turn.');
16428
+ const base = this.context.tx('agentic.status.projectKnowledgeRetrieved', 'Encontrei conhecimento governado do projeto para orientar este pedido.');
16134
16429
  if (influenceCount && influenceCount > 0) {
16135
16430
  return this.context
16136
- .tx('agentic.status.projectKnowledgeRetrievedCount', 'Retrieved {count} governed project knowledge signals for this authoring turn.')
16431
+ .tx('agentic.status.projectKnowledgeRetrievedCount', 'Encontrei {count} sinais governados do projeto para orientar este pedido.')
16137
16432
  .replace('{count}', String(influenceCount));
16138
16433
  }
16139
16434
  return base;
@@ -16144,8 +16439,8 @@ class PageBuilderAgenticAuthoringTurnFlow {
16144
16439
  return normalized;
16145
16440
  }
16146
16441
  return canApply
16147
- ? this.context.tx('agentic.status.reviewReady', 'Ready for review.')
16148
- : this.context.tx('agentic.status.reviewNeedsAttention', 'Review the pending points before saving.');
16442
+ ? this.context.tx('agentic.status.reviewReady', 'Pronto para revisão.')
16443
+ : this.context.tx('agentic.status.reviewNeedsAttention', 'Revise os pontos pendentes antes de salvar.');
16149
16444
  }
16150
16445
  shouldReplaceReviewStatus(status) {
16151
16446
  const normalized = status.toLocaleLowerCase();
@@ -16166,13 +16461,13 @@ class PageBuilderAgenticAuthoringTurnFlow {
16166
16461
  describeStreamError(payload) {
16167
16462
  const code = this.readString(payload, 'code');
16168
16463
  if (code === 'agentic-authoring-timeout') {
16169
- return this.context.tx('agentic.errors.streamTimeout', 'The assistant took too long to finish this request. Try again with a narrower request or review the active context.');
16464
+ return this.context.tx('agentic.errors.streamTimeout', 'O assistente demorou para concluir este pedido. Tente de novo com um recorte menor ou revise o contexto ativo.');
16170
16465
  }
16171
16466
  if (code === 'agentic-authoring-processing-failed') {
16172
- return this.context.tx('agentic.errors.streamProcessing', 'The assistant could not finish this authoring request. Try again or ask support to review the diagnostics.');
16467
+ return this.context.tx('agentic.errors.streamProcessing', 'Não consegui concluir este pedido. Tente novamente ou peça uma revisão dos detalhes.');
16173
16468
  }
16174
16469
  return this.readString(payload, 'assistantMessage')
16175
- || this.context.tx('agentic.errors.generic', 'AI authoring failed.');
16470
+ || this.context.tx('agentic.errors.generic', 'Não consegui concluir este pedido.');
16176
16471
  }
16177
16472
  toTurnStreamTransportErrorResult(error) {
16178
16473
  const message = this.isTurnStreamConnectionError(error)
@@ -16249,7 +16544,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
16249
16544
  toGovernedRouteFailClosedResult(request, prompt, error) {
16250
16545
  const contextHints = this.buildContextHints(request);
16251
16546
  const domainCatalog = this.toJsonObject(contextHints?.['domainCatalog']);
16252
- const assistantMessage = this.context.tx('agentic.governedRoute.streamUnavailable', 'This request must continue through the governed semantic-decision flow in /api/praxis/config/domain-rules. The backend stream is unavailable, so local preview/apply is blocked.');
16547
+ const assistantMessage = this.context.tx('agentic.governedRoute.streamUnavailable', 'Este pedido precisa continuar pela revisão governada da regra de negócio. Não vou criar uma prévia local enquanto essa revisão não estiver disponível.');
16253
16548
  const intentResolution = {
16254
16549
  valid: false,
16255
16550
  operationKind: 'route',
@@ -16463,9 +16758,9 @@ class PageBuilderAgenticAuthoringTurnFlow {
16463
16758
  return backendText;
16464
16759
  }
16465
16760
  const firstLabel = quickReplies[0]?.label?.trim()
16466
- || this.context.tx('agentic.resourceDiscovery.defaultRecommendedLabel', 'the first option');
16761
+ || this.context.tx('agentic.resourceDiscovery.defaultRecommendedLabel', 'a primeira opção');
16467
16762
  const sourceCount = this.resourceDiscoverySourceCountLabel(quickReplies.length);
16468
- return this.context.tx('agentic.resourceDiscovery.found', 'I found {sourceCount} for this screen. I recommend starting with {first} because it is the best fit for charts, KPIs, and drill-down. Review the cards below to see what each source is good for, what it returns, and what I will create after you select it.')
16763
+ return this.context.tx('agentic.resourceDiscovery.found', 'Encontrei {sourceCount} para esta tela. Recomendo começar por {first}, porque parece a melhor opção para indicadores, gráficos e detalhes. Revise as opções abaixo e escolha a fonte que melhor combina com o que você quer criar.')
16469
16764
  .replace('{sourceCount}', sourceCount)
16470
16765
  .replace('{first}', firstLabel);
16471
16766
  }
@@ -17305,30 +17600,37 @@ class PageBuilderAgenticAuthoringTurnFlow {
17305
17600
  && !!String(presentation[key]).trim());
17306
17601
  }
17307
17602
  resourceQuickReplyDescription(reply) {
17603
+ const label = this.resourceQuickReplySubjectLabel(reply.label);
17308
17604
  const description = reply.description?.trim() ?? '';
17309
17605
  if (description
17310
17606
  && !this.isTechnicalResourceDescription(description)
17311
17607
  && !this.isGenericResourceDescription(description)) {
17312
17608
  return description;
17313
17609
  }
17314
- return this.context.tx('agentic.resourceDiscovery.cardDescription', 'Fonte recomendada para transformar {label} em painel: ajuda a escolher graficos, listas, filtros e formatos antes de materializar a tela.').replace('{label}', reply.label);
17610
+ return this.context.tx('agentic.resourceDiscovery.cardDescription', 'Fonte recomendada para transformar {label} em painel: ajuda a escolher graficos, listas, filtros e formatos antes de materializar a tela.').replace('{label}', label);
17315
17611
  }
17316
17612
  resourceQuickReplyPresentation(reply) {
17317
17613
  const contextHints = this.toJsonObject(reply.contextHints);
17318
17614
  const artifactKind = this.readString(contextHints, 'artifactKind');
17615
+ const label = this.resourceQuickReplySubjectLabel(reply.label);
17319
17616
  if (artifactKind === 'table') {
17320
17617
  return {
17321
- bestFor: `Boa quando voce quer transformar ${reply.label} em uma tabela navegavel.`,
17322
- returns: 'Retorna uma pre-visualizacao com colunas, filtros e fonte semantica preservada.',
17618
+ bestFor: `Boa quando você quer navegar, filtrar e comparar registros de ${label}.`,
17619
+ returns: 'Retorna uma pré-visualização com colunas, filtros e fonte semântica preservada.',
17323
17620
  nextStep: 'Clique para criar a tabela e revisar antes de salvar.',
17324
17621
  };
17325
17622
  }
17326
17623
  return {
17327
- bestFor: this.context.tx('agentic.resourceDiscovery.cardBestFor', 'Quando voce quer entender se {label} responde ao objetivo de negocio antes de criar widgets.').replace('{label}', reply.label),
17328
- returns: this.context.tx('agentic.resourceDiscovery.cardReturns', 'Sugere metricas, dimensoes, filtros, formatos de valor, graficos e listas de detalhe compativeis com a fonte.'),
17329
- nextStep: this.context.tx('agentic.resourceDiscovery.cardNextStep', 'Selecione para eu propor uma pre-visualizacao governada com cards ricos, drill-down e formatos adequados por padrao.'),
17624
+ bestFor: this.context.tx('agentic.resourceDiscovery.cardBestFor', 'Quando você precisa decidir se {label} é a melhor fonte para a experiência que está criando.').replace('{label}', label),
17625
+ returns: this.context.tx('agentic.resourceDiscovery.cardReturns', 'Sugere métricas, dimensões, filtros, formatos de valor, gráficos e listas de detalhe compatíveis com a fonte.'),
17626
+ nextStep: this.context.tx('agentic.resourceDiscovery.cardNextStep', 'Selecione para eu propor uma pré-visualização governada com cards ricos, drill-down e formatos adequados por padrão.'),
17330
17627
  };
17331
17628
  }
17629
+ resourceQuickReplySubjectLabel(label) {
17630
+ const normalized = (label || '').trim();
17631
+ return normalized.replace(/^(?:Criar\s+)?(?:tabela|gr[aá]fico|formul[aá]rio|dashboard|p[aá]gina)\s*:\s*/iu, '').trim()
17632
+ || normalized;
17633
+ }
17332
17634
  isTechnicalResourceDescription(description) {
17333
17635
  return /(?:^|\s)(?:GET|POST|PUT|PATCH|DELETE)\s+\//iu.test(description)
17334
17636
  || /\/api\//iu.test(description)
@@ -17445,15 +17747,53 @@ class PageBuilderAgenticAuthoringTurnFlow {
17445
17747
  buildContextHints(request) {
17446
17748
  const base = this.toJsonObject(request.action?.contextHints)
17447
17749
  ?? this.toJsonObject(request.contextHints);
17750
+ const normalizedBase = this.normalizeAmbientDomainCatalogContextHints(base);
17448
17751
  const includeLlmDiagnostics = this.context.includeLlmDiagnostics?.() === true;
17449
17752
  if (!includeLlmDiagnostics) {
17450
- return base ?? undefined;
17753
+ return normalizedBase ?? undefined;
17451
17754
  }
17452
17755
  return {
17453
- ...(base ?? {}),
17756
+ ...(normalizedBase ?? {}),
17454
17757
  includeLlmDiagnostics: true,
17455
17758
  };
17456
17759
  }
17760
+ normalizeAmbientDomainCatalogContextHints(contextHints) {
17761
+ if (!contextHints) {
17762
+ return null;
17763
+ }
17764
+ const domainCatalog = this.toJsonObject(contextHints['domainCatalog']);
17765
+ if (!domainCatalog || !this.isAmbientUiCompositionDomainCatalog(domainCatalog, contextHints)) {
17766
+ return contextHints;
17767
+ }
17768
+ const normalizedDomainCatalog = { ...domainCatalog };
17769
+ delete normalizedDomainCatalog['resourceKey'];
17770
+ delete normalizedDomainCatalog['query'];
17771
+ return {
17772
+ ...contextHints,
17773
+ domainCatalog: normalizedDomainCatalog,
17774
+ };
17775
+ }
17776
+ isAmbientUiCompositionDomainCatalog(domainCatalog, contextHints) {
17777
+ const recommendedFlow = this.readString(domainCatalog, 'recommendedAuthoringFlow');
17778
+ if (recommendedFlow !== 'ui_composition_authoring') {
17779
+ return false;
17780
+ }
17781
+ if (this.readString(domainCatalog, 'type') === 'governance'
17782
+ || this.readString(domainCatalog, 'recommendedRuleType')
17783
+ || this.readString(domainCatalog, 'ruleType')
17784
+ || this.readString(domainCatalog, 'domainRuleType')
17785
+ || this.readString(domainCatalog, 'targetLayer')) {
17786
+ return false;
17787
+ }
17788
+ return !this.hasExplicitResourceTarget(contextHints);
17789
+ }
17790
+ hasExplicitResourceTarget(contextHints) {
17791
+ return !!(this.readString(contextHints, 'resourcePath')
17792
+ || this.readString(contextHints, 'submitUrl')
17793
+ || this.readString(contextHints, 'schemaUrl')
17794
+ || this.readString(contextHints, 'selectedResourcePath')
17795
+ || this.readString(contextHints, 'targetResourcePath'));
17796
+ }
17457
17797
  toAttachmentSummaries(attachments) {
17458
17798
  return attachments.map((attachment) => ({
17459
17799
  id: attachment.id,
@@ -17554,13 +17894,13 @@ function deriveSharedRuleContinuationActions(input) {
17554
17894
  return status === 'applied' || status === 'active';
17555
17895
  });
17556
17896
  return [
17557
- sharedRuleAction('open_definition', 'Create definition', 'Create or open the governed definition.', target, enabledWhen(!busy && hasAuthoringTarget && !definitionId, busy ? 'busy' : definitionId ? 'definition_already_available' : !handoff ? 'missing_handoff' : 'missing_authoring_target')),
17558
- sharedRuleAction('simulate', 'Simulate', 'Run canonical backend simulation before publication.', target, enabledWhen(!busy && !!definitionId, busy ? 'busy' : 'missing_definition')),
17559
- sharedRuleAction('approve', 'Approve', 'Approve the governed definition after review.', target, enabledWhen(!busy && !!definitionId && definitionStatus !== 'approved' && definitionStatus !== 'active', busy ? 'busy' : !definitionId ? 'missing_definition' : 'definition_already_available')),
17560
- sharedRuleAction('publish', 'Publish/materialize', 'Publish the decision and derive eligible runtime materializations.', target, enabledWhen(!busy && !!definitionId, busy ? 'busy' : 'missing_definition')),
17561
- sharedRuleAction('materialize', 'Inspect materializations', 'Inspect derived materializations without making the UI the source of truth.', target, enabledWhen(!busy && !!definitionId, busy ? 'busy' : 'missing_definition')),
17562
- sharedRuleAction('validate_enforcement', 'Validate enforcement', 'Check whether applied materializations are ready for runtime validation.', target, enabledWhen(!busy && !!definitionId && hasAppliedMaterialization, busy ? 'busy' : !definitionId ? 'missing_definition' : 'missing_materialization')),
17563
- sharedRuleAction('open_timeline', 'Open timeline', 'Open safe timeline observability for this governed decision.', target, enabledWhen(!busy && !!definitionId && hasTimelineEvents, busy ? 'busy' : !definitionId ? 'missing_definition' : 'timeline_unavailable')),
17897
+ sharedRuleAction('open_definition', 'Preparar regra', 'Preparar ou abrir a regra governada para revisão.', target, enabledWhen(!busy && hasAuthoringTarget && !definitionId, busy ? 'busy' : definitionId ? 'definition_already_available' : !handoff ? 'missing_handoff' : 'missing_authoring_target')),
17898
+ sharedRuleAction('simulate', 'Simular impacto', 'Verificar o efeito da regra antes de publicar.', target, enabledWhen(!busy && !!definitionId, busy ? 'busy' : 'missing_definition')),
17899
+ sharedRuleAction('approve', 'Aprovar revisão', 'Aprovar a regra governada depois da conferência.', target, enabledWhen(!busy && !!definitionId && definitionStatus !== 'approved' && definitionStatus !== 'active', busy ? 'busy' : !definitionId ? 'missing_definition' : 'definition_already_available')),
17900
+ sharedRuleAction('publish', 'Publicar alteração', 'Publicar a decisão aprovada e atualizar as telas que dependem dela.', target, enabledWhen(!busy && !!definitionId, busy ? 'busy' : 'missing_definition')),
17901
+ sharedRuleAction('materialize', 'Ver telas afetadas', 'Ver quais telas serão atualizadas por essa decisão governada.', target, enabledWhen(!busy && !!definitionId, busy ? 'busy' : 'missing_definition')),
17902
+ sharedRuleAction('validate_enforcement', 'Validar aplicação', 'Conferir se a alteração publicada está pronta para uso.', target, enabledWhen(!busy && !!definitionId && hasAppliedMaterialization, busy ? 'busy' : !definitionId ? 'missing_definition' : 'missing_materialization')),
17903
+ sharedRuleAction('open_timeline', 'Ver histórico', 'Abrir o histórico seguro dessa decisão governada.', target, enabledWhen(!busy && !!definitionId && hasTimelineEvents, busy ? 'busy' : !definitionId ? 'missing_definition' : 'timeline_unavailable')),
17564
17904
  ];
17565
17905
  }
17566
17906
  function deriveProjectKnowledgeContinuationActions(input) {
@@ -17575,12 +17915,12 @@ function deriveProjectKnowledgeContinuationActions(input) {
17575
17915
  const hasTimelineEvents = (input.timeline?.events?.length ?? 0) > 0;
17576
17916
  const target = projectKnowledgeTarget(changeSet, candidate?.conceptKey ?? null);
17577
17917
  return [
17578
- projectKnowledgeAction('create_knowledge_change_set', 'Create change-set', 'Create a governed proposal from cited Project Knowledge.', target, enabledWhen(!busy && !!audit && !!candidate && !changeSet, busy ? 'busy' : !audit ? 'missing_project_knowledge_audit' : !candidate ? 'missing_project_knowledge_candidate' : 'change_set_already_available')),
17579
- projectKnowledgeAction('validate_knowledge_change_set', 'Validate change-set', 'Run deterministic validation before review.', target, enabledWhen(!busy && !!changeSet && validationStatus !== 'valid', busy ? 'busy' : !changeSet ? 'missing_change_set' : 'validation_already_valid')),
17580
- projectKnowledgeAction('approve', 'Approve', 'Approve the valid change-set explicitly.', target, enabledWhen(!busy && !!changeSet && validationValid && status !== 'approved' && status !== 'applied', busy ? 'busy' : !changeSet ? 'missing_change_set' : 'validation_required')),
17581
- projectKnowledgeAction('reject', 'Reject', 'Reject the proposed change-set without applying knowledge.', target, enabledWhen(!busy && !!changeSet && status !== 'applied', busy ? 'busy' : !changeSet ? 'missing_change_set' : 'already_applied')),
17582
- projectKnowledgeAction('apply_knowledge_change_set', 'Apply change-set', 'Apply only after approval and valid persisted validation.', target, enabledWhen(!busy && !!changeSet && validationValid && status === 'approved', busy ? 'busy' : !changeSet ? 'missing_change_set' : !validationValid ? 'validation_required' : status === 'applied' ? 'already_applied' : 'approval_required')),
17583
- projectKnowledgeAction('open_timeline', 'Open timeline', 'Open safe Domain Knowledge timeline observability.', target, enabledWhen(!busy && !!changeSet && hasTimelineEvents, busy ? 'busy' : !changeSet ? 'missing_change_set' : 'timeline_unavailable')),
17918
+ projectKnowledgeAction('create_knowledge_change_set', 'Preparar revisão', 'Preparar uma proposta governada a partir do conhecimento citado.', target, enabledWhen(!busy && !!audit && !!candidate && !changeSet, busy ? 'busy' : !audit ? 'missing_project_knowledge_audit' : !candidate ? 'missing_project_knowledge_candidate' : 'change_set_already_available')),
17919
+ projectKnowledgeAction('validate_knowledge_change_set', 'Validar proposta', 'Conferir a proposta antes da revisão.', target, enabledWhen(!busy && !!changeSet && validationStatus !== 'valid', busy ? 'busy' : !changeSet ? 'missing_change_set' : 'validation_already_valid')),
17920
+ projectKnowledgeAction('approve', 'Aprovar revisão', 'Aprovar explicitamente a proposta validada.', target, enabledWhen(!busy && !!changeSet && validationValid && status !== 'approved' && status !== 'applied', busy ? 'busy' : !changeSet ? 'missing_change_set' : 'validation_required')),
17921
+ projectKnowledgeAction('reject', 'Rejeitar proposta', 'Rejeitar a proposta sem aplicar mudanças no conhecimento.', target, enabledWhen(!busy && !!changeSet && status !== 'applied', busy ? 'busy' : !changeSet ? 'missing_change_set' : 'already_applied')),
17922
+ projectKnowledgeAction('apply_knowledge_change_set', 'Aplicar conhecimento', 'Aplicar somente depois da aprovação e da validação.', target, enabledWhen(!busy && !!changeSet && validationValid && status === 'approved', busy ? 'busy' : !changeSet ? 'missing_change_set' : !validationValid ? 'validation_required' : status === 'applied' ? 'already_applied' : 'approval_required')),
17923
+ projectKnowledgeAction('open_timeline', 'Ver histórico', 'Abrir o histórico seguro dessa revisão de conhecimento.', target, enabledWhen(!busy && !!changeSet && hasTimelineEvents, busy ? 'busy' : !changeSet ? 'missing_change_set' : 'timeline_unavailable')),
17584
17924
  ];
17585
17925
  }
17586
17926
  function selectProjectKnowledgeContinuationCandidate(audit) {
@@ -17634,16 +17974,19 @@ function projectKnowledgeTarget(changeSet, conceptKey) {
17634
17974
  };
17635
17975
  }
17636
17976
 
17977
+ const AGENTIC_AUTHORING_TURN_TERMINAL_TIMEOUT_MS = 270_000;
17637
17978
  const AGENTIC_PAGE_COMPOSITION_REQUEST_OUTPUT = 'agenticPageCompositionRequested';
17638
17979
  class DynamicPageBuilderComponent {
17639
17980
  dialog;
17640
17981
  settingsPanel;
17641
17982
  i18n = inject(PraxisI18nService);
17642
17983
  injector = inject(Injector);
17984
+ hostElement = inject((ElementRef));
17643
17985
  componentMetadata = inject(ComponentMetadataRegistry);
17644
17986
  agenticAuthoring = inject(PageBuilderAgenticAuthoringService);
17645
17987
  agenticTurnOrchestrator = inject(PraxisAssistantTurnOrchestratorService);
17646
17988
  assistantSessions = inject(PraxisAssistantSessionRegistryService);
17989
+ runtimeObservationRegistry = inject(PraxisRuntimeComponentObservationRegistryService, { optional: true });
17647
17990
  agenticAuthoringOptions = inject(PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS, { optional: true });
17648
17991
  runtime;
17649
17992
  page;
@@ -17655,6 +17998,9 @@ class DynamicPageBuilderComponent {
17655
17998
  pageIdentity;
17656
17999
  componentInstanceId;
17657
18000
  pageEditorComponent = DynamicPageConfigEditorComponent;
18001
+ componentPaletteAllowedWidgetIds = null;
18002
+ componentPaletteAllowedWidgetTags = null;
18003
+ componentPaletteAllowedPresetIds = null;
17658
18004
  enableAgenticAuthoring = false;
17659
18005
  agenticAuthoringProvider;
17660
18006
  agenticAuthoringModel;
@@ -17678,6 +18024,7 @@ class DynamicPageBuilderComponent {
17678
18024
  savedPageDeleteRequested = new EventEmitter();
17679
18025
  currentPage = signal({ widgets: [] }, ...(ngDevMode ? [{ debugName: "currentPage" }] : /* istanbul ignore next */ []));
17680
18026
  hasPageWidgets = computed(() => (this.currentPage().widgets || []).length > 0, ...(ngDevMode ? [{ debugName: "hasPageWidgets" }] : /* istanbul ignore next */ []));
18027
+ premiumReadinessIssues = computed(() => this.evaluatePremiumReadiness(this.currentPage()).slice(0, 3), ...(ngDevMode ? [{ debugName: "premiumReadinessIssues" }] : /* istanbul ignore next */ []));
17681
18028
  connectionsViewerOpen = signal(false, ...(ngDevMode ? [{ debugName: "connectionsViewerOpen" }] : /* istanbul ignore next */ []));
17682
18029
  agenticAuthoringOpen = signal(false, ...(ngDevMode ? [{ debugName: "agenticAuthoringOpen" }] : /* istanbul ignore next */ []));
17683
18030
  agenticAuthoringPrompt = signal('', ...(ngDevMode ? [{ debugName: "agenticAuthoringPrompt" }] : /* istanbul ignore next */ []));
@@ -17722,6 +18069,9 @@ class DynamicPageBuilderComponent {
17722
18069
  agenticComponentCapabilities;
17723
18070
  agenticComponentCapabilitiesPromise;
17724
18071
  agenticTurnController;
18072
+ agenticTurnCancel$ = new Subject();
18073
+ agenticTurnRunId = 0;
18074
+ agenticAuthoringTurnTerminalTimeoutMs = AGENTIC_AUTHORING_TURN_TERMINAL_TIMEOUT_MS;
17725
18075
  sharedRuleHandoffRevision = 0;
17726
18076
  agenticAuthoringPanelLayoutTouched = false;
17727
18077
  constructor(dialog, settingsPanel) {
@@ -17743,9 +18093,31 @@ class DynamicPageBuilderComponent {
17743
18093
  this.resetAgenticAuthoringSessionState();
17744
18094
  }
17745
18095
  }
18096
+ ngOnDestroy() {
18097
+ this.cancelActiveAgenticTurn();
18098
+ this.agenticTurnCancel$.complete();
18099
+ }
17746
18100
  showSettings() {
17747
18101
  return !!this.enableCustomization && !this.previewMode;
17748
18102
  }
18103
+ isPreviewMode() {
18104
+ return this.previewMode;
18105
+ }
18106
+ builderModeLabel() {
18107
+ if (this.previewMode) {
18108
+ return this.tx('builderMode.preview', 'Prévia');
18109
+ }
18110
+ if (this.showSettings() && this.connectionsViewerOpen()) {
18111
+ return this.tx('builderMode.connections', 'Conexões');
18112
+ }
18113
+ if (this.showSettings() && this.enableAgenticAuthoring && this.agenticAuthoringOpen()) {
18114
+ return this.tx('builderMode.ai', 'AI');
18115
+ }
18116
+ if (this.showSettings()) {
18117
+ return this.tx('builderMode.editing', 'Editing');
18118
+ }
18119
+ return this.tx('builderMode.presentation', 'Presentation');
18120
+ }
17749
18121
  onRuntimePageChange(next) {
17750
18122
  const cloned = this.clonePage(next);
17751
18123
  this.currentPage.set(cloned);
@@ -17805,10 +18177,21 @@ class DynamicPageBuilderComponent {
17805
18177
  toggleConnectionsViewer() {
17806
18178
  this.connectionsViewerOpen.update((current) => !current);
17807
18179
  }
18180
+ connectionsToggleLabel() {
18181
+ if (this.connectionsViewerOpen()) {
18182
+ return this.tx('connections.close', 'Close connections');
18183
+ }
18184
+ return this.tx('connections.toggle', 'Edit connections');
18185
+ }
17808
18186
  onAddComponent() {
17809
18187
  const ref = this.dialog.open(ComponentPaletteDialogComponent, {
17810
18188
  width: '720px',
17811
- data: { title: this.tx('connections.palette.insertComponent', 'Insert component') },
18189
+ data: {
18190
+ title: this.tx('connections.palette.insertComponent', 'Insert component'),
18191
+ allowedWidgetIds: this.componentPaletteAllowedWidgetIds || undefined,
18192
+ allowedWidgetTags: this.componentPaletteAllowedWidgetTags || undefined,
18193
+ allowedPresetIds: this.componentPaletteAllowedPresetIds || undefined,
18194
+ },
17812
18195
  });
17813
18196
  ref.afterClosed().subscribe((selection) => {
17814
18197
  if (selection)
@@ -17827,6 +18210,10 @@ class DynamicPageBuilderComponent {
17827
18210
  next.widgets = widgets;
17828
18211
  if (next.canvas) {
17829
18212
  const lastRow = Math.max(1, ...Object.values(next.canvas.items || {}).map((item) => (item.row + item.rowSpan) - 1));
18213
+ const canvasColumns = Math.max(1, next.canvas.columns || 1);
18214
+ const layoutHints = this.layoutHintsFor(type);
18215
+ const colSpan = Math.min(canvasColumns, Math.max(1, layoutHints?.recommendedCols ?? Math.min(4, canvasColumns)));
18216
+ const rowSpan = Math.max(1, layoutHints?.recommendedRows ?? 2);
17830
18217
  next.canvas = {
17831
18218
  ...next.canvas,
17832
18219
  items: {
@@ -17834,18 +18221,38 @@ class DynamicPageBuilderComponent {
17834
18221
  [key]: {
17835
18222
  col: 1,
17836
18223
  row: lastRow + 1,
17837
- colSpan: Math.min(4, Math.max(1, next.canvas.columns || 1)),
17838
- rowSpan: 2,
18224
+ colSpan,
18225
+ rowSpan,
17839
18226
  },
17840
18227
  },
17841
18228
  };
17842
18229
  }
17843
18230
  this.currentPage.set(next);
18231
+ this.selectInsertedWidget(key, widgets.length);
17844
18232
  this.pageChange.emit(this.clonePage(next));
17845
18233
  }
18234
+ layoutHintsFor(componentId) {
18235
+ const metadataHints = this.componentMetadata.get(componentId)?.layoutHints;
18236
+ if (metadataHints) {
18237
+ return metadataHints;
18238
+ }
18239
+ switch (componentId) {
18240
+ case 'praxis-table':
18241
+ return { recommendedCols: 8, recommendedRows: 6 };
18242
+ case 'praxis-filter':
18243
+ return { recommendedCols: 12, recommendedRows: 3 };
18244
+ case 'praxis-chart':
18245
+ case 'praxis-list':
18246
+ case 'praxis-crud':
18247
+ return { recommendedCols: 8, recommendedRows: 5 };
18248
+ default:
18249
+ return undefined;
18250
+ }
18251
+ }
17846
18252
  openPageSettings() {
17847
18253
  if (!this.pageEditorComponent)
17848
18254
  return;
18255
+ this.connectionsViewerOpen.set(false);
17849
18256
  this.runtime?.openPageSettings();
17850
18257
  }
17851
18258
  saveCurrentPage() {
@@ -17862,6 +18269,181 @@ class DynamicPageBuilderComponent {
17862
18269
  canSaveCurrentPage() {
17863
18270
  return this.hasPageWidgets() && !this.hasBlockingAgenticReview();
17864
18271
  }
18272
+ evaluatePremiumReadiness(page) {
18273
+ const widgets = page.widgets || [];
18274
+ if (!widgets.length) {
18275
+ return [];
18276
+ }
18277
+ const issues = [];
18278
+ const themePreset = (page.themePreset || '').trim();
18279
+ const hasKnownThemePreset = !!themePreset && Object.prototype.hasOwnProperty.call(BUILTIN_PAGE_THEME_PRESETS, themePreset);
18280
+ const isDashboard = this.isPremiumReadinessCandidate(page);
18281
+ if (!isDashboard) {
18282
+ return [];
18283
+ }
18284
+ if (!themePreset) {
18285
+ issues.push({
18286
+ id: 'theme-missing',
18287
+ severity: 'warning',
18288
+ title: this.tx('premiumReadiness.themeMissing.title', 'Defina um tema executivo'),
18289
+ description: this.tx('premiumReadiness.themeMissing.description', 'Dashboards corporativos precisam de preset visual para densidade, shell e tokens consistentes.'),
18290
+ action: {
18291
+ kind: 'open-page-settings',
18292
+ label: this.tx('premiumReadiness.actions.openPageSettings', 'Abrir configurações da página'),
18293
+ },
18294
+ });
18295
+ }
18296
+ else if (!hasKnownThemePreset) {
18297
+ issues.push({
18298
+ id: 'theme-unknown',
18299
+ severity: 'error',
18300
+ title: this.tx('premiumReadiness.themeUnknown.title', 'Tema não reconhecido'),
18301
+ description: this.tx('premiumReadiness.themeUnknown.description', 'O preset informado não existe no catálogo canônico e pode cair em aparência genérica.'),
18302
+ action: {
18303
+ kind: 'open-page-settings',
18304
+ label: this.tx('premiumReadiness.actions.reviewTheme', 'Revisar tema'),
18305
+ },
18306
+ });
18307
+ }
18308
+ if (isDashboard && page.canvas && !page.deviceLayouts?.mobile?.canvas) {
18309
+ issues.push({
18310
+ id: 'mobile-layout-missing',
18311
+ severity: 'warning',
18312
+ title: this.tx('premiumReadiness.mobileMissing.title', 'Inclua layout mobile'),
18313
+ description: this.tx('premiumReadiness.mobileMissing.description', 'Uma página premium precisa preservar hierarquia e leitura em telas menores.'),
18314
+ action: {
18315
+ kind: 'open-page-settings',
18316
+ label: this.tx('premiumReadiness.actions.openDeviceLayouts', 'Abrir layouts'),
18317
+ },
18318
+ });
18319
+ }
18320
+ if (this.hasDisconnectedOperationalWidgets(page)) {
18321
+ issues.push({
18322
+ id: 'widgets-disconnected',
18323
+ severity: 'warning',
18324
+ title: this.tx('premiumReadiness.disconnected.title', 'Conecte filtros, gráficos e filas'),
18325
+ description: this.tx('premiumReadiness.disconnected.description', 'A composição parece visualmente rica, mas ainda não mostra causa e efeito entre widgets.'),
18326
+ action: {
18327
+ kind: 'open-connections',
18328
+ label: this.tx('premiumReadiness.actions.openConnections', 'Abrir conexões'),
18329
+ },
18330
+ });
18331
+ }
18332
+ const localAnalyticWidget = widgets.find((widget) => this.usesLocalAnalyticData(widget));
18333
+ if (localAnalyticWidget) {
18334
+ issues.push({
18335
+ id: 'local-data-source',
18336
+ severity: 'info',
18337
+ title: this.tx('premiumReadiness.localData.title', 'Troque dados locais por fonte governada'),
18338
+ description: this.tx('premiumReadiness.localData.description', 'Dados locais ajudam a prototipar, mas produção deve apontar para recurso, endpoint ou estado governado.'),
18339
+ action: {
18340
+ kind: 'open-widget-config',
18341
+ label: this.tx('premiumReadiness.actions.openWidgetConfig', 'Abrir widget'),
18342
+ widgetKey: localAnalyticWidget.key,
18343
+ },
18344
+ });
18345
+ }
18346
+ const latePrimaryChartKey = this.latePrimaryChartKey(page);
18347
+ if (latePrimaryChartKey) {
18348
+ issues.push({
18349
+ id: 'late-primary-chart',
18350
+ severity: 'info',
18351
+ title: this.tx('premiumReadiness.chartHierarchy.title', 'Suba o gráfico principal'),
18352
+ description: this.tx('premiumReadiness.chartHierarchy.description', 'O primeiro gráfico deveria aparecer cedo o bastante para orientar a primeira dobra.'),
18353
+ action: {
18354
+ kind: 'focus-widget',
18355
+ label: this.tx('premiumReadiness.actions.focusChart', 'Focar gráfico'),
18356
+ widgetKey: latePrimaryChartKey,
18357
+ },
18358
+ });
18359
+ }
18360
+ return issues;
18361
+ }
18362
+ runPremiumReadinessAction(issue) {
18363
+ const action = issue.action;
18364
+ if (!action)
18365
+ return;
18366
+ if (this.previewMode) {
18367
+ this.previewMode = false;
18368
+ }
18369
+ switch (action.kind) {
18370
+ case 'open-page-settings':
18371
+ this.openPageSettings();
18372
+ return;
18373
+ case 'open-connections':
18374
+ this.connectionsViewerOpen.set(true);
18375
+ return;
18376
+ case 'open-widget-config':
18377
+ if (action.widgetKey) {
18378
+ this.openWidgetConfiguration(action.widgetKey);
18379
+ }
18380
+ return;
18381
+ case 'focus-widget':
18382
+ if (action.widgetKey) {
18383
+ this.connectionsViewerOpen.set(false);
18384
+ this.focusCanvasWidget(action.widgetKey);
18385
+ }
18386
+ return;
18387
+ }
18388
+ }
18389
+ isPremiumReadinessCandidate(page) {
18390
+ const widgets = page.widgets || [];
18391
+ if (widgets.length >= 4) {
18392
+ return true;
18393
+ }
18394
+ const analyticWidgets = widgets.filter((widget) => this.isAnalyticWidget(widget.definition?.id));
18395
+ if (analyticWidgets.length >= 2) {
18396
+ return true;
18397
+ }
18398
+ const hasFilter = widgets.some((widget) => widget.definition?.id === 'praxis-filter');
18399
+ if (hasFilter && analyticWidgets.length > 0) {
18400
+ return true;
18401
+ }
18402
+ return (page.composition?.links || []).length > 0 && analyticWidgets.length > 0;
18403
+ }
18404
+ hasDisconnectedOperationalWidgets(page) {
18405
+ const widgets = page.widgets || [];
18406
+ const hasFilter = widgets.some((widget) => widget.definition?.id === 'praxis-filter');
18407
+ const hasConsumer = widgets.some((widget) => {
18408
+ const id = widget.definition?.id;
18409
+ return id === 'praxis-chart' || id === 'praxis-list' || id === 'praxis-table';
18410
+ });
18411
+ if (!hasFilter || !hasConsumer) {
18412
+ return false;
18413
+ }
18414
+ return !(page.composition?.links || []).length;
18415
+ }
18416
+ latePrimaryChartKey(page) {
18417
+ const chartKeys = (page.widgets || [])
18418
+ .filter((widget) => widget.definition?.id === 'praxis-chart')
18419
+ .map((widget) => widget.key)
18420
+ .filter(Boolean);
18421
+ if (!chartKeys.length || !page.canvas?.items) {
18422
+ return null;
18423
+ }
18424
+ const firstChart = chartKeys
18425
+ .map((key) => ({ key, row: page.canvas?.items?.[key]?.row }))
18426
+ .filter((item) => typeof item.row === 'number')
18427
+ .sort((left, right) => left.row - right.row)[0];
18428
+ return firstChart && firstChart.row > 8 ? firstChart.key : null;
18429
+ }
18430
+ usesLocalAnalyticData(widget) {
18431
+ if (!this.isAnalyticWidget(widget.definition?.id)) {
18432
+ return false;
18433
+ }
18434
+ const config = widget.definition?.inputs?.['config'];
18435
+ const configRecord = this.toRecord(config);
18436
+ if (!configRecord) {
18437
+ return false;
18438
+ }
18439
+ const dataSource = this.toRecord(configRecord['dataSource']);
18440
+ return dataSource?.['kind'] === 'local';
18441
+ }
18442
+ isAnalyticWidget(componentId) {
18443
+ return componentId === 'praxis-chart'
18444
+ || componentId === 'praxis-list'
18445
+ || componentId === 'praxis-table';
18446
+ }
17865
18447
  applyConfigFromAdapter(config) {
17866
18448
  if (!config.page)
17867
18449
  return;
@@ -17908,9 +18490,9 @@ class DynamicPageBuilderComponent {
17908
18490
  this.syncAgenticAuthoringSession('active');
17909
18491
  }
17910
18492
  minimizeAgenticAuthoring() {
17911
- this.agenticAuthoringOpen.set(false);
17912
18493
  this.agenticAuthoringError.set('');
17913
18494
  this.syncAgenticAuthoringSession('minimized');
18495
+ this.agenticAuthoringOpen.set(false);
17914
18496
  }
17915
18497
  onAgenticAuthoringLayoutChange(layout) {
17916
18498
  this.agenticAuthoringPanelLayoutTouched = true;
@@ -17934,90 +18516,90 @@ class DynamicPageBuilderComponent {
17934
18516
  }
17935
18517
  agenticAuthoringToggleLabel() {
17936
18518
  if (this.agenticAuthoringOpen()) {
17937
- return this.tx('agentic.toggle.minimize', 'Minimize Praxis copilot');
18519
+ return this.tx('agentic.toggle.minimize', 'Minimizar copiloto Praxis');
17938
18520
  }
17939
18521
  if (this.agenticAuthoringMinimized()) {
17940
- return this.tx('agentic.dock.openTooltip', 'Reopen Praxis copilot');
18522
+ return this.tx('agentic.dock.openTooltip', 'Reabrir copiloto Praxis');
17941
18523
  }
17942
- return this.tx('agentic.toggle', 'Create with AI');
18524
+ return this.tx('agentic.toggle', 'Criar com IA');
17943
18525
  }
17944
18526
  agenticAuthoringHeaderTitle() {
17945
18527
  if (this.agenticAuthoringSharedRuleHandoffState()) {
17946
- return this.tx('agentic.header.title.governed', 'Praxis governed copilot');
18528
+ return this.tx('agentic.header.title.governed', 'Copiloto governado Praxis');
17947
18529
  }
17948
18530
  if (this.agenticAuthoringPreviewResult()?.valid) {
17949
- return this.tx('agentic.header.title.review', 'Praxis review copilot');
18531
+ return this.tx('agentic.header.title.review', 'Copiloto de revisão Praxis');
17950
18532
  }
17951
18533
  if (this.resolveSelectedWidgetKey()) {
17952
- return this.tx('agentic.header.title.widget', 'Praxis widget copilot');
18534
+ return this.tx('agentic.header.title.widget', 'Copiloto de componente Praxis');
17953
18535
  }
17954
- return this.tx('agentic.header.title.page', 'Praxis page decision copilot');
18536
+ return this.tx('agentic.header.title.page', 'Copiloto de página Praxis');
17955
18537
  }
17956
18538
  agenticAuthoringHeaderSubtitle() {
17957
18539
  const selectedWidgetLabel = this.resolveSelectedWidgetLabel();
17958
18540
  if (this.agenticAuthoringSharedRuleHandoffState()) {
17959
- return this.tx('agentic.header.subtitle.governed', 'Continue the governed semantic-decision flow.');
18541
+ return this.tx('agentic.header.subtitle.governed', 'Continue a revisão da regra antes de criar a tela.');
17960
18542
  }
17961
18543
  if (this.agenticAuthoringPreviewResult()?.valid) {
17962
18544
  if (!this.agenticAuthoringCanApply()) {
17963
- return this.tx('agentic.header.subtitle.reviewBlocked', 'Preview ready for governed review.');
18545
+ return this.tx('agentic.header.subtitle.reviewBlocked', 'Prévia pronta, com pontos para revisar.');
17964
18546
  }
17965
- return this.tx('agentic.header.subtitle.review', 'Preview ready for review and persistence.');
18547
+ return this.tx('agentic.header.subtitle.review', 'Prévia pronta para revisar e salvar.');
17966
18548
  }
17967
18549
  if (selectedWidgetLabel) {
17968
- return this.tx('agentic.header.subtitle.widget', 'Focused on {target}.')
18550
+ return this.tx('agentic.header.subtitle.widget', 'Foco em {target}.')
17969
18551
  .replace('{target}', selectedWidgetLabel);
17970
18552
  }
17971
18553
  const routePath = this.pageIdentity?.routePath?.trim();
17972
18554
  if (routePath) {
17973
- return this.tx('agentic.header.subtitle.route', 'Authoring page route {route}.')
18555
+ return this.tx('agentic.header.subtitle.route', 'Criando ou ajustando a página {route}.')
17974
18556
  .replace('{route}', routePath);
17975
18557
  }
17976
- return this.tx('agentic.header.subtitle.page', 'Turn intent into layout, widgets, and governed materializations.');
18558
+ return this.tx('agentic.header.subtitle.page', 'Transforme uma necessidade do domínio em tabela, formulário ou painel.');
17977
18559
  }
17978
18560
  agenticAuthoringHeaderModeLabel() {
17979
18561
  if (this.agenticAuthoringSharedRuleHandoffState()) {
17980
- return this.tx('agentic.header.mode.governed', 'Governed');
18562
+ return this.tx('agentic.header.mode.governed', 'Governado');
17981
18563
  }
17982
18564
  if (this.resolveSelectedWidgetKey()) {
17983
18565
  return this.tx('agentic.header.mode.widget', 'Widget');
17984
18566
  }
17985
- return this.tx('agentic.header.mode.page', 'Page');
18567
+ return this.tx('agentic.header.mode.page', 'Página');
17986
18568
  }
17987
18569
  agenticAuthoringShellLabels() {
17988
18570
  return {
17989
18571
  title: this.agenticAuthoringHeaderTitle(),
17990
18572
  subtitle: this.agenticAuthoringHeaderSubtitle(),
17991
- close: this.tx('agentic.minimize', 'Minimize'),
17992
- prompt: this.tx('agentic.promptLabel', 'Message'),
17993
- promptPlaceholder: this.tx('agentic.promptPlaceholder', 'Describe the page, dashboard, form or change you need.'),
18573
+ close: this.tx('agentic.minimize', 'Minimizar'),
18574
+ prompt: this.tx('agentic.promptLabel', 'Mensagem'),
18575
+ promptPlaceholder: this.tx('agentic.promptPlaceholder', 'Descreva a página, dashboard, formulário ou alteração que você precisa.'),
17994
18576
  emptyConversation: this.agenticAuthoringEmptyConversationMessage(),
17995
- submit: this.tx('agentic.preview', 'Generate preview'),
17996
- apply: this.tx('agentic.persist', 'Save'),
17997
- conversationAria: this.tx('agentic.conversationAria', 'AI conversation'),
17998
- quickRepliesAria: this.tx('agentic.quickRepliesAria', 'Quick replies'),
17999
- dragHandleAria: this.tx('agentic.dragHandleAria', 'Move AI assistant'),
18000
- resizeHandleAria: this.tx('agentic.resizeHandleAria', 'Resize AI assistant'),
18001
- contextAria: this.tx('agentic.contextAria', 'Active context'),
18002
- attachmentsAria: this.tx('agentic.attachmentsAria', 'Attached context'),
18003
- attach: this.tx('agentic.attach', 'Attach'),
18004
- removeAttachment: this.tx('agentic.removeAttachment', 'Remove attachment'),
18005
- editMessage: this.tx('agentic.editMessage', 'Edit'),
18006
- resendMessage: this.tx('agentic.resendMessage', 'Resend'),
18577
+ submit: this.tx('agentic.submit', 'Enviar pedido'),
18578
+ apply: this.tx('agentic.persist', 'Salvar'),
18579
+ conversationAria: this.tx('agentic.conversationAria', 'Conversa com IA'),
18580
+ quickRepliesAria: this.tx('agentic.quickRepliesAria', 'Respostas rápidas'),
18581
+ dragHandleAria: this.tx('agentic.dragHandleAria', 'Mover assistente de IA'),
18582
+ resizeHandleAria: this.tx('agentic.resizeHandleAria', 'Redimensionar assistente de IA'),
18583
+ contextAria: this.tx('agentic.contextAria', 'Contexto ativo'),
18584
+ attachmentsAria: this.tx('agentic.attachmentsAria', 'Contexto anexado'),
18585
+ attach: this.tx('agentic.attach', 'Anexar'),
18586
+ removeAttachment: this.tx('agentic.removeAttachment', 'Remover anexo'),
18587
+ editMessage: this.tx('agentic.editMessage', 'Editar'),
18588
+ resendMessage: this.tx('agentic.resendMessage', 'Reenviar'),
18007
18589
  modeAgenticAuthoring: this.agenticAuthoringHeaderModeLabel(),
18008
- modeConfig: this.tx('agentic.mode.config', 'Configuration'),
18590
+ modeConfig: this.tx('agentic.mode.config', 'Configuração'),
18009
18591
  modeChat: this.tx('agentic.mode.chat', 'Chat'),
18010
- modeDiagnostic: this.tx('agentic.mode.diagnostic', 'Diagnostic'),
18011
- modeReview: this.tx('agentic.mode.review', 'Review'),
18012
- modeInlineHelp: this.tx('agentic.mode.inlineHelp', 'Help'),
18013
- stateIdle: this.tx('agentic.state.idle', 'Ready'),
18014
- stateListening: this.tx('agentic.state.listening', 'Ready'),
18015
- stateProcessing: this.tx('agentic.state.processing', 'Processing'),
18016
- stateClarification: this.tx('agentic.state.clarification', 'Waiting for input'),
18017
- stateReview: this.tx('agentic.state.review', 'Review'),
18018
- stateApplying: this.tx('agentic.state.applying', 'Applying'),
18019
- stateSuccess: this.tx('agentic.state.success', 'Done'),
18020
- stateError: this.tx('agentic.state.error', 'Error'),
18592
+ modeDiagnostic: this.tx('agentic.mode.diagnostic', 'Diagnóstico'),
18593
+ modeReview: this.tx('agentic.mode.review', 'Revisão'),
18594
+ modeInlineHelp: this.tx('agentic.mode.inlineHelp', 'Ajuda'),
18595
+ stateIdle: this.tx('agentic.state.idle', 'Pronto'),
18596
+ stateListening: this.tx('agentic.state.listening', 'Pronto'),
18597
+ stateProcessing: this.tx('agentic.state.processing', 'Processando'),
18598
+ stateClarification: this.tx('agentic.state.clarification', 'Aguardando resposta'),
18599
+ stateReview: this.tx('agentic.state.review', 'Revisão'),
18600
+ stateApplying: this.tx('agentic.state.applying', 'Aplicando'),
18601
+ stateSuccess: this.tx('agentic.state.success', 'Concluído'),
18602
+ stateError: this.tx('agentic.state.error', 'Erro'),
18021
18603
  };
18022
18604
  }
18023
18605
  agenticAuthoringEmptyConversationMessage() {
@@ -18026,9 +18608,9 @@ class DynamicPageBuilderComponent {
18026
18608
  return authoredOpening;
18027
18609
  }
18028
18610
  if (this.isAgenticAuthoringPageBlank()) {
18029
- return this.tx('agentic.emptyConversation.blankGeneric', 'This host page is still blank. Tell me what decision or activity this app needs to support. I can suggest a dashboard, table, form, or review flow, then turn it into a governed preview for you to review before anything changes.');
18611
+ return this.tx('agentic.emptyConversation.blankGeneric', 'Esta tela ainda está vazia. Diga qual atividade do domínio ela precisa apoiar. Posso sugerir um painel, tabela ou formulário e montar uma prévia para você revisar antes de salvar.');
18030
18612
  }
18031
- return this.tx('agentic.emptyConversation.existingPage', 'Tell me what you want to improve here. I can read the current layout, widgets, route, and governed context, then prepare a preview for you to review before anything changes.');
18613
+ return this.tx('agentic.emptyConversation.existingPage', 'Diga o que você quer melhorar nesta tela. Eu leio o que existe e preparo uma prévia para você revisar antes de salvar.');
18032
18614
  }
18033
18615
  resolveAgenticAuthoredOpeningMessage() {
18034
18616
  const hints = this.toRecord(this.agenticAuthoringContextHints);
@@ -18057,7 +18639,7 @@ class DynamicPageBuilderComponent {
18057
18639
  return !!this.agenticAuthoringPreviewResult()?.valid && !this.agenticAuthoringCanApply();
18058
18640
  }
18059
18641
  agenticAuthoringSubmitAction() {
18060
- const label = this.tx('agentic.preview', 'Generate preview');
18642
+ const label = this.tx('agentic.submit', 'Enviar pedido');
18061
18643
  return {
18062
18644
  id: 'submit',
18063
18645
  kind: 'submit-prompt',
@@ -18085,14 +18667,14 @@ class DynamicPageBuilderComponent {
18085
18667
  agenticAuthoringDockBadge() {
18086
18668
  const state = this.agenticAuthoringShellState();
18087
18669
  if (state === 'error')
18088
- return this.tx('agentic.dock.badgeError', 'Attention');
18670
+ return this.tx('agentic.dock.badgeError', 'Atenção');
18089
18671
  if (state === 'processing' || state === 'applying')
18090
- return this.tx('agentic.dock.badgeWorking', 'Working');
18672
+ return this.tx('agentic.dock.badgeWorking', 'Trabalhando');
18091
18673
  if (state === 'review')
18092
- return this.tx('agentic.dock.badgeReview', 'Review');
18674
+ return this.tx('agentic.dock.badgeReview', 'Revisão');
18093
18675
  if (state === 'clarification')
18094
- return this.tx('agentic.dock.badgeGoverned', 'Governed');
18095
- return this.tx('agentic.dock.badgeReady', 'Ready');
18676
+ return this.tx('agentic.dock.badgeGoverned', 'Governado');
18677
+ return this.tx('agentic.dock.badgeReady', 'Pronto');
18096
18678
  }
18097
18679
  agenticAuthoringDockSummary() {
18098
18680
  const status = this.agenticAuthoringStatus().trim();
@@ -18108,12 +18690,12 @@ class DynamicPageBuilderComponent {
18108
18690
  return this.truncateAgenticDockText(lastMessage.text);
18109
18691
  }
18110
18692
  if (this.agenticAuthoringPreviewResult()?.valid) {
18111
- return this.tx('agentic.dock.summaryReview', 'Preview ready. Reopen to review or save.');
18693
+ return this.tx('agentic.dock.summaryReview', 'Prévia pronta. Reabra para revisar ou salvar.');
18112
18694
  }
18113
18695
  if (this.agenticAuthoringSharedRuleHandoffState()) {
18114
- return this.tx('agentic.dock.summaryGoverned', 'Governed handoff preserved. Continue the semantic decision flow.');
18696
+ return this.tx('agentic.dock.summaryGoverned', 'Revisão preservada. Continue de onde parou.');
18115
18697
  }
18116
- return this.tx('agentic.dock.summaryIdle', 'Conversation preserved. Continue where you stopped.');
18698
+ return this.tx('agentic.dock.summaryIdle', 'Conversa preservada. Continue de onde parou.');
18117
18699
  }
18118
18700
  agenticAuthoringShellState() {
18119
18701
  if (this.agenticAuthoringBusy())
@@ -18621,6 +19203,7 @@ class DynamicPageBuilderComponent {
18621
19203
  const prompt = this.agenticAuthoringPrompt().trim();
18622
19204
  if (!prompt || this.agenticAuthoringBusy())
18623
19205
  return;
19206
+ const turnRunId = this.beginAgenticTurn();
18624
19207
  this.agenticAuthoringBusy.set(true);
18625
19208
  this.agenticAuthoringError.set('');
18626
19209
  this.agenticAuthoringPreviewResult.set(null);
@@ -18628,37 +19211,43 @@ class DynamicPageBuilderComponent {
18628
19211
  this.agenticAuthoringSharedRuleHandoffState.set(null);
18629
19212
  this.clearSharedRuleCockpitState();
18630
19213
  this.clearProjectKnowledgeCockpitState();
18631
- this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Resolving intent...'));
19214
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Entendendo o pedido...'));
18632
19215
  try {
18633
19216
  const controller = this.ensureAgenticTurnController();
18634
19217
  const editingMessageId = this.agenticAuthoringEditingMessageId();
18635
19218
  await this.consumeAgenticTurn(editingMessageId
18636
19219
  ? controller.submitEditedMessage(editingMessageId, prompt)
18637
- : controller.submitPrompt(prompt));
19220
+ : controller.submitPrompt(prompt), turnRunId);
18638
19221
  this.agenticAuthoringEditingMessageId.set(null);
18639
19222
  this.agenticAuthoringPrompt.set('');
18640
19223
  }
18641
19224
  catch (error) {
19225
+ if (!this.isCurrentAgenticTurn(turnRunId))
19226
+ return;
18642
19227
  this.agenticAuthoringStatus.set('');
18643
19228
  const message = this.describeAgenticError(error);
18644
19229
  this.agenticAuthoringError.set(message);
18645
19230
  this.appendAgenticMessage('error', message);
18646
19231
  }
18647
19232
  finally {
18648
- this.agenticAuthoringBusy.set(false);
19233
+ if (this.isCurrentAgenticTurn(turnRunId)) {
19234
+ this.agenticAuthoringBusy.set(false);
19235
+ }
18649
19236
  }
18650
19237
  }
18651
19238
  async submitAgenticQuickReply(reply) {
18652
19239
  const replyKind = (reply.kind || 'suggestion').trim().toLowerCase();
18653
19240
  if (replyKind === 'cancel') {
19241
+ this.cancelActiveAgenticTurn();
19242
+ this.agenticAuthoringBusy.set(false);
18654
19243
  this.agenticAuthoringEditingMessageId.set(null);
18655
- await this.consumeAgenticTurn(this.ensureAgenticTurnController().cancel());
19244
+ await this.applyAgenticTurnState(await firstValueFrom(this.ensureAgenticTurnController().cancel()));
18656
19245
  return;
18657
19246
  }
18658
19247
  if (replyKind === 'revise') {
18659
19248
  this.agenticAuthoringEditingMessageId.set(null);
18660
19249
  this.agenticAuthoringQuickReplies.set([]);
18661
- this.agenticAuthoringStatus.set(this.tx('agentic.status.waitingRevision', 'Refine your prompt and preview again.'));
19250
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.waitingRevision', 'Ajuste o pedido e crie uma nova prévia.'));
18662
19251
  return;
18663
19252
  }
18664
19253
  this.agenticAuthoringEditingMessageId.set(null);
@@ -18669,6 +19258,7 @@ class DynamicPageBuilderComponent {
18669
19258
  return;
18670
19259
  }
18671
19260
  this.agenticAuthoringPrompt.set(visiblePrompt);
19261
+ const turnRunId = this.beginAgenticTurn();
18672
19262
  this.agenticAuthoringQuickReplies.set([]);
18673
19263
  this.agenticAuthoringBusy.set(true);
18674
19264
  this.agenticAuthoringError.set('');
@@ -18677,7 +19267,7 @@ class DynamicPageBuilderComponent {
18677
19267
  this.agenticAuthoringSharedRuleHandoffState.set(null);
18678
19268
  this.clearSharedRuleCockpitState();
18679
19269
  this.clearProjectKnowledgeCockpitState();
18680
- this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Resolving intent...'));
19270
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Entendendo o pedido...'));
18681
19271
  try {
18682
19272
  const controller = this.ensureAgenticTurnController();
18683
19273
  const actionKind = controller.snapshot().state === 'clarification'
@@ -18690,17 +19280,21 @@ class DynamicPageBuilderComponent {
18690
19280
  value: reply.prompt,
18691
19281
  displayPrompt: visiblePrompt,
18692
19282
  contextHints,
18693
- }));
19283
+ }), turnRunId);
18694
19284
  this.agenticAuthoringPrompt.set('');
18695
19285
  }
18696
19286
  catch (error) {
19287
+ if (!this.isCurrentAgenticTurn(turnRunId))
19288
+ return;
18697
19289
  this.agenticAuthoringStatus.set('');
18698
19290
  const message = this.describeAgenticError(error);
18699
19291
  this.agenticAuthoringError.set(message);
18700
19292
  this.appendAgenticMessage('error', message);
18701
19293
  }
18702
19294
  finally {
18703
- this.agenticAuthoringBusy.set(false);
19295
+ if (this.isCurrentAgenticTurn(turnRunId)) {
19296
+ this.agenticAuthoringBusy.set(false);
19297
+ }
18704
19298
  }
18705
19299
  }
18706
19300
  agenticQuickReplyVisiblePrompt(reply, contextHints) {
@@ -18894,54 +19488,64 @@ class DynamicPageBuilderComponent {
18894
19488
  return;
18895
19489
  this.agenticAuthoringEditingMessageId.set(message.id);
18896
19490
  this.agenticAuthoringPrompt.set(message.text);
18897
- this.agenticAuthoringStatus.set(this.tx('agentic.status.waitingRevision', 'Refine your prompt and preview again.'));
19491
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.waitingRevision', 'Ajuste o pedido e crie uma nova prévia.'));
18898
19492
  }
18899
19493
  async resendAgenticMessage(message) {
18900
19494
  if (message.role !== 'user' || this.agenticAuthoringBusy())
18901
19495
  return;
19496
+ const turnRunId = this.beginAgenticTurn();
18902
19497
  this.agenticAuthoringEditingMessageId.set(null);
18903
19498
  this.agenticAuthoringBusy.set(true);
18904
- this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Resolving intent...'));
19499
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Entendendo o pedido...'));
18905
19500
  this.agenticAuthoringError.set('');
18906
19501
  this.agenticAuthoringPreviewResult.set(null);
18907
19502
  this.agenticAuthoringCanApply.set(false);
18908
19503
  this.clearProjectKnowledgeCockpitState();
18909
19504
  try {
18910
- await this.consumeAgenticTurn(this.ensureAgenticTurnController().resendMessage(message.id));
19505
+ await this.consumeAgenticTurn(this.ensureAgenticTurnController().resendMessage(message.id), turnRunId);
18911
19506
  }
18912
19507
  catch (error) {
19508
+ if (!this.isCurrentAgenticTurn(turnRunId))
19509
+ return;
18913
19510
  this.agenticAuthoringStatus.set('');
18914
19511
  const errorMessage = this.describeAgenticError(error);
18915
19512
  this.agenticAuthoringError.set(errorMessage);
18916
19513
  this.appendAgenticMessage('error', errorMessage);
18917
19514
  }
18918
19515
  finally {
18919
- this.agenticAuthoringBusy.set(false);
19516
+ if (this.isCurrentAgenticTurn(turnRunId)) {
19517
+ this.agenticAuthoringBusy.set(false);
19518
+ }
18920
19519
  }
18921
19520
  }
18922
19521
  async retryAgenticAuthoring() {
18923
19522
  if (this.agenticAuthoringBusy())
18924
19523
  return;
19524
+ const turnRunId = this.beginAgenticTurn();
18925
19525
  this.agenticAuthoringEditingMessageId.set(null);
18926
19526
  this.agenticAuthoringBusy.set(true);
18927
- this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Resolving intent...'));
19527
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Entendendo o pedido...'));
18928
19528
  this.agenticAuthoringError.set('');
18929
19529
  try {
18930
- await this.consumeAgenticTurn(this.ensureAgenticTurnController().retry());
19530
+ await this.consumeAgenticTurn(this.ensureAgenticTurnController().retry(), turnRunId);
18931
19531
  }
18932
19532
  catch (error) {
19533
+ if (!this.isCurrentAgenticTurn(turnRunId))
19534
+ return;
18933
19535
  this.agenticAuthoringStatus.set('');
18934
19536
  const errorMessage = this.describeAgenticError(error);
18935
19537
  this.agenticAuthoringError.set(errorMessage);
18936
19538
  this.appendAgenticMessage('error', errorMessage);
18937
19539
  }
18938
19540
  finally {
18939
- this.agenticAuthoringBusy.set(false);
19541
+ if (this.isCurrentAgenticTurn(turnRunId)) {
19542
+ this.agenticAuthoringBusy.set(false);
19543
+ }
18940
19544
  }
18941
19545
  }
18942
19546
  async cancelAgenticAuthoring() {
18943
- if (this.agenticAuthoringBusy())
18944
- return;
19547
+ this.cancelActiveAgenticTurn();
19548
+ this.agenticAuthoringBusy.set(false);
18945
19549
  this.agenticAuthoringEditingMessageId.set(null);
18946
19550
  this.agenticAuthoringPrompt.set('');
18947
19551
  this.agenticAuthoringPreviewResult.set(null);
@@ -18950,7 +19554,7 @@ class DynamicPageBuilderComponent {
18950
19554
  this.agenticAuthoringSharedRuleHandoffState.set(null);
18951
19555
  this.clearSharedRuleCockpitState();
18952
19556
  this.clearProjectKnowledgeCockpitState();
18953
- await this.consumeAgenticTurn(this.ensureAgenticTurnController().cancel());
19557
+ await this.applyAgenticTurnState(await firstValueFrom(this.ensureAgenticTurnController().cancel()));
18954
19558
  }
18955
19559
  async persistAgenticAuthoring() {
18956
19560
  const preview = this.agenticAuthoringPreviewResult();
@@ -18963,7 +19567,7 @@ class DynamicPageBuilderComponent {
18963
19567
  }
18964
19568
  this.agenticAuthoringBusy.set(true);
18965
19569
  this.agenticAuthoringError.set('');
18966
- this.agenticAuthoringStatus.set(this.tx('agentic.status.saving', 'Saving page...'));
19570
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.saving', 'Salvando tela...'));
18967
19571
  try {
18968
19572
  const compiledFormPatch = this.resolvePreviewCompiledFormPatch(preview);
18969
19573
  const result = await firstValueFrom(this.agenticAuthoring.applyPage({
@@ -18983,7 +19587,7 @@ class DynamicPageBuilderComponent {
18983
19587
  this.agenticAuthoringCanApply.set(false);
18984
19588
  this.agenticAuthoringQuickReplies.set([]);
18985
19589
  this.agenticAuthoringPrompt.set('');
18986
- this.agenticAuthoringStatus.set(this.tx('agentic.status.saved', 'Page saved.'));
19590
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.saved', 'Tela salva.'));
18987
19591
  this.syncAgenticAuthoringSession();
18988
19592
  }
18989
19593
  catch (error) {
@@ -19000,7 +19604,7 @@ class DynamicPageBuilderComponent {
19000
19604
  return null;
19001
19605
  if (handoff.ruleDefinitionId?.trim()) {
19002
19606
  this.sharedRuleCockpitError.set('');
19003
- this.appendAgenticMessage('assistant', this.tx('agentic.sharedRuleCockpit.definitionReady', 'Governed definition is ready for simulation and review.'));
19607
+ this.appendAgenticMessage('assistant', this.tx('agentic.sharedRuleCockpit.definitionReady', 'Definição governada pronta para simulação e revisão.'));
19004
19608
  await this.refreshSharedRuleTimeline();
19005
19609
  return this.sharedRuleCockpitDefinition();
19006
19610
  }
@@ -19135,8 +19739,8 @@ class DynamicPageBuilderComponent {
19135
19739
  const enforcement = this.summarizeSharedRuleEnforcement(materializations);
19136
19740
  this.sharedRuleCockpitEnforcement.set(enforcement);
19137
19741
  this.appendAgenticMessage('assistant', enforcement.status === 'ready'
19138
- ? this.tx('agentic.sharedRuleCockpit.enforcementReady', 'Runtime enforcement validation is ready: applied materializations are available for consumer runtimes.')
19139
- : this.tx('agentic.sharedRuleCockpit.enforcementWaiting', 'Runtime enforcement is still waiting for applied materializations. Publish or review materialization status before validating a consumer runtime.'));
19742
+ ? this.tx('agentic.sharedRuleCockpit.enforcementReady', 'Validação de enforcement runtime pronta: materializações aplicadas estão disponíveis para os runtimes consumidores.')
19743
+ : this.tx('agentic.sharedRuleCockpit.enforcementWaiting', 'O enforcement runtime ainda aguarda materializações aplicadas. Publique ou revise o status de materialização antes de validar um runtime consumidor.'));
19140
19744
  await this.refreshSharedRuleTimeline();
19141
19745
  return enforcement;
19142
19746
  });
@@ -19543,14 +20147,14 @@ class DynamicPageBuilderComponent {
19543
20147
  next.ruleKey = current.ruleKey || this.resolveSharedRuleKey(next, false);
19544
20148
  this.agenticAuthoringPrompt.set(visiblePrompt);
19545
20149
  this.agenticAuthoringQuickReplies.set([]);
19546
- this.agenticAuthoringStatus.set(this.tx('agentic.status.sharedRuleTargetSelected', 'Shared-rule target selected. Continue by creating the governed definition.'));
20150
+ this.agenticAuthoringStatus.set(this.tx('agentic.status.sharedRuleTargetSelected', 'Continue this request in the rule review.'));
19547
20151
  this.agenticAuthoringError.set('');
19548
20152
  this.agenticAuthoringPreviewResult.set(null);
19549
20153
  this.agenticAuthoringCanApply.set(false);
19550
20154
  this.agenticAuthoringSharedRuleHandoffState.set(next);
19551
20155
  this.agenticAuthoringSharedRuleHandoff.emit(next);
19552
20156
  this.appendAgenticMessage('user', visiblePrompt);
19553
- this.appendAgenticMessage('assistant', this.tx('agentic.sharedRuleCockpit.targetSelected', 'Shared-rule target selected. The next safe step is creating the governed definition.'));
20157
+ this.appendAgenticMessage('assistant', this.tx('agentic.sharedRuleCockpit.targetSelected', 'Rule identified. The next safe step is reviewing the rule before creating the screen.'));
19554
20158
  return true;
19555
20159
  }
19556
20160
  resolveSharedRuleQuickReplyRuleType(contextHints, text) {
@@ -19763,6 +20367,12 @@ class DynamicPageBuilderComponent {
19763
20367
  });
19764
20368
  return this.agenticComponentCapabilitiesPromise;
19765
20369
  }
20370
+ async collectRuntimeComponentObservationsForAgenticTurn() {
20371
+ if (!this.runtimeObservationRegistry) {
20372
+ return [];
20373
+ }
20374
+ return this.runtimeObservationRegistry.listActive();
20375
+ }
19766
20376
  ensureAgenticTurnController() {
19767
20377
  if (!this.agenticTurnController) {
19768
20378
  const flow = new PageBuilderAgenticAuthoringTurnFlow(this.agenticAuthoring, {
@@ -19775,6 +20385,7 @@ class DynamicPageBuilderComponent {
19775
20385
  apiKey: () => this.agenticAuthoringApiKey,
19776
20386
  enableTurnStream: () => this.agenticAuthoringEnableStreaming,
19777
20387
  includeLlmDiagnostics: () => this.agenticAuthoringIncludeLlmDiagnostics,
20388
+ collectRuntimeComponentObservations: () => this.collectRuntimeComponentObservationsForAgenticTurn(),
19778
20389
  loadComponentCapabilities: () => this.loadAgenticComponentCapabilities(),
19779
20390
  applyLocalPreview: (result) => this.applyAgenticPreviewLocally(result),
19780
20391
  describePreviewFailure: (result) => this.describeAgenticPreviewFailure(result),
@@ -19804,7 +20415,7 @@ class DynamicPageBuilderComponent {
19804
20415
  if (!applied.success && this.isAgenticTableContractError(applied.error)) {
19805
20416
  return {
19806
20417
  ...applied,
19807
- error: this.tx('agentic.errors.invalidTableContract', 'I found the data source, but the generated plan used properties that are incompatible with the table component. I will adjust it to use only supported fields.'),
20418
+ error: this.tx('agentic.errors.invalidTableContract', 'Encontrei a fonte de dados, mas a tabela proposta usa informações que esse componente não aceita. Vou ajustar para usar apenas campos compatíveis.'),
19808
20419
  };
19809
20420
  }
19810
20421
  return applied;
@@ -19816,7 +20427,7 @@ class DynamicPageBuilderComponent {
19816
20427
  this.agenticAuthoringConversation.set(state.messages);
19817
20428
  this.agenticAuthoringQuickReplies.set(state.quickReplies);
19818
20429
  this.agenticAuthoringStatus.set(handoff && !preview?.valid
19819
- ? this.tx('agentic.status.sharedRuleHandoff', 'Continue this request in the shared-rules flow.')
20430
+ ? this.tx('agentic.status.sharedRuleHandoff', 'Continue este pedido na revisão da regra.')
19820
20431
  : state.statusText);
19821
20432
  this.agenticAuthoringError.set(state.errorText);
19822
20433
  this.agenticAuthoringPreviewResult.set(preview);
@@ -20018,8 +20629,69 @@ class DynamicPageBuilderComponent {
20018
20629
  }
20019
20630
  return Object.keys(merged).length ? merged : undefined;
20020
20631
  }
20021
- consumeAgenticTurn(states$) {
20022
- return firstValueFrom(states$.pipe(concatMap((state) => from(this.applyAgenticTurnState(state)).pipe(map(() => state))), filter((state) => this.isAgenticTurnTerminalState(state)), take(1)));
20632
+ consumeAgenticTurn(states$, turnRunId) {
20633
+ return firstValueFrom(states$.pipe(takeUntil(this.agenticTurnCancel$), concatMap((state) => {
20634
+ if (!this.isCurrentAgenticTurn(turnRunId)) {
20635
+ return of(state);
20636
+ }
20637
+ return from(this.applyAgenticTurnState(state)).pipe(map(() => state));
20638
+ }), filter((state) => this.isAgenticTurnTerminalState(state)), timeout({
20639
+ first: this.agenticAuthoringTurnTerminalTimeoutMs,
20640
+ with: () => of(this.createAgenticTurnTimeoutState()),
20641
+ }), take(1))).then(async (state) => {
20642
+ if (this.isCurrentAgenticTurn(turnRunId) && this.isAgenticTurnTimeoutState(state)) {
20643
+ await this.applyAgenticTurnState(state);
20644
+ }
20645
+ return state;
20646
+ });
20647
+ }
20648
+ beginAgenticTurn() {
20649
+ this.cancelActiveAgenticTurn();
20650
+ this.agenticTurnRunId += 1;
20651
+ return this.agenticTurnRunId;
20652
+ }
20653
+ cancelActiveAgenticTurn() {
20654
+ this.agenticTurnRunId += 1;
20655
+ this.agenticTurnCancel$.next();
20656
+ }
20657
+ isCurrentAgenticTurn(turnRunId) {
20658
+ return this.agenticTurnRunId === turnRunId;
20659
+ }
20660
+ createAgenticTurnTimeoutState() {
20661
+ const message = this.tx('agentic.errors.streamTimeout', 'Ainda não consegui concluir este pedido. Tente novamente com um pedido mais específico ou revise o contexto ativo.');
20662
+ return {
20663
+ mode: 'agentic-authoring',
20664
+ state: 'error',
20665
+ phase: 'contextualize',
20666
+ statusText: '',
20667
+ errorText: message,
20668
+ messages: [
20669
+ ...this.agenticAuthoringConversation(),
20670
+ {
20671
+ id: `${Date.now()}-timeout-error`,
20672
+ role: 'error',
20673
+ text: message,
20674
+ },
20675
+ ],
20676
+ quickReplies: [],
20677
+ clarificationQuestions: [],
20678
+ contextItems: this.agenticAuthoringContextItems(),
20679
+ attachments: this.agenticAuthoringAttachments(),
20680
+ canApply: false,
20681
+ preview: null,
20682
+ diagnostics: {
20683
+ timeout: {
20684
+ schemaVersion: 'praxis-page-builder-agentic-turn-timeout.v1',
20685
+ source: 'dynamic-page-builder',
20686
+ elapsedMs: this.agenticAuthoringTurnTerminalTimeoutMs,
20687
+ },
20688
+ },
20689
+ };
20690
+ }
20691
+ isAgenticTurnTimeoutState(state) {
20692
+ const diagnostics = this.toRecord(state.diagnostics);
20693
+ const timeoutDiagnostics = this.toRecord(diagnostics?.['timeout']);
20694
+ return timeoutDiagnostics?.['source'] === 'dynamic-page-builder';
20023
20695
  }
20024
20696
  isAgenticTurnTerminalState(state) {
20025
20697
  return state.state === 'review'
@@ -20118,8 +20790,46 @@ class DynamicPageBuilderComponent {
20118
20790
  focusCanvasWidget(widgetKey) {
20119
20791
  if (!widgetKey)
20120
20792
  return;
20793
+ this.selectedWidgetKey.set(widgetKey);
20121
20794
  this.runtime?.selectWidget(widgetKey);
20122
20795
  }
20796
+ openWidgetConfiguration(widgetKey) {
20797
+ if (!widgetKey)
20798
+ return;
20799
+ this.connectionsViewerOpen.set(false);
20800
+ this.focusCanvasWidget(widgetKey);
20801
+ this.runtime?.openWidgetComponentSettings(widgetKey);
20802
+ }
20803
+ selectInsertedWidget(widgetKey, expectedWidgetCount) {
20804
+ this.selectedWidgetKey.set(widgetKey);
20805
+ this.deferInsertedWidgetFocus(widgetKey, expectedWidgetCount, 0);
20806
+ }
20807
+ deferInsertedWidgetFocus(widgetKey, expectedWidgetCount, attempt) {
20808
+ setTimeout(() => {
20809
+ const ready = this.scrollInsertedWidgetIntoView(widgetKey, expectedWidgetCount);
20810
+ if (!ready && attempt < 5) {
20811
+ this.deferInsertedWidgetFocus(widgetKey, expectedWidgetCount, attempt + 1);
20812
+ return;
20813
+ }
20814
+ setTimeout(() => this.focusCanvasWidget(widgetKey), 120);
20815
+ }, attempt === 0 ? 50 : 120);
20816
+ }
20817
+ scrollInsertedWidgetIntoView(widgetKey, expectedWidgetCount) {
20818
+ const widgets = this.hostElement.nativeElement.querySelectorAll('praxis-dynamic-page .pdx-widget');
20819
+ if (widgets.length < expectedWidgetCount) {
20820
+ return false;
20821
+ }
20822
+ const target = this.hostElement.nativeElement.querySelector(`praxis-dynamic-page .pdx-widget[data-widget-key="${this.escapeAttributeValue(widgetKey)}"]`) || widgets.item(widgets.length - 1);
20823
+ target?.scrollIntoView?.({
20824
+ block: 'center',
20825
+ inline: 'nearest',
20826
+ behavior: 'smooth',
20827
+ });
20828
+ return !!target;
20829
+ }
20830
+ escapeAttributeValue(value) {
20831
+ return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
20832
+ }
20123
20833
  parsePage(input) {
20124
20834
  if (!input)
20125
20835
  return undefined;
@@ -20226,16 +20936,16 @@ class DynamicPageBuilderComponent {
20226
20936
  formatAgenticFailures(failureCodes) {
20227
20937
  const codes = (failureCodes ?? []).filter((code) => !!code);
20228
20938
  if (codes.length === 0) {
20229
- return this.tx('agentic.errors.invalidPreview', 'Generated preview is invalid.');
20939
+ return this.tx('agentic.errors.invalidPreview', 'Não consegui montar uma prévia segura para este pedido.');
20230
20940
  }
20231
- return `${this.tx('agentic.errors.invalidPreview', 'Generated preview is invalid.')}: ${codes.join(', ')}`;
20941
+ return this.tx('agentic.errors.invalidPreviewWithDetails', 'Não consegui montar uma prévia segura. Revise o pedido ou escolha outra fonte de dados.');
20232
20942
  }
20233
20943
  describeAgenticPreviewFailure(result) {
20234
20944
  switch (result.diagnostics?.fieldScopeDecision) {
20235
20945
  case 'rejected-duplicate-field':
20236
- return this.tx('agentic.errors.duplicateField', 'This field already exists in the selected form.');
20946
+ return this.tx('agentic.errors.duplicateField', 'Este campo existe no formulário selecionado.');
20237
20947
  case 'rejected-non-local-field-removal':
20238
- return this.tx('agentic.errors.nonLocalFieldRemoval', 'Only local fields created by AI can be removed in this flow.');
20948
+ return this.tx('agentic.errors.nonLocalFieldRemoval', ' posso remover, por aqui, campos que foram criados nesta própria prévia.');
20239
20949
  default:
20240
20950
  return this.formatAgenticFailures(result.failureCodes);
20241
20951
  }
@@ -20249,13 +20959,13 @@ class DynamicPageBuilderComponent {
20249
20959
  }
20250
20960
  switch (result.diagnostics?.fieldScopeDecision) {
20251
20961
  case 'accepted-add-local-field':
20252
- return this.tx('agentic.status.acceptedAddLocalField', 'Local field added to the form.');
20962
+ return this.tx('agentic.status.acceptedAddLocalField', 'Campo adicionado ao formulário.');
20253
20963
  case 'accepted-remove-local-field':
20254
- return this.tx('agentic.status.acceptedRemoveLocalField', 'Local field removed from the form.');
20964
+ return this.tx('agentic.status.acceptedRemoveLocalField', 'Campo removido do formulário.');
20255
20965
  case 'accepted-relabel-server-backed-field':
20256
- return this.tx('agentic.status.acceptedRelabelField', 'Field label updated.');
20966
+ return this.tx('agentic.status.acceptedRelabelField', 'Nome do campo atualizado.');
20257
20967
  default:
20258
- return this.tx('agentic.status.previewReady', 'Preview applied to the page.');
20968
+ return this.tx('agentic.status.previewReady', 'Prévia aplicada na tela.');
20259
20969
  }
20260
20970
  }
20261
20971
  isAgenticTableContractError(error) {
@@ -20278,7 +20988,7 @@ class DynamicPageBuilderComponent {
20278
20988
  }
20279
20989
  describeAgenticError(error) {
20280
20990
  if (error?.name === 'TimeoutError') {
20281
- return this.tx('agentic.errors.streamTimeout', 'The assistant took too long to finish this request. Try again with a narrower request or review the active context.');
20991
+ return this.tx('agentic.errors.streamTimeout', 'O assistente demorou para concluir este pedido. Tente de novo com um recorte menor ou revise o contexto ativo.');
20282
20992
  }
20283
20993
  if (typeof error?.error?.message === 'string' && error.error.message.trim()) {
20284
20994
  return error.error.message.trim();
@@ -20290,9 +21000,9 @@ class DynamicPageBuilderComponent {
20290
21000
  return error.message.trim();
20291
21001
  }
20292
21002
  if (typeof error?.status === 'number') {
20293
- return `HTTP ${error.status}`;
21003
+ return this.tx('agentic.errors.status', 'Não consegui concluir este pedido. Revise a conexão e tente novamente.');
20294
21004
  }
20295
- return this.tx('agentic.errors.generic', 'AI authoring failed.');
21005
+ return this.tx('agentic.errors.generic', 'Não consegui concluir este pedido.');
20296
21006
  }
20297
21007
  cloneValue(value) {
20298
21008
  if (value == null || typeof value !== 'object') {
@@ -20304,7 +21014,7 @@ class DynamicPageBuilderComponent {
20304
21014
  return resolvePraxisPageBuilderText(this.i18n, key, fallback);
20305
21015
  }
20306
21016
  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 });
20307
- 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: [
21017
+ 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", componentPaletteAllowedWidgetIds: "componentPaletteAllowedWidgetIds", componentPaletteAllowedWidgetTags: "componentPaletteAllowedWidgetTags", componentPaletteAllowedPresetIds: "componentPaletteAllowedPresetIds", 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: [
20308
21018
  providePraxisPageBuilderI18n(),
20309
21019
  { provide: DYNAMIC_PAGE_SHELL_EDITOR, useValue: WidgetShellEditorComponent },
20310
21020
  ], viewQueries: [{ propertyName: "runtime", first: true, predicate: ["runtime"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
@@ -20312,6 +21022,47 @@ class DynamicPageBuilderComponent {
20312
21022
  class="builder-shell"
20313
21023
  [class.builder-shell--agentic-review-rail]="agenticAuthoringReviewRailActive()"
20314
21024
  >
21025
+ @if (showSettings() && !connectionsViewerOpen() && premiumReadinessIssues().length) {
21026
+ <section
21027
+ class="builder-premium-readiness"
21028
+ data-testid="page-builder-premium-readiness"
21029
+ [attr.aria-label]="tx('premiumReadiness.title', 'Premium readiness')"
21030
+ >
21031
+ <header class="builder-premium-readiness__header">
21032
+ <span class="builder-premium-readiness__icon material-symbols-outlined" aria-hidden="true">auto_awesome</span>
21033
+ <div>
21034
+ <strong>{{ tx('premiumReadiness.title', 'Premium readiness') }}</strong>
21035
+ <p>{{ tx('premiumReadiness.subtitle', 'Qualidade visual e operacional antes de publicar.') }}</p>
21036
+ </div>
21037
+ </header>
21038
+ <ul class="builder-premium-readiness__list">
21039
+ @for (issue of premiumReadinessIssues(); track issue.id) {
21040
+ <li
21041
+ class="builder-premium-readiness__item"
21042
+ [attr.data-severity]="issue.severity"
21043
+ [attr.data-testid]="'page-builder-premium-readiness-' + issue.id"
21044
+ >
21045
+ <span class="builder-premium-readiness__severity" aria-hidden="true"></span>
21046
+ <div>
21047
+ <strong>{{ issue.title }}</strong>
21048
+ <p>{{ issue.description }}</p>
21049
+ @if (issue.action) {
21050
+ <button
21051
+ type="button"
21052
+ class="builder-premium-readiness__action"
21053
+ [attr.data-testid]="'page-builder-premium-readiness-action-' + issue.id"
21054
+ (click)="runPremiumReadinessAction(issue)"
21055
+ >
21056
+ {{ issue.action.label }}
21057
+ </button>
21058
+ }
21059
+ </div>
21060
+ </li>
21061
+ }
21062
+ </ul>
21063
+ </section>
21064
+ }
21065
+
20315
21066
  <praxis-dynamic-page
20316
21067
  #runtime
20317
21068
  [page]="currentPage()"
@@ -20378,7 +21129,7 @@ class DynamicPageBuilderComponent {
20378
21129
  (close)="minimizeAgenticAuthoring()"
20379
21130
  />
20380
21131
  }
20381
-
21132
+
20382
21133
  @if (agenticAuthoringIncludeLlmDiagnostics && agenticAuthoringLlmDiagnosticsText()) {
20383
21134
  <section
20384
21135
  class="agentic-diagnostics-panel"
@@ -20409,7 +21160,7 @@ class DynamicPageBuilderComponent {
20409
21160
  </header>
20410
21161
  @if (!agenticAuthoringLlmDiagnosticsCollapsed()) {
20411
21162
  <p class="agentic-diagnostics-panel__description">
20412
- {{ tx('agentic.diagnostics.description', 'Prompt, context bundle, and tool catalog returned by the backend for this turn.') }}
21163
+ {{ tx('agentic.diagnostics.description', 'Informações usadas para explicar como o assistente chegou à resposta deste pedido.') }}
20413
21164
  </p>
20414
21165
  <pre>{{ agenticAuthoringLlmDiagnosticsText() }}</pre>
20415
21166
  }
@@ -20422,11 +21173,11 @@ class DynamicPageBuilderComponent {
20422
21173
  [class.shared-rule-cockpit--collapsed]="sharedRuleCockpitCollapsed()"
20423
21174
  data-testid="page-builder-shared-rule-cockpit"
20424
21175
  role="region"
20425
- [attr.aria-label]="tx('agentic.sharedRuleCockpit.title', 'Shared-rule governed actions')"
21176
+ [attr.aria-label]="tx('agentic.sharedRuleCockpit.title', 'Revisão governada da regra')"
20426
21177
  >
20427
21178
  <header class="shared-rule-cockpit__header">
20428
21179
  <div>
20429
- <strong>{{ tx('agentic.sharedRuleCockpit.title', 'Shared-rule governed actions') }}</strong>
21180
+ <strong>{{ tx('agentic.sharedRuleCockpit.title', 'Revisão governada da regra') }}</strong>
20430
21181
  <span>{{ handoff.ruleKey || handoff.recommendedRuleType || handoff.flowId }}</span>
20431
21182
  </div>
20432
21183
  <div class="shared-rule-cockpit__header-actions">
@@ -20446,7 +21197,7 @@ class DynamicPageBuilderComponent {
20446
21197
  </header>
20447
21198
  @if (!sharedRuleCockpitCollapsed()) {
20448
21199
  <p class="shared-rule-cockpit__description">
20449
- {{ tx('agentic.sharedRuleCockpit.description', 'Continue the semantic decision in the governed domain-rules lifecycle. The cockpit calls canonical backend actions and only displays derived materializations.') }}
21200
+ {{ tx('agentic.sharedRuleCockpit.description', 'Continue a revisão da regra de negócio antes de criar ou salvar alterações na tela.') }}
20450
21201
  </p>
20451
21202
  <div class="shared-rule-cockpit__actions">
20452
21203
  @for (action of sharedRuleGovernedContinuationActions(); track trackGovernedContinuationAction($index, action)) {
@@ -20662,17 +21413,23 @@ class DynamicPageBuilderComponent {
20662
21413
  }
20663
21414
 
20664
21415
  <praxis-floating-toolbar
20665
- [visible]="showSettings()"
21416
+ [visible]="!!enableCustomization"
20666
21417
  [canUndo]="false"
20667
21418
  [canRedo]="false"
20668
21419
  [showSave]="canSaveCurrentPage()"
20669
21420
  [showPreview]="hasPageWidgets()"
21421
+ [editingEnabled]="showSettings()"
21422
+ [previewActive]="isPreviewMode()"
21423
+ [connectionMode]="showSettings() && connectionsViewerOpen()"
21424
+ [modeLabel]="builderModeLabel()"
21425
+ [previewLabel]="tx('toolbar.preview', 'Pré-visualizar')"
21426
+ [exitPreviewLabel]="tx('toolbar.exitPreview', 'Voltar para edição')"
20670
21427
  (add)="onAddComponent()"
20671
21428
  (settings)="openPageSettings()"
20672
21429
  (save)="saveCurrentPage()"
20673
21430
  (preview)="togglePreview()"
20674
21431
  >
20675
- @if (showPageLifecycleActions && hasPageWidgets()) {
21432
+ @if (showSettings() && showPageLifecycleActions && hasPageWidgets()) {
20676
21433
  <button
20677
21434
  pdx-toolbar-extra
20678
21435
  mat-mini-fab
@@ -20686,7 +21443,7 @@ class DynamicPageBuilderComponent {
20686
21443
  <mat-icon [praxisIcon]="'restart_alt'"></mat-icon>
20687
21444
  </button>
20688
21445
  }
20689
- @if (showPageLifecycleActions && canDeleteSavedPage) {
21446
+ @if (showSettings() && showPageLifecycleActions && canDeleteSavedPage) {
20690
21447
  <button
20691
21448
  pdx-toolbar-extra
20692
21449
  mat-mini-fab
@@ -20701,7 +21458,7 @@ class DynamicPageBuilderComponent {
20701
21458
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
20702
21459
  </button>
20703
21460
  }
20704
- @if (enableAgenticAuthoring) {
21461
+ @if (showSettings() && enableAgenticAuthoring) {
20705
21462
  <button
20706
21463
  pdx-toolbar-extra
20707
21464
  mat-mini-fab
@@ -20717,14 +21474,17 @@ class DynamicPageBuilderComponent {
20717
21474
  <mat-icon [praxisIcon]="'auto_awesome'"></mat-icon>
20718
21475
  </button>
20719
21476
  }
20720
- @if (hasPageWidgets()) {
21477
+ @if (showSettings() && hasPageWidgets()) {
20721
21478
  <button
20722
21479
  pdx-toolbar-extra
20723
21480
  mat-mini-fab
20724
21481
  type="button"
21482
+ class="builder-shell__connections-toggle"
21483
+ [class.builder-shell__connections-toggle--open]="connectionsViewerOpen()"
20725
21484
  [attr.data-testid]="'page-builder-connections-toggle'"
20726
- [matTooltip]="tx('connections.toggle', 'Edit connections')"
20727
- [attr.aria-label]="tx('connections.toggleAria', 'Edit connections')"
21485
+ [matTooltip]="connectionsToggleLabel()"
21486
+ [attr.aria-label]="connectionsToggleLabel()"
21487
+ [disabled]="!showSettings()"
20728
21488
  (click)="toggleConnectionsViewer()"
20729
21489
  >
20730
21490
  <mat-icon [praxisIcon]="'hub'"></mat-icon>
@@ -20732,7 +21492,7 @@ class DynamicPageBuilderComponent {
20732
21492
  }
20733
21493
  </praxis-floating-toolbar>
20734
21494
  </div>
20735
- `, isInline: true, styles: [":host{display:block;position:relative;min-height:var(--pdx-page-builder-min-height, 420px)}.builder-shell{display:block;position:relative;min-height:inherit;height:100%}.builder-shell:has(.pdx-shell.fullscreen) praxis-floating-toolbar{display:none}.agentic-diagnostics-panel{position:absolute;z-index:21;right:16px;width:min(520px,calc(100% - 32px));max-height:min(440px,calc(100% - 32px));overflow:auto;padding:12px;border:1px solid rgba(107,114,128,.28);border-radius:8px;background:#fffffff5;color:#111827;box-shadow:0 14px 36px #0000003d}.agentic-diagnostics-panel--collapsed{width:min(280px,calc(100% - 32px));max-height:58px;overflow:hidden;padding:10px 12px;pointer-events:auto}.agentic-diagnostics-panel__header{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:13px;font-weight:700}.agentic-diagnostics-panel__header-actions{display:flex;align-items:center;gap:8px}.agentic-diagnostics-panel__badge{padding:2px 6px;border:1px solid rgba(107,114,128,.28);border-radius:8px;font-size:11px;font-weight:600;color:#4b5563}.agentic-diagnostics-panel__toggle,.shared-rule-cockpit__toggle{appearance:none;border:1px solid rgba(30,64,175,.18);border-radius:999px;background:#ffffffd6;color:#1e3a8a;cursor:pointer;font-size:11px;font-weight:700;line-height:1;padding:6px 9px;white-space:nowrap}.agentic-diagnostics-panel__description{margin:8px 0 10px;color:#4b5563;font-size:12px;line-height:1.4}.agentic-diagnostics-panel pre{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px;line-height:1.45;color:#1f2937}praxis-ai-assistant-shell{position:relative;z-index:140}@media(min-width:1100px){.builder-shell--agentic-review-rail{box-sizing:border-box;padding-right:464px}}.builder-shell__agentic-toggle{position:relative}.builder-shell__agentic-toggle--open,.builder-shell__agentic-toggle--minimized{outline:2px solid rgba(96,165,250,.52);outline-offset:2px}.builder-shell__agentic-toggle--minimized:after{content:\"\";position:absolute;top:6px;right:6px;width:8px;height:8px;border:2px solid var(--md-sys-color-surface, #111827);border-radius:999px;background:#34d399}.shared-rule-cockpit{position:absolute;z-index:120;left:16px;bottom:88px;width:min(720px,calc(100% - 32px));max-height:min(560px,calc(100vh - 140px));padding:14px;border:1px solid rgba(30,64,175,.22);border-radius:12px;background:linear-gradient(135deg,#eff6fffa,#fffbebf5);color:#172554;box-shadow:0 18px 46px #0f172a38;overflow:auto;overscroll-behavior:contain}.shared-rule-cockpit--collapsed{width:min(360px,calc(100% - 32px));max-height:72px;overflow:hidden;padding:10px 12px}.shared-rule-cockpit__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.shared-rule-cockpit__header-actions{display:flex;align-items:center;gap:8px}.shared-rule-cockpit__header div{display:grid;gap:2px}.shared-rule-cockpit__header strong{font-size:14px;line-height:1.2}.shared-rule-cockpit__header span{color:#475569;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__badge{flex:0 0 auto;max-width:220px;padding:3px 8px;border:1px solid rgba(30,64,175,.2);border-radius:999px;background:#ffffffbd;color:#1e3a8a;font-size:11px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shared-rule-cockpit__description,.shared-rule-cockpit__status,.shared-rule-cockpit__error{margin:10px 0 0;color:#334155;font-size:12px;line-height:1.45}.shared-rule-cockpit__error{color:#991b1b;font-weight:600}.shared-rule-cockpit__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.shared-rule-cockpit__facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:12px 0 0}.shared-rule-cockpit__facts div{min-width:0;padding:8px;border-radius:10px;background:#ffffffb8}.shared-rule-cockpit__facts dt{color:#64748b;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.shared-rule-cockpit__facts dd{margin:4px 0 0;color:#0f172a;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__enforcement-matrix{display:grid;gap:10px;margin-top:12px;padding:10px;border:1px solid rgba(30,64,175,.14);border-radius:12px;background:#ffffff94}.shared-rule-cockpit__matrix-header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.shared-rule-cockpit__matrix-header div{display:grid;gap:2px}.shared-rule-cockpit__matrix-header strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__matrix-header span,.shared-rule-cockpit__matrix-source{color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-badge{flex:0 0 auto;padding:3px 8px;border-radius:999px;background:#16a34a1f;color:#166534;font-weight:800;white-space:nowrap}.shared-rule-cockpit__projection-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.shared-rule-cockpit__projection{display:grid;gap:3px;min-width:0;padding:9px;border:1px solid rgba(15,23,42,.08);border-radius:11px;background:#f8fafcd1}.shared-rule-cockpit__projection[data-status=ready]{border-color:#16a34a33;background:#f0fdf4d1}.shared-rule-cockpit__projection span{color:#1d4ed8;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;overflow-wrap:anywhere}.shared-rule-cockpit__projection strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__projection small,.shared-rule-cockpit__projection em{color:#475569;font-size:11px;font-style:normal;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-source{margin:0}.shared-rule-cockpit__timeline{display:grid;gap:8px;max-height:190px;margin:12px 0 0;padding:0;overflow:auto;list-style:none}.shared-rule-cockpit__timeline-item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;border:1px solid rgba(30,64,175,.12);border-radius:12px;background:#ffffffc2}.shared-rule-cockpit__timeline-icon{display:grid;width:24px;height:24px;place-items:center;border-radius:999px;background:#1e40af1a;color:#1e3a8a;font-family:Material Icons;font-size:16px;line-height:1}.shared-rule-cockpit__timeline-item strong{color:#0f172a;font-size:12px;line-height:1.35}.shared-rule-cockpit__timeline-item p,.shared-rule-cockpit__timeline-item small,.shared-rule-cockpit__timeline-item time,.shared-rule-cockpit__timeline-empty{display:block;margin:3px 0 0;color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__timeline-badge{display:inline-flex;margin-left:6px;padding:2px 6px;border-radius:999px;background:#0ea5e91f;color:#075985;font-size:10px;font-weight:700}.shared-rule-cockpit__timeline-empty{padding:10px;border-radius:12px;background:#ffffffa3}@media(max-width:720px){.shared-rule-cockpit{bottom:72px;max-height:calc(100vh - 112px)}.shared-rule-cockpit__facts,.shared-rule-cockpit__projection-grid{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: DynamicWidgetPageComponent, selector: "praxis-dynamic-page", inputs: ["page", "context", "strictValidation", "enableCustomization", "showPageSettingsButton", "shellEditorComponent", "pageEditorComponent", "autoPersist", "pageIdentity", "componentInstanceId", "showWidgetAssistantButton"], outputs: ["pageChange", "widgetEvent", "widgetSelectionChange", "widgetAssistantRequested", "widgetDiagnosticsChange"] }, { kind: "component", type: FloatingToolbarComponent, selector: "praxis-floating-toolbar", inputs: ["visible", "canUndo", "canRedo", "showSave", "showPreview"], outputs: ["add", "undo", "redo", "settings", "preview", "save"] }, { kind: "component", type: ConnectionEditorComponent, selector: "praxis-connection-editor", inputs: ["open", "page"], outputs: ["pageChange", "focusWidget", "openPageSettings", "close"] }, { kind: "component", type: PraxisAiAssistantShellComponent, selector: "praxis-ai-assistant-shell", inputs: ["labels", "mode", "state", "contextItems", "attachments", "messages", "quickReplies", "recommendedIntents", "prompt", "statusText", "errorText", "testIdPrefix", "panelTestId", "submitTestId", "applyTestId", "primaryAction", "secondaryActions", "governanceActions", "busy", "canSubmit", "canApply", "submitOnEnter", "showAttachAction", "enablePastedAttachments", "enableFileAttachments", "attachmentAccept", "attachmentMultiple", "voiceInputMode", "voiceLanguage", "draggable", "resizable", "minWidth", "minHeight", "margin", "layout"], outputs: ["promptChange", "submitPrompt", "apply", "retryTurn", "cancelTurn", "shellAction", "close", "attach", "attachmentsPasted", "attachmentsSelected", "removeAttachment", "messageAction", "editMessage", "resendMessage", "quickReply", "recommendedIntent", "layoutChange"] }] });
21495
+ `, isInline: true, styles: [":host{display:block;position:relative;min-height:var(--pdx-page-builder-min-height, 420px)}.builder-shell{display:block;position:relative;min-height:inherit;height:100%}.builder-shell:has(.pdx-shell.fullscreen) praxis-floating-toolbar{display:none}.builder-premium-readiness{display:grid;grid-template-columns:minmax(220px,.72fr) minmax(0,1.28fr);gap:12px;width:100%;margin:0 0 14px;padding:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #cac4d0) 72%,transparent);border-radius:12px;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 10%,transparent),transparent 36%),color-mix(in srgb,var(--md-sys-color-surface-container-lowest, #fff) 96%,transparent);color:var(--md-sys-color-on-surface, #1d1b20);box-shadow:inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface, #1d1b20) 5%,transparent)}.builder-premium-readiness__header{display:flex;align-items:flex-start;gap:10px;min-width:0}.builder-premium-readiness__header strong{display:block;font-size:13px;line-height:1.25}.builder-premium-readiness__header p,.builder-premium-readiness__item p{margin:2px 0 0;color:var(--md-sys-color-on-surface-variant, #49454f);font-size:11px;line-height:1.35}.builder-premium-readiness__icon{color:var(--md-sys-color-primary, #6750a4);font-size:20px;line-height:1}.builder-premium-readiness__list{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:8px;margin:0;padding:0;list-style:none}.builder-premium-readiness__item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px;min-width:0;padding:9px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #cac4d0) 64%,transparent);border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low, #f7f2fa) 84%,transparent)}.builder-premium-readiness__item strong{display:block;font-size:12px;line-height:1.25}.builder-premium-readiness__action{appearance:none;display:inline-flex;align-items:center;justify-content:center;min-height:26px;margin-top:7px;padding:4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 34%,transparent);border-radius:7px;background:color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 9%,var(--md-sys-color-surface, #fff));color:var(--md-sys-color-primary, #6750a4);cursor:pointer;font:inherit;font-size:11px;font-weight:700;line-height:1.2;text-align:left}.builder-premium-readiness__severity{width:8px;height:8px;margin-top:4px;border-radius:999px;background:var(--md-sys-color-primary, #6750a4)}.builder-premium-readiness__item[data-severity=warning] .builder-premium-readiness__severity{background:var(--praxis-warning, #b26a00)}.builder-premium-readiness__item[data-severity=error] .builder-premium-readiness__severity{background:var(--md-sys-color-error, #b3261e)}@media(max-width:760px){.builder-premium-readiness{grid-template-columns:1fr}}.agentic-diagnostics-panel{position:absolute;z-index:21;right:16px;width:min(520px,calc(100% - 32px));max-height:min(440px,calc(100% - 32px));overflow:auto;padding:12px;border:1px solid rgba(107,114,128,.28);border-radius:8px;background:#fffffff5;color:#111827;box-shadow:0 14px 36px #0000003d}.agentic-diagnostics-panel--collapsed{width:min(280px,calc(100% - 32px));max-height:58px;overflow:hidden;padding:10px 12px;pointer-events:auto}.agentic-diagnostics-panel__header{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:13px;font-weight:700}.agentic-diagnostics-panel__header-actions{display:flex;align-items:center;gap:8px}.agentic-diagnostics-panel__badge{padding:2px 6px;border:1px solid rgba(107,114,128,.28);border-radius:8px;font-size:11px;font-weight:600;color:#4b5563}.agentic-diagnostics-panel__toggle,.shared-rule-cockpit__toggle{appearance:none;border:1px solid rgba(30,64,175,.18);border-radius:999px;background:#ffffffd6;color:#1e3a8a;cursor:pointer;font-size:11px;font-weight:700;line-height:1;padding:6px 9px;white-space:nowrap}.agentic-diagnostics-panel__description{margin:8px 0 10px;color:#4b5563;font-size:12px;line-height:1.4}.agentic-diagnostics-panel pre{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px;line-height:1.45;color:#1f2937}praxis-ai-assistant-shell{position:fixed;inset:0;z-index:140;pointer-events:none}@media(min-width:1100px){.builder-shell--agentic-review-rail{box-sizing:border-box;padding-right:464px}}.builder-shell__agentic-toggle{position:relative}.builder-shell__agentic-toggle--open,.builder-shell__agentic-toggle--minimized{outline:2px solid rgba(96,165,250,.52);outline-offset:2px}.builder-shell__agentic-toggle--minimized:after{content:\"\";position:absolute;top:6px;right:6px;width:8px;height:8px;border:2px solid var(--md-sys-color-surface, #111827);border-radius:999px;background:#34d399}.builder-shell__connections-toggle--open{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 52%,transparent);outline-offset:2px}.shared-rule-cockpit{position:absolute;z-index:120;left:16px;bottom:88px;width:min(720px,calc(100% - 32px));max-height:min(560px,calc(100vh - 140px));padding:14px;border:1px solid rgba(30,64,175,.22);border-radius:12px;background:linear-gradient(135deg,#eff6fffa,#fffbebf5);color:#172554;box-shadow:0 18px 46px #0f172a38;overflow:auto;overscroll-behavior:contain}.shared-rule-cockpit--collapsed{width:min(360px,calc(100% - 32px));max-height:72px;overflow:hidden;padding:10px 12px}.shared-rule-cockpit__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.shared-rule-cockpit__header-actions{display:flex;align-items:center;gap:8px}.shared-rule-cockpit__header div{display:grid;gap:2px}.shared-rule-cockpit__header strong{font-size:14px;line-height:1.2}.shared-rule-cockpit__header span{color:#475569;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__badge{flex:0 0 auto;max-width:220px;padding:3px 8px;border:1px solid rgba(30,64,175,.2);border-radius:999px;background:#ffffffbd;color:#1e3a8a;font-size:11px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shared-rule-cockpit__description,.shared-rule-cockpit__status,.shared-rule-cockpit__error{margin:10px 0 0;color:#334155;font-size:12px;line-height:1.45}.shared-rule-cockpit__error{color:#991b1b;font-weight:600}.shared-rule-cockpit__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.shared-rule-cockpit__facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:12px 0 0}.shared-rule-cockpit__facts div{min-width:0;padding:8px;border-radius:10px;background:#ffffffb8}.shared-rule-cockpit__facts dt{color:#64748b;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.shared-rule-cockpit__facts dd{margin:4px 0 0;color:#0f172a;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__enforcement-matrix{display:grid;gap:10px;margin-top:12px;padding:10px;border:1px solid rgba(30,64,175,.14);border-radius:12px;background:#ffffff94}.shared-rule-cockpit__matrix-header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.shared-rule-cockpit__matrix-header div{display:grid;gap:2px}.shared-rule-cockpit__matrix-header strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__matrix-header span,.shared-rule-cockpit__matrix-source{color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-badge{flex:0 0 auto;padding:3px 8px;border-radius:999px;background:#16a34a1f;color:#166534;font-weight:800;white-space:nowrap}.shared-rule-cockpit__projection-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.shared-rule-cockpit__projection{display:grid;gap:3px;min-width:0;padding:9px;border:1px solid rgba(15,23,42,.08);border-radius:11px;background:#f8fafcd1}.shared-rule-cockpit__projection[data-status=ready]{border-color:#16a34a33;background:#f0fdf4d1}.shared-rule-cockpit__projection span{color:#1d4ed8;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;overflow-wrap:anywhere}.shared-rule-cockpit__projection strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__projection small,.shared-rule-cockpit__projection em{color:#475569;font-size:11px;font-style:normal;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-source{margin:0}.shared-rule-cockpit__timeline{display:grid;gap:8px;max-height:190px;margin:12px 0 0;padding:0;overflow:auto;list-style:none}.shared-rule-cockpit__timeline-item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;border:1px solid rgba(30,64,175,.12);border-radius:12px;background:#ffffffc2}.shared-rule-cockpit__timeline-icon{display:grid;width:24px;height:24px;place-items:center;border-radius:999px;background:#1e40af1a;color:#1e3a8a;font-family:Material Icons;font-size:16px;line-height:1}.shared-rule-cockpit__timeline-item strong{color:#0f172a;font-size:12px;line-height:1.35}.shared-rule-cockpit__timeline-item p,.shared-rule-cockpit__timeline-item small,.shared-rule-cockpit__timeline-item time,.shared-rule-cockpit__timeline-empty{display:block;margin:3px 0 0;color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__timeline-badge{display:inline-flex;margin-left:6px;padding:2px 6px;border-radius:999px;background:#0ea5e91f;color:#075985;font-size:10px;font-weight:700}.shared-rule-cockpit__timeline-empty{padding:10px;border-radius:12px;background:#ffffffa3}@media(max-width:720px){.shared-rule-cockpit{bottom:72px;max-height:calc(100vh - 112px)}.shared-rule-cockpit__facts,.shared-rule-cockpit__projection-grid{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: DynamicWidgetPageComponent, selector: "praxis-dynamic-page", inputs: ["page", "context", "strictValidation", "enableCustomization", "showPageSettingsButton", "shellEditorComponent", "pageEditorComponent", "autoPersist", "pageIdentity", "componentInstanceId", "showWidgetAssistantButton"], outputs: ["pageChange", "widgetEvent", "widgetSelectionChange", "widgetAssistantRequested", "widgetDiagnosticsChange"] }, { kind: "component", type: FloatingToolbarComponent, selector: "praxis-floating-toolbar", inputs: ["visible", "canUndo", "canRedo", "showSave", "showPreview", "editingEnabled", "previewActive", "connectionMode", "modeLabel", "previewLabel", "exitPreviewLabel"], outputs: ["add", "undo", "redo", "settings", "preview", "save"] }, { kind: "component", type: ConnectionEditorComponent, selector: "praxis-connection-editor", inputs: ["open", "page"], outputs: ["pageChange", "focusWidget", "openPageSettings", "close"] }, { kind: "component", type: PraxisAiAssistantShellComponent, selector: "praxis-ai-assistant-shell", inputs: ["labels", "mode", "state", "contextItems", "attachments", "messages", "quickReplies", "recommendedIntents", "prompt", "statusText", "errorText", "testIdPrefix", "panelTestId", "submitTestId", "applyTestId", "primaryAction", "secondaryActions", "governanceActions", "busy", "canSubmit", "canApply", "submitOnEnter", "showAttachAction", "enablePastedAttachments", "enableFileAttachments", "attachmentAccept", "attachmentMultiple", "voiceInputMode", "voiceLanguage", "draggable", "resizable", "minWidth", "minHeight", "margin", "layout"], outputs: ["promptChange", "submitPrompt", "apply", "retryTurn", "cancelTurn", "shellAction", "close", "attach", "attachmentsPasted", "attachmentsSelected", "removeAttachment", "messageAction", "editMessage", "resendMessage", "quickReply", "recommendedIntent", "layoutChange"] }] });
20736
21496
  }
20737
21497
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicPageBuilderComponent, decorators: [{
20738
21498
  type: Component,
@@ -20753,6 +21513,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
20753
21513
  class="builder-shell"
20754
21514
  [class.builder-shell--agentic-review-rail]="agenticAuthoringReviewRailActive()"
20755
21515
  >
21516
+ @if (showSettings() && !connectionsViewerOpen() && premiumReadinessIssues().length) {
21517
+ <section
21518
+ class="builder-premium-readiness"
21519
+ data-testid="page-builder-premium-readiness"
21520
+ [attr.aria-label]="tx('premiumReadiness.title', 'Premium readiness')"
21521
+ >
21522
+ <header class="builder-premium-readiness__header">
21523
+ <span class="builder-premium-readiness__icon material-symbols-outlined" aria-hidden="true">auto_awesome</span>
21524
+ <div>
21525
+ <strong>{{ tx('premiumReadiness.title', 'Premium readiness') }}</strong>
21526
+ <p>{{ tx('premiumReadiness.subtitle', 'Qualidade visual e operacional antes de publicar.') }}</p>
21527
+ </div>
21528
+ </header>
21529
+ <ul class="builder-premium-readiness__list">
21530
+ @for (issue of premiumReadinessIssues(); track issue.id) {
21531
+ <li
21532
+ class="builder-premium-readiness__item"
21533
+ [attr.data-severity]="issue.severity"
21534
+ [attr.data-testid]="'page-builder-premium-readiness-' + issue.id"
21535
+ >
21536
+ <span class="builder-premium-readiness__severity" aria-hidden="true"></span>
21537
+ <div>
21538
+ <strong>{{ issue.title }}</strong>
21539
+ <p>{{ issue.description }}</p>
21540
+ @if (issue.action) {
21541
+ <button
21542
+ type="button"
21543
+ class="builder-premium-readiness__action"
21544
+ [attr.data-testid]="'page-builder-premium-readiness-action-' + issue.id"
21545
+ (click)="runPremiumReadinessAction(issue)"
21546
+ >
21547
+ {{ issue.action.label }}
21548
+ </button>
21549
+ }
21550
+ </div>
21551
+ </li>
21552
+ }
21553
+ </ul>
21554
+ </section>
21555
+ }
21556
+
20756
21557
  <praxis-dynamic-page
20757
21558
  #runtime
20758
21559
  [page]="currentPage()"
@@ -20819,7 +21620,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
20819
21620
  (close)="minimizeAgenticAuthoring()"
20820
21621
  />
20821
21622
  }
20822
-
21623
+
20823
21624
  @if (agenticAuthoringIncludeLlmDiagnostics && agenticAuthoringLlmDiagnosticsText()) {
20824
21625
  <section
20825
21626
  class="agentic-diagnostics-panel"
@@ -20850,7 +21651,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
20850
21651
  </header>
20851
21652
  @if (!agenticAuthoringLlmDiagnosticsCollapsed()) {
20852
21653
  <p class="agentic-diagnostics-panel__description">
20853
- {{ tx('agentic.diagnostics.description', 'Prompt, context bundle, and tool catalog returned by the backend for this turn.') }}
21654
+ {{ tx('agentic.diagnostics.description', 'Informações usadas para explicar como o assistente chegou à resposta deste pedido.') }}
20854
21655
  </p>
20855
21656
  <pre>{{ agenticAuthoringLlmDiagnosticsText() }}</pre>
20856
21657
  }
@@ -20863,11 +21664,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
20863
21664
  [class.shared-rule-cockpit--collapsed]="sharedRuleCockpitCollapsed()"
20864
21665
  data-testid="page-builder-shared-rule-cockpit"
20865
21666
  role="region"
20866
- [attr.aria-label]="tx('agentic.sharedRuleCockpit.title', 'Shared-rule governed actions')"
21667
+ [attr.aria-label]="tx('agentic.sharedRuleCockpit.title', 'Revisão governada da regra')"
20867
21668
  >
20868
21669
  <header class="shared-rule-cockpit__header">
20869
21670
  <div>
20870
- <strong>{{ tx('agentic.sharedRuleCockpit.title', 'Shared-rule governed actions') }}</strong>
21671
+ <strong>{{ tx('agentic.sharedRuleCockpit.title', 'Revisão governada da regra') }}</strong>
20871
21672
  <span>{{ handoff.ruleKey || handoff.recommendedRuleType || handoff.flowId }}</span>
20872
21673
  </div>
20873
21674
  <div class="shared-rule-cockpit__header-actions">
@@ -20887,7 +21688,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
20887
21688
  </header>
20888
21689
  @if (!sharedRuleCockpitCollapsed()) {
20889
21690
  <p class="shared-rule-cockpit__description">
20890
- {{ tx('agentic.sharedRuleCockpit.description', 'Continue the semantic decision in the governed domain-rules lifecycle. The cockpit calls canonical backend actions and only displays derived materializations.') }}
21691
+ {{ tx('agentic.sharedRuleCockpit.description', 'Continue a revisão da regra de negócio antes de criar ou salvar alterações na tela.') }}
20891
21692
  </p>
20892
21693
  <div class="shared-rule-cockpit__actions">
20893
21694
  @for (action of sharedRuleGovernedContinuationActions(); track trackGovernedContinuationAction($index, action)) {
@@ -21103,17 +21904,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21103
21904
  }
21104
21905
 
21105
21906
  <praxis-floating-toolbar
21106
- [visible]="showSettings()"
21907
+ [visible]="!!enableCustomization"
21107
21908
  [canUndo]="false"
21108
21909
  [canRedo]="false"
21109
21910
  [showSave]="canSaveCurrentPage()"
21110
21911
  [showPreview]="hasPageWidgets()"
21912
+ [editingEnabled]="showSettings()"
21913
+ [previewActive]="isPreviewMode()"
21914
+ [connectionMode]="showSettings() && connectionsViewerOpen()"
21915
+ [modeLabel]="builderModeLabel()"
21916
+ [previewLabel]="tx('toolbar.preview', 'Pré-visualizar')"
21917
+ [exitPreviewLabel]="tx('toolbar.exitPreview', 'Voltar para edição')"
21111
21918
  (add)="onAddComponent()"
21112
21919
  (settings)="openPageSettings()"
21113
21920
  (save)="saveCurrentPage()"
21114
21921
  (preview)="togglePreview()"
21115
21922
  >
21116
- @if (showPageLifecycleActions && hasPageWidgets()) {
21923
+ @if (showSettings() && showPageLifecycleActions && hasPageWidgets()) {
21117
21924
  <button
21118
21925
  pdx-toolbar-extra
21119
21926
  mat-mini-fab
@@ -21127,7 +21934,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21127
21934
  <mat-icon [praxisIcon]="'restart_alt'"></mat-icon>
21128
21935
  </button>
21129
21936
  }
21130
- @if (showPageLifecycleActions && canDeleteSavedPage) {
21937
+ @if (showSettings() && showPageLifecycleActions && canDeleteSavedPage) {
21131
21938
  <button
21132
21939
  pdx-toolbar-extra
21133
21940
  mat-mini-fab
@@ -21142,7 +21949,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21142
21949
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
21143
21950
  </button>
21144
21951
  }
21145
- @if (enableAgenticAuthoring) {
21952
+ @if (showSettings() && enableAgenticAuthoring) {
21146
21953
  <button
21147
21954
  pdx-toolbar-extra
21148
21955
  mat-mini-fab
@@ -21158,14 +21965,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21158
21965
  <mat-icon [praxisIcon]="'auto_awesome'"></mat-icon>
21159
21966
  </button>
21160
21967
  }
21161
- @if (hasPageWidgets()) {
21968
+ @if (showSettings() && hasPageWidgets()) {
21162
21969
  <button
21163
21970
  pdx-toolbar-extra
21164
21971
  mat-mini-fab
21165
21972
  type="button"
21973
+ class="builder-shell__connections-toggle"
21974
+ [class.builder-shell__connections-toggle--open]="connectionsViewerOpen()"
21166
21975
  [attr.data-testid]="'page-builder-connections-toggle'"
21167
- [matTooltip]="tx('connections.toggle', 'Edit connections')"
21168
- [attr.aria-label]="tx('connections.toggleAria', 'Edit connections')"
21976
+ [matTooltip]="connectionsToggleLabel()"
21977
+ [attr.aria-label]="connectionsToggleLabel()"
21978
+ [disabled]="!showSettings()"
21169
21979
  (click)="toggleConnectionsViewer()"
21170
21980
  >
21171
21981
  <mat-icon [praxisIcon]="'hub'"></mat-icon>
@@ -21173,7 +21983,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21173
21983
  }
21174
21984
  </praxis-floating-toolbar>
21175
21985
  </div>
21176
- `, styles: [":host{display:block;position:relative;min-height:var(--pdx-page-builder-min-height, 420px)}.builder-shell{display:block;position:relative;min-height:inherit;height:100%}.builder-shell:has(.pdx-shell.fullscreen) praxis-floating-toolbar{display:none}.agentic-diagnostics-panel{position:absolute;z-index:21;right:16px;width:min(520px,calc(100% - 32px));max-height:min(440px,calc(100% - 32px));overflow:auto;padding:12px;border:1px solid rgba(107,114,128,.28);border-radius:8px;background:#fffffff5;color:#111827;box-shadow:0 14px 36px #0000003d}.agentic-diagnostics-panel--collapsed{width:min(280px,calc(100% - 32px));max-height:58px;overflow:hidden;padding:10px 12px;pointer-events:auto}.agentic-diagnostics-panel__header{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:13px;font-weight:700}.agentic-diagnostics-panel__header-actions{display:flex;align-items:center;gap:8px}.agentic-diagnostics-panel__badge{padding:2px 6px;border:1px solid rgba(107,114,128,.28);border-radius:8px;font-size:11px;font-weight:600;color:#4b5563}.agentic-diagnostics-panel__toggle,.shared-rule-cockpit__toggle{appearance:none;border:1px solid rgba(30,64,175,.18);border-radius:999px;background:#ffffffd6;color:#1e3a8a;cursor:pointer;font-size:11px;font-weight:700;line-height:1;padding:6px 9px;white-space:nowrap}.agentic-diagnostics-panel__description{margin:8px 0 10px;color:#4b5563;font-size:12px;line-height:1.4}.agentic-diagnostics-panel pre{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px;line-height:1.45;color:#1f2937}praxis-ai-assistant-shell{position:relative;z-index:140}@media(min-width:1100px){.builder-shell--agentic-review-rail{box-sizing:border-box;padding-right:464px}}.builder-shell__agentic-toggle{position:relative}.builder-shell__agentic-toggle--open,.builder-shell__agentic-toggle--minimized{outline:2px solid rgba(96,165,250,.52);outline-offset:2px}.builder-shell__agentic-toggle--minimized:after{content:\"\";position:absolute;top:6px;right:6px;width:8px;height:8px;border:2px solid var(--md-sys-color-surface, #111827);border-radius:999px;background:#34d399}.shared-rule-cockpit{position:absolute;z-index:120;left:16px;bottom:88px;width:min(720px,calc(100% - 32px));max-height:min(560px,calc(100vh - 140px));padding:14px;border:1px solid rgba(30,64,175,.22);border-radius:12px;background:linear-gradient(135deg,#eff6fffa,#fffbebf5);color:#172554;box-shadow:0 18px 46px #0f172a38;overflow:auto;overscroll-behavior:contain}.shared-rule-cockpit--collapsed{width:min(360px,calc(100% - 32px));max-height:72px;overflow:hidden;padding:10px 12px}.shared-rule-cockpit__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.shared-rule-cockpit__header-actions{display:flex;align-items:center;gap:8px}.shared-rule-cockpit__header div{display:grid;gap:2px}.shared-rule-cockpit__header strong{font-size:14px;line-height:1.2}.shared-rule-cockpit__header span{color:#475569;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__badge{flex:0 0 auto;max-width:220px;padding:3px 8px;border:1px solid rgba(30,64,175,.2);border-radius:999px;background:#ffffffbd;color:#1e3a8a;font-size:11px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shared-rule-cockpit__description,.shared-rule-cockpit__status,.shared-rule-cockpit__error{margin:10px 0 0;color:#334155;font-size:12px;line-height:1.45}.shared-rule-cockpit__error{color:#991b1b;font-weight:600}.shared-rule-cockpit__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.shared-rule-cockpit__facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:12px 0 0}.shared-rule-cockpit__facts div{min-width:0;padding:8px;border-radius:10px;background:#ffffffb8}.shared-rule-cockpit__facts dt{color:#64748b;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.shared-rule-cockpit__facts dd{margin:4px 0 0;color:#0f172a;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__enforcement-matrix{display:grid;gap:10px;margin-top:12px;padding:10px;border:1px solid rgba(30,64,175,.14);border-radius:12px;background:#ffffff94}.shared-rule-cockpit__matrix-header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.shared-rule-cockpit__matrix-header div{display:grid;gap:2px}.shared-rule-cockpit__matrix-header strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__matrix-header span,.shared-rule-cockpit__matrix-source{color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-badge{flex:0 0 auto;padding:3px 8px;border-radius:999px;background:#16a34a1f;color:#166534;font-weight:800;white-space:nowrap}.shared-rule-cockpit__projection-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.shared-rule-cockpit__projection{display:grid;gap:3px;min-width:0;padding:9px;border:1px solid rgba(15,23,42,.08);border-radius:11px;background:#f8fafcd1}.shared-rule-cockpit__projection[data-status=ready]{border-color:#16a34a33;background:#f0fdf4d1}.shared-rule-cockpit__projection span{color:#1d4ed8;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;overflow-wrap:anywhere}.shared-rule-cockpit__projection strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__projection small,.shared-rule-cockpit__projection em{color:#475569;font-size:11px;font-style:normal;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-source{margin:0}.shared-rule-cockpit__timeline{display:grid;gap:8px;max-height:190px;margin:12px 0 0;padding:0;overflow:auto;list-style:none}.shared-rule-cockpit__timeline-item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;border:1px solid rgba(30,64,175,.12);border-radius:12px;background:#ffffffc2}.shared-rule-cockpit__timeline-icon{display:grid;width:24px;height:24px;place-items:center;border-radius:999px;background:#1e40af1a;color:#1e3a8a;font-family:Material Icons;font-size:16px;line-height:1}.shared-rule-cockpit__timeline-item strong{color:#0f172a;font-size:12px;line-height:1.35}.shared-rule-cockpit__timeline-item p,.shared-rule-cockpit__timeline-item small,.shared-rule-cockpit__timeline-item time,.shared-rule-cockpit__timeline-empty{display:block;margin:3px 0 0;color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__timeline-badge{display:inline-flex;margin-left:6px;padding:2px 6px;border-radius:999px;background:#0ea5e91f;color:#075985;font-size:10px;font-weight:700}.shared-rule-cockpit__timeline-empty{padding:10px;border-radius:12px;background:#ffffffa3}@media(max-width:720px){.shared-rule-cockpit{bottom:72px;max-height:calc(100vh - 112px)}.shared-rule-cockpit__facts,.shared-rule-cockpit__projection-grid{grid-template-columns:1fr}}\n"] }]
21986
+ `, styles: [":host{display:block;position:relative;min-height:var(--pdx-page-builder-min-height, 420px)}.builder-shell{display:block;position:relative;min-height:inherit;height:100%}.builder-shell:has(.pdx-shell.fullscreen) praxis-floating-toolbar{display:none}.builder-premium-readiness{display:grid;grid-template-columns:minmax(220px,.72fr) minmax(0,1.28fr);gap:12px;width:100%;margin:0 0 14px;padding:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #cac4d0) 72%,transparent);border-radius:12px;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 10%,transparent),transparent 36%),color-mix(in srgb,var(--md-sys-color-surface-container-lowest, #fff) 96%,transparent);color:var(--md-sys-color-on-surface, #1d1b20);box-shadow:inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface, #1d1b20) 5%,transparent)}.builder-premium-readiness__header{display:flex;align-items:flex-start;gap:10px;min-width:0}.builder-premium-readiness__header strong{display:block;font-size:13px;line-height:1.25}.builder-premium-readiness__header p,.builder-premium-readiness__item p{margin:2px 0 0;color:var(--md-sys-color-on-surface-variant, #49454f);font-size:11px;line-height:1.35}.builder-premium-readiness__icon{color:var(--md-sys-color-primary, #6750a4);font-size:20px;line-height:1}.builder-premium-readiness__list{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:8px;margin:0;padding:0;list-style:none}.builder-premium-readiness__item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px;min-width:0;padding:9px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #cac4d0) 64%,transparent);border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low, #f7f2fa) 84%,transparent)}.builder-premium-readiness__item strong{display:block;font-size:12px;line-height:1.25}.builder-premium-readiness__action{appearance:none;display:inline-flex;align-items:center;justify-content:center;min-height:26px;margin-top:7px;padding:4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 34%,transparent);border-radius:7px;background:color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 9%,var(--md-sys-color-surface, #fff));color:var(--md-sys-color-primary, #6750a4);cursor:pointer;font:inherit;font-size:11px;font-weight:700;line-height:1.2;text-align:left}.builder-premium-readiness__severity{width:8px;height:8px;margin-top:4px;border-radius:999px;background:var(--md-sys-color-primary, #6750a4)}.builder-premium-readiness__item[data-severity=warning] .builder-premium-readiness__severity{background:var(--praxis-warning, #b26a00)}.builder-premium-readiness__item[data-severity=error] .builder-premium-readiness__severity{background:var(--md-sys-color-error, #b3261e)}@media(max-width:760px){.builder-premium-readiness{grid-template-columns:1fr}}.agentic-diagnostics-panel{position:absolute;z-index:21;right:16px;width:min(520px,calc(100% - 32px));max-height:min(440px,calc(100% - 32px));overflow:auto;padding:12px;border:1px solid rgba(107,114,128,.28);border-radius:8px;background:#fffffff5;color:#111827;box-shadow:0 14px 36px #0000003d}.agentic-diagnostics-panel--collapsed{width:min(280px,calc(100% - 32px));max-height:58px;overflow:hidden;padding:10px 12px;pointer-events:auto}.agentic-diagnostics-panel__header{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:13px;font-weight:700}.agentic-diagnostics-panel__header-actions{display:flex;align-items:center;gap:8px}.agentic-diagnostics-panel__badge{padding:2px 6px;border:1px solid rgba(107,114,128,.28);border-radius:8px;font-size:11px;font-weight:600;color:#4b5563}.agentic-diagnostics-panel__toggle,.shared-rule-cockpit__toggle{appearance:none;border:1px solid rgba(30,64,175,.18);border-radius:999px;background:#ffffffd6;color:#1e3a8a;cursor:pointer;font-size:11px;font-weight:700;line-height:1;padding:6px 9px;white-space:nowrap}.agentic-diagnostics-panel__description{margin:8px 0 10px;color:#4b5563;font-size:12px;line-height:1.4}.agentic-diagnostics-panel pre{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px;line-height:1.45;color:#1f2937}praxis-ai-assistant-shell{position:fixed;inset:0;z-index:140;pointer-events:none}@media(min-width:1100px){.builder-shell--agentic-review-rail{box-sizing:border-box;padding-right:464px}}.builder-shell__agentic-toggle{position:relative}.builder-shell__agentic-toggle--open,.builder-shell__agentic-toggle--minimized{outline:2px solid rgba(96,165,250,.52);outline-offset:2px}.builder-shell__agentic-toggle--minimized:after{content:\"\";position:absolute;top:6px;right:6px;width:8px;height:8px;border:2px solid var(--md-sys-color-surface, #111827);border-radius:999px;background:#34d399}.builder-shell__connections-toggle--open{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 52%,transparent);outline-offset:2px}.shared-rule-cockpit{position:absolute;z-index:120;left:16px;bottom:88px;width:min(720px,calc(100% - 32px));max-height:min(560px,calc(100vh - 140px));padding:14px;border:1px solid rgba(30,64,175,.22);border-radius:12px;background:linear-gradient(135deg,#eff6fffa,#fffbebf5);color:#172554;box-shadow:0 18px 46px #0f172a38;overflow:auto;overscroll-behavior:contain}.shared-rule-cockpit--collapsed{width:min(360px,calc(100% - 32px));max-height:72px;overflow:hidden;padding:10px 12px}.shared-rule-cockpit__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.shared-rule-cockpit__header-actions{display:flex;align-items:center;gap:8px}.shared-rule-cockpit__header div{display:grid;gap:2px}.shared-rule-cockpit__header strong{font-size:14px;line-height:1.2}.shared-rule-cockpit__header span{color:#475569;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__badge{flex:0 0 auto;max-width:220px;padding:3px 8px;border:1px solid rgba(30,64,175,.2);border-radius:999px;background:#ffffffbd;color:#1e3a8a;font-size:11px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shared-rule-cockpit__description,.shared-rule-cockpit__status,.shared-rule-cockpit__error{margin:10px 0 0;color:#334155;font-size:12px;line-height:1.45}.shared-rule-cockpit__error{color:#991b1b;font-weight:600}.shared-rule-cockpit__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.shared-rule-cockpit__facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:12px 0 0}.shared-rule-cockpit__facts div{min-width:0;padding:8px;border-radius:10px;background:#ffffffb8}.shared-rule-cockpit__facts dt{color:#64748b;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.shared-rule-cockpit__facts dd{margin:4px 0 0;color:#0f172a;font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__enforcement-matrix{display:grid;gap:10px;margin-top:12px;padding:10px;border:1px solid rgba(30,64,175,.14);border-radius:12px;background:#ffffff94}.shared-rule-cockpit__matrix-header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.shared-rule-cockpit__matrix-header div{display:grid;gap:2px}.shared-rule-cockpit__matrix-header strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__matrix-header span,.shared-rule-cockpit__matrix-source{color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-badge{flex:0 0 auto;padding:3px 8px;border-radius:999px;background:#16a34a1f;color:#166534;font-weight:800;white-space:nowrap}.shared-rule-cockpit__projection-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.shared-rule-cockpit__projection{display:grid;gap:3px;min-width:0;padding:9px;border:1px solid rgba(15,23,42,.08);border-radius:11px;background:#f8fafcd1}.shared-rule-cockpit__projection[data-status=ready]{border-color:#16a34a33;background:#f0fdf4d1}.shared-rule-cockpit__projection span{color:#1d4ed8;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;overflow-wrap:anywhere}.shared-rule-cockpit__projection strong{color:#0f172a;font-size:12px}.shared-rule-cockpit__projection small,.shared-rule-cockpit__projection em{color:#475569;font-size:11px;font-style:normal;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-source{margin:0}.shared-rule-cockpit__timeline{display:grid;gap:8px;max-height:190px;margin:12px 0 0;padding:0;overflow:auto;list-style:none}.shared-rule-cockpit__timeline-item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;border:1px solid rgba(30,64,175,.12);border-radius:12px;background:#ffffffc2}.shared-rule-cockpit__timeline-icon{display:grid;width:24px;height:24px;place-items:center;border-radius:999px;background:#1e40af1a;color:#1e3a8a;font-family:Material Icons;font-size:16px;line-height:1}.shared-rule-cockpit__timeline-item strong{color:#0f172a;font-size:12px;line-height:1.35}.shared-rule-cockpit__timeline-item p,.shared-rule-cockpit__timeline-item small,.shared-rule-cockpit__timeline-item time,.shared-rule-cockpit__timeline-empty{display:block;margin:3px 0 0;color:#475569;font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__timeline-badge{display:inline-flex;margin-left:6px;padding:2px 6px;border-radius:999px;background:#0ea5e91f;color:#075985;font-size:10px;font-weight:700}.shared-rule-cockpit__timeline-empty{padding:10px;border-radius:12px;background:#ffffffa3}@media(max-width:720px){.shared-rule-cockpit{bottom:72px;max-height:calc(100vh - 112px)}.shared-rule-cockpit__facts,.shared-rule-cockpit__projection-grid{grid-template-columns:1fr}}\n"] }]
21177
21987
  }], ctorParameters: () => [{ type: i1.MatDialog }, { type: undefined, decorators: [{
21178
21988
  type: Optional
21179
21989
  }, {
@@ -21200,6 +22010,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21200
22010
  type: Input
21201
22011
  }], pageEditorComponent: [{
21202
22012
  type: Input
22013
+ }], componentPaletteAllowedWidgetIds: [{
22014
+ type: Input
22015
+ }], componentPaletteAllowedWidgetTags: [{
22016
+ type: Input
22017
+ }], componentPaletteAllowedPresetIds: [{
22018
+ type: Input
21203
22019
  }], enableAgenticAuthoring: [{
21204
22020
  type: Input
21205
22021
  }], agenticAuthoringProvider: [{