@praxisui/page-builder 8.0.0-beta.0 → 8.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -0
- package/fesm2022/praxisui-page-builder.mjs +2638 -17
- package/index.d.ts +315 -32
- package/package.json +4 -3
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import * as i2$1 from '@angular/common';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { Inject, ChangeDetectionStrategy, Component, EventEmitter, Output, Input, signal, computed, effect, Optional, inject, input, output, InjectionToken, ENVIRONMENT_INITIALIZER, ViewChild } from '@angular/core';
|
|
4
|
+
import { Inject, ChangeDetectionStrategy, Component, EventEmitter, Output, Input, signal, computed, effect, Optional, inject, input, output, InjectionToken, ENVIRONMENT_INITIALIZER, Injectable, ViewChild } from '@angular/core';
|
|
5
5
|
import * as i2 from '@angular/material/button';
|
|
6
6
|
import { MatButtonModule } from '@angular/material/button';
|
|
7
7
|
import * as i1 from '@angular/material/dialog';
|
|
8
8
|
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
|
9
|
-
import * as
|
|
9
|
+
import * as i4 from '@angular/material/icon';
|
|
10
10
|
import { MatIconModule } from '@angular/material/icon';
|
|
11
11
|
import * as i2$2 from '@praxisui/core';
|
|
12
|
-
import { PraxisIconDirective, BUILTIN_SHELL_PRESETS, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, providePraxisI18n, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, PraxisI18nService,
|
|
12
|
+
import { PraxisIconDirective, BUILTIN_SHELL_PRESETS, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, providePraxisI18n, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, PraxisI18nService, deepMerge, generateId, ComponentMetadataRegistry, SETTINGS_PANEL_BRIDGE, DynamicWidgetPageComponent, DYNAMIC_PAGE_SHELL_EDITOR } from '@praxisui/core';
|
|
13
13
|
export { WidgetShellComponent } from '@praxisui/core';
|
|
14
|
-
import * as
|
|
14
|
+
import * as i3 from '@angular/material/tooltip';
|
|
15
15
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
16
16
|
import * as i3$1 from '@angular/material/form-field';
|
|
17
17
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
@@ -25,11 +25,13 @@ 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 } from 'rxjs';
|
|
28
|
+
import { BehaviorSubject, merge, switchMap, Observable, firstValueFrom, from, concatMap, catchError, of, lastValueFrom, tap } 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';
|
|
32
32
|
import { MatTabsModule } from '@angular/material/tabs';
|
|
33
|
+
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
|
34
|
+
import { AI_STREAM_EVENT_TYPES, PraxisAssistantTurnOrchestratorService, PraxisAiAssistantShellComponent } from '@praxisui/ai';
|
|
33
35
|
|
|
34
36
|
const PLACEHOLDER = 1;
|
|
35
37
|
|
|
@@ -53,7 +55,7 @@ class ConfirmDialogComponent {
|
|
|
53
55
|
<button mat-button mat-dialog-close>{{ data.cancelLabel || 'Cancelar' }}</button>
|
|
54
56
|
<button mat-raised-button color="warn" [mat-dialog-close]="true">{{ data.confirmLabel || 'Excluir' }}</button>
|
|
55
57
|
</div>
|
|
56
|
-
`, isInline: true, styles: [":host{color:var(--md-sys-color-on-surface)}.dlg-icon{vertical-align:middle;margin-right:8px;color:var(--md-sys-color-error)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { 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: "ngmodule", type: MatIconModule }, { kind: "component", type:
|
|
58
|
+
`, isInline: true, styles: [":host{color:var(--md-sys-color-on-surface)}.dlg-icon{vertical-align:middle;margin-right:8px;color:var(--md-sys-color-error)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { 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: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
57
59
|
}
|
|
58
60
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ConfirmDialogComponent, decorators: [{
|
|
59
61
|
type: Component,
|
|
@@ -119,7 +121,7 @@ class TileToolbarComponent {
|
|
|
119
121
|
<mat-icon [praxisIcon]="'delete'"></mat-icon>
|
|
120
122
|
</button>
|
|
121
123
|
</div>
|
|
122
|
-
`, isInline: true, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-tile-toolbar{position:absolute;right:6px;top:-18px;display:flex;gap:6px;z-index:5;opacity:0;transition:opacity .12s ease-in-out;pointer-events:auto;background:var(--md-sys-color-surface-container-low);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);border-radius:999px;padding:4px;box-shadow:var(--mat-elevation-level3)}.pdx-tile-toolbar.always-visible{opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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:
|
|
124
|
+
`, isInline: true, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-tile-toolbar{position:absolute;right:6px;top:-18px;display:flex;gap:6px;z-index:5;opacity:0;transition:opacity .12s ease-in-out;pointer-events:auto;background:var(--md-sys-color-surface-container-low);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);border-radius:999px;padding:4px;box-shadow:var(--mat-elevation-level3)}.pdx-tile-toolbar.always-visible{opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: i4.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 });
|
|
123
125
|
}
|
|
124
126
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: TileToolbarComponent, decorators: [{
|
|
125
127
|
type: Component,
|
|
@@ -211,7 +213,7 @@ class FloatingToolbarComponent {
|
|
|
211
213
|
<ng-content select="[pdx-toolbar-extra]"></ng-content>
|
|
212
214
|
</div>
|
|
213
215
|
</div>
|
|
214
|
-
`, 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}.pdx-fab{box-shadow:var(--mat-elevation-level4)}@media(max-width:720px){.pdx-actions{gap:6px}.pdx-floating-toolbar{right:12px;bottom:12px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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: "component", type: i2.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type:
|
|
216
|
+
`, 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}.pdx-fab{box-shadow:var(--mat-elevation-level4)}@media(max-width:720px){.pdx-actions{gap:6px}.pdx-floating-toolbar{right:12px;bottom:12px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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: "component", type: i2.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.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 });
|
|
215
217
|
}
|
|
216
218
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FloatingToolbarComponent, decorators: [{
|
|
217
219
|
type: Component,
|
|
@@ -369,7 +371,7 @@ class ComponentPaletteDialogComponent {
|
|
|
369
371
|
<div mat-dialog-actions align="end">
|
|
370
372
|
<button mat-stroked-button color="primary" mat-dialog-close>Cancelar</button>
|
|
371
373
|
</div>
|
|
372
|
-
`, isInline: true, styles: [":host{display:block}h2[mat-dialog-title]{margin:0;padding:12px 24px 10px;border-bottom:1px solid var(--md-sys-color-outline-variant)}.dlg-title{display:flex;align-items:center;gap:10px}.dlg-icon{color:var(--md-sys-color-primary)}.dlg-head{font-size:18px;font-weight:600;line-height:1.2}.dlg-sub{font-size:12px;opacity:.85;color:var(--md-sys-color-on-surface-variant)}.pdx-palette-content{min-width:480px;max-width:920px;padding-top:8px}.pdx-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px}.pdx-grid.dense{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}.pdx-grid.roomy{grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:16px}.pdx-card{position:relative;display:grid;grid-template-columns:44px 1fr;grid-template-rows:auto auto;gap:10px;padding:14px;border:1px solid transparent;border-radius:14px;cursor:pointer;outline:none;min-height:92px;background:var(--md-sys-color-surface);border-color:var(--md-sys-color-outline-variant);transition:box-shadow .2s ease,background .25s ease,transform .06s ease}.pdx-grid.dense .pdx-card{padding:10px;border-radius:12px;min-height:84px}.pdx-grid.roomy .pdx-card{padding:16px;border-radius:16px;min-height:100px}.pdx-card:focus,.pdx-card:hover{box-shadow:var(--mat-elevation-level4);background:var(--md-sys-color-surface-container-low);border-color:var(--md-sys-color-primary)}.pdx-card:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-card:active{transform:translateY(1px)}.pdx-card-icon{grid-row:span 2;display:flex;align-items:center;justify-content:center;color:var(--md-sys-color-primary)}.pdx-card-title{font-weight:600;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pdx-card-desc{color:var(--md-sys-color-on-surface-variant);display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;word-break:break-word}.pdx-empty{padding:24px;display:grid;place-items:center;color:var(--md-sys-color-on-surface-variant);gap:8px}@media(max-width:600px){.pdx-palette-content{min-width:320px}.pdx-grid{grid-template-columns:repeat(auto-fill,minmax(200px,1fr))}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type:
|
|
374
|
+
`, isInline: true, styles: [":host{display:block}h2[mat-dialog-title]{margin:0;padding:12px 24px 10px;border-bottom:1px solid var(--md-sys-color-outline-variant)}.dlg-title{display:flex;align-items:center;gap:10px}.dlg-icon{color:var(--md-sys-color-primary)}.dlg-head{font-size:18px;font-weight:600;line-height:1.2}.dlg-sub{font-size:12px;opacity:.85;color:var(--md-sys-color-on-surface-variant)}.pdx-palette-content{min-width:480px;max-width:920px;padding-top:8px}.pdx-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px}.pdx-grid.dense{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}.pdx-grid.roomy{grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:16px}.pdx-card{position:relative;display:grid;grid-template-columns:44px 1fr;grid-template-rows:auto auto;gap:10px;padding:14px;border:1px solid transparent;border-radius:14px;cursor:pointer;outline:none;min-height:92px;background:var(--md-sys-color-surface);border-color:var(--md-sys-color-outline-variant);transition:box-shadow .2s ease,background .25s ease,transform .06s ease}.pdx-grid.dense .pdx-card{padding:10px;border-radius:12px;min-height:84px}.pdx-grid.roomy .pdx-card{padding:16px;border-radius:16px;min-height:100px}.pdx-card:focus,.pdx-card:hover{box-shadow:var(--mat-elevation-level4);background:var(--md-sys-color-surface-container-low);border-color:var(--md-sys-color-primary)}.pdx-card:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-card:active{transform:translateY(1px)}.pdx-card-icon{grid-row:span 2;display:flex;align-items:center;justify-content:center;color:var(--md-sys-color-primary)}.pdx-card-title{font-weight:600;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pdx-card-desc{color:var(--md-sys-color-on-surface-variant);display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;word-break:break-word}.pdx-empty{padding:24px;display:grid;place-items:center;color:var(--md-sys-color-on-surface-variant);gap:8px}@media(max-width:600px){.pdx-palette-content{min-width:320px}.pdx-grid{grid-template-columns:repeat(auto-fill,minmax(200px,1fr))}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
373
375
|
}
|
|
374
376
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ComponentPaletteDialogComponent, decorators: [{
|
|
375
377
|
type: Component,
|
|
@@ -1516,7 +1518,7 @@ class WidgetShellEditorComponent {
|
|
|
1516
1518
|
<div class="shell-empty">Nenhuma ação configurada.</div>
|
|
1517
1519
|
</ng-template>
|
|
1518
1520
|
</div>
|
|
1519
|
-
`, isInline: true, styles: [".shell-editor{display:grid;gap:12px;padding:16px;background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.shell-head{display:flex;align-items:center;gap:12px}.shell-title{font-weight:600}.shell-subtitle{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-section{font-weight:600;margin-top:8px}.shell-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.shell-flags{display:flex;gap:16px;align-items:center}.shell-actions-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.shell-available{display:grid;gap:12px}.shell-available-toolbar{display:grid;gap:12px;grid-template-columns:minmax(200px,1fr)}.shell-available-filters{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.shell-available-list{display:grid;gap:10px}.shell-available-item{display:grid;gap:8px;grid-template-columns:1fr auto;border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;padding:12px;background:var(--md-sys-color-surface-container-low)}.shell-available-title{display:flex;align-items:center;gap:10px}.shell-available-text{display:grid;gap:4px}.shell-available-label{font-weight:600}.shell-available-meta{display:flex;gap:8px;flex-wrap:wrap;font-size:11px;color:var(--md-sys-color-on-surface-variant)}.shell-available-desc{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-available-payload{font-size:11px;color:var(--md-sys-color-on-surface-variant)}.shell-available-warning{font-size:11px;color:var(--md-sys-color-error)}.shell-available-actions{display:flex;align-items:flex-start;justify-content:flex-end}.shell-badge{padding:2px 6px;border-radius:999px;border:1px solid var(--md-sys-color-outline-variant);font-size:10px}.shell-code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.shell-actions{display:grid;gap:12px}.shell-action{border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;padding:12px;display:grid;gap:8px}.shell-action-row{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}.shell-action-actions{display:flex;justify-content:flex-end}.shell-action-hint,.shell-empty{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-hint{align-self:center;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-quick-inputs{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));align-items:end}.shell-input-path{font-size:12px;color:var(--md-sys-color-on-surface-variant);align-self:center}.shell-editor .mat-mdc-form-field{width:100%}.shell-preview{border:1px dashed var(--md-sys-color-outline-variant);border-radius:12px;padding:12px}.shell-preview-card{background:var(--pdx-shell-card-bg, var(--md-sys-color-surface));border:1px solid var(--pdx-shell-card-border, var(--md-sys-color-outline-variant));border-radius:var(--pdx-shell-card-radius, 14px);box-shadow:var(--pdx-shell-card-shadow, var(--mat-elevation-level2));overflow:hidden}.shell-preview-card.no-shell{background:transparent;border:none;box-shadow:none}.shell-preview-card.expanded{box-shadow:var(--pdx-shell-card-shadow, 0 16px 34px rgba(0,0,0,.32));transform:scale(1.01)}.shell-preview-header{display:flex;align-items:center;gap:12px;padding:10px 12px 8px;border-bottom:1px solid var(--pdx-shell-header-border, var(--md-sys-color-outline-variant));background:var(--pdx-shell-header-bg, var(--md-sys-color-surface-container))}.shell-preview-title{display:flex;align-items:center;gap:10px;min-width:0;flex:1;color:var(--pdx-shell-title-color, inherit)}.shell-preview-title mat-icon{color:var(--pdx-shell-icon-color, currentColor)}.shell-preview-text{min-width:0}.shell-preview-title-text{font-weight:var(--pdx-shell-title-weight, 600);font-size:var(--pdx-shell-title-size, 14px);line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.shell-preview-subtitle{font-size:var(--pdx-shell-subtitle-size, 12px);opacity:.75;color:var(--pdx-shell-subtitle-color, currentColor);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.shell-preview-actions{display:flex;align-items:center;gap:6px}.pdx-preview-text{padding:0 8px}.pdx-preview-outlined{border:1px solid var(--md-sys-color-outline-variant);border-radius:999px;padding:0 10px}.pdx-preview-label{font-size:12px;font-weight:500}.shell-preview-body{padding:var(--pdx-shell-body-padding, 10px 12px 12px 12px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit);font-size:12px}.shell-preview-body.hidden{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i5.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i6.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type:
|
|
1521
|
+
`, isInline: true, styles: [".shell-editor{display:grid;gap:12px;padding:16px;background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.shell-head{display:flex;align-items:center;gap:12px}.shell-title{font-weight:600}.shell-subtitle{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-section{font-weight:600;margin-top:8px}.shell-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.shell-flags{display:flex;gap:16px;align-items:center}.shell-actions-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.shell-available{display:grid;gap:12px}.shell-available-toolbar{display:grid;gap:12px;grid-template-columns:minmax(200px,1fr)}.shell-available-filters{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.shell-available-list{display:grid;gap:10px}.shell-available-item{display:grid;gap:8px;grid-template-columns:1fr auto;border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;padding:12px;background:var(--md-sys-color-surface-container-low)}.shell-available-title{display:flex;align-items:center;gap:10px}.shell-available-text{display:grid;gap:4px}.shell-available-label{font-weight:600}.shell-available-meta{display:flex;gap:8px;flex-wrap:wrap;font-size:11px;color:var(--md-sys-color-on-surface-variant)}.shell-available-desc{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-available-payload{font-size:11px;color:var(--md-sys-color-on-surface-variant)}.shell-available-warning{font-size:11px;color:var(--md-sys-color-error)}.shell-available-actions{display:flex;align-items:flex-start;justify-content:flex-end}.shell-badge{padding:2px 6px;border-radius:999px;border:1px solid var(--md-sys-color-outline-variant);font-size:10px}.shell-code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.shell-actions{display:grid;gap:12px}.shell-action{border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;padding:12px;display:grid;gap:8px}.shell-action-row{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}.shell-action-actions{display:flex;justify-content:flex-end}.shell-action-hint,.shell-empty{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-hint{align-self:center;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-quick-inputs{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));align-items:end}.shell-input-path{font-size:12px;color:var(--md-sys-color-on-surface-variant);align-self:center}.shell-editor .mat-mdc-form-field{width:100%}.shell-preview{border:1px dashed var(--md-sys-color-outline-variant);border-radius:12px;padding:12px}.shell-preview-card{background:var(--pdx-shell-card-bg, var(--md-sys-color-surface));border:1px solid var(--pdx-shell-card-border, var(--md-sys-color-outline-variant));border-radius:var(--pdx-shell-card-radius, 14px);box-shadow:var(--pdx-shell-card-shadow, var(--mat-elevation-level2));overflow:hidden}.shell-preview-card.no-shell{background:transparent;border:none;box-shadow:none}.shell-preview-card.expanded{box-shadow:var(--pdx-shell-card-shadow, 0 16px 34px rgba(0,0,0,.32));transform:scale(1.01)}.shell-preview-header{display:flex;align-items:center;gap:12px;padding:10px 12px 8px;border-bottom:1px solid var(--pdx-shell-header-border, var(--md-sys-color-outline-variant));background:var(--pdx-shell-header-bg, var(--md-sys-color-surface-container))}.shell-preview-title{display:flex;align-items:center;gap:10px;min-width:0;flex:1;color:var(--pdx-shell-title-color, inherit)}.shell-preview-title mat-icon{color:var(--pdx-shell-icon-color, currentColor)}.shell-preview-text{min-width:0}.shell-preview-title-text{font-weight:var(--pdx-shell-title-weight, 600);font-size:var(--pdx-shell-title-size, 14px);line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.shell-preview-subtitle{font-size:var(--pdx-shell-subtitle-size, 12px);opacity:.75;color:var(--pdx-shell-subtitle-color, currentColor);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.shell-preview-actions{display:flex;align-items:center;gap:6px}.pdx-preview-text{padding:0 8px}.pdx-preview-outlined{border:1px solid var(--md-sys-color-outline-variant);border-radius:999px;padding:0 10px}.pdx-preview-label{font-size:12px;font-weight:500}.shell-preview-body{padding:var(--pdx-shell-body-padding, 10px 12px 12px 12px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit);font-size:12px}.shell-preview-body.hidden{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i5.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i6.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i9.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1520
1522
|
}
|
|
1521
1523
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: WidgetShellEditorComponent, decorators: [{
|
|
1522
1524
|
type: Component,
|
|
@@ -2101,7 +2103,7 @@ class DynamicPageConfigEditorComponent {
|
|
|
2101
2103
|
<mat-tab label="Estado da Pagina"><mat-form-field appearance="outline" class="wide"><mat-label>State (JSON)</mat-label><textarea matInput rows="14" [formControl]="stateControl"></textarea></mat-form-field></mat-tab>
|
|
2102
2104
|
</mat-tab-group>
|
|
2103
2105
|
</div>
|
|
2104
|
-
`, isInline: true, styles: [".editor,.panel{display:grid;gap:16px}.head,.summary{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.card{display:grid;gap:12px;padding:16px;border:1px solid #d8e0ea;border-radius:16px;background:#fbfcfe}.wide{grid-column:1/-1}.hint{color:#5b6472;font-size:12px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type:
|
|
2106
|
+
`, isInline: true, styles: [".editor,.panel{display:grid;gap:16px}.head,.summary{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.card{display:grid;gap:12px;padding:16px;border:1px solid #d8e0ea;border-radius:16px;background:#fbfcfe}.wide{grid-column:1/-1}.hint{color:#5b6472;font-size:12px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i9.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i7.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i7.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2105
2107
|
}
|
|
2106
2108
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicPageConfigEditorComponent, decorators: [{
|
|
2107
2109
|
type: Component,
|
|
@@ -2300,6 +2302,100 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
|
|
|
2300
2302
|
'praxis.pageBuilder.connections.details.policy': 'Policy',
|
|
2301
2303
|
'praxis.pageBuilder.connections.details.diagnostics': 'Diagnostics',
|
|
2302
2304
|
'praxis.pageBuilder.connections.palette.insertComponent': 'Insert component',
|
|
2305
|
+
'praxis.pageBuilder.agentic.toggle': 'Create with AI',
|
|
2306
|
+
'praxis.pageBuilder.agentic.panelAria': 'AI page authoring',
|
|
2307
|
+
'praxis.pageBuilder.agentic.title': 'AI assistant',
|
|
2308
|
+
'praxis.pageBuilder.agentic.subtitle': 'Chat, confirm the intent, and review the result before saving.',
|
|
2309
|
+
'praxis.pageBuilder.agentic.close': 'Close',
|
|
2310
|
+
'praxis.pageBuilder.agentic.promptLabel': 'Message',
|
|
2311
|
+
'praxis.pageBuilder.agentic.promptPlaceholder': 'Describe the page, dashboard, form, or change you need.',
|
|
2312
|
+
'praxis.pageBuilder.agentic.emptyConversation': 'Tell me what you want to create or change. I will ask follow-up questions before applying the preview.',
|
|
2313
|
+
'praxis.pageBuilder.agentic.conversationAria': 'AI conversation',
|
|
2314
|
+
'praxis.pageBuilder.agentic.quickRepliesAria': 'Quick replies',
|
|
2315
|
+
'praxis.pageBuilder.agentic.contextAria': 'Active context',
|
|
2316
|
+
'praxis.pageBuilder.agentic.attachmentsAria': 'Attached context',
|
|
2317
|
+
'praxis.pageBuilder.agentic.context.component': 'Component',
|
|
2318
|
+
'praxis.pageBuilder.agentic.context.pageBuilder': 'Page Builder',
|
|
2319
|
+
'praxis.pageBuilder.agentic.context.route': 'Route',
|
|
2320
|
+
'praxis.pageBuilder.agentic.context.selection': 'Selection',
|
|
2321
|
+
'praxis.pageBuilder.agentic.editMessage': 'Edit',
|
|
2322
|
+
'praxis.pageBuilder.agentic.resendMessage': 'Resend',
|
|
2323
|
+
'praxis.pageBuilder.agentic.removeAttachment': 'Remove attachment',
|
|
2324
|
+
'praxis.pageBuilder.agentic.mode.config': 'Configuration',
|
|
2325
|
+
'praxis.pageBuilder.agentic.mode.agenticAuthoring': 'Authoring',
|
|
2326
|
+
'praxis.pageBuilder.agentic.mode.chat': 'Chat',
|
|
2327
|
+
'praxis.pageBuilder.agentic.mode.diagnostic': 'Diagnostic',
|
|
2328
|
+
'praxis.pageBuilder.agentic.mode.review': 'Review',
|
|
2329
|
+
'praxis.pageBuilder.agentic.mode.inlineHelp': 'Help',
|
|
2330
|
+
'praxis.pageBuilder.agentic.state.idle': 'Idle',
|
|
2331
|
+
'praxis.pageBuilder.agentic.state.listening': 'Ready',
|
|
2332
|
+
'praxis.pageBuilder.agentic.state.processing': 'Processing',
|
|
2333
|
+
'praxis.pageBuilder.agentic.state.clarification': 'Waiting for input',
|
|
2334
|
+
'praxis.pageBuilder.agentic.state.review': 'Review',
|
|
2335
|
+
'praxis.pageBuilder.agentic.state.applying': 'Applying',
|
|
2336
|
+
'praxis.pageBuilder.agentic.state.success': 'Done',
|
|
2337
|
+
'praxis.pageBuilder.agentic.state.error': 'Error',
|
|
2338
|
+
'praxis.pageBuilder.agentic.quickReplies.confirm': 'Yes, create it',
|
|
2339
|
+
'praxis.pageBuilder.agentic.quickReplies.revise': 'I want to adjust',
|
|
2340
|
+
'praxis.pageBuilder.agentic.quickReplies.cancel': 'Cancel',
|
|
2341
|
+
'praxis.pageBuilder.agentic.quickReplies.payrollExecutiveDashboard': 'Executive dashboard',
|
|
2342
|
+
'praxis.pageBuilder.agentic.quickReplies.payrollDepartmentDrilldown': 'Department drill-down',
|
|
2343
|
+
'praxis.pageBuilder.agentic.quickReplies.payrollDetailTable': 'Detailed table',
|
|
2344
|
+
'praxis.pageBuilder.agentic.quickReplies.dashboardSuggestion': 'Dashboard',
|
|
2345
|
+
'praxis.pageBuilder.agentic.quickReplies.formSuggestion': 'Form',
|
|
2346
|
+
'praxis.pageBuilder.agentic.quickReplies.masterDetailSuggestion': 'Master detail',
|
|
2347
|
+
'praxis.pageBuilder.agentic.quickReplies.confirmPromptSuffix': 'Confirmed:',
|
|
2348
|
+
'praxis.pageBuilder.agentic.quickReplies.resourceSelectionPrompt': 'Use {label} ({resourcePath}) as the data source.',
|
|
2349
|
+
'praxis.pageBuilder.agentic.attachments.currentPage': 'Current page',
|
|
2350
|
+
'praxis.pageBuilder.agentic.suggestionPrompts.payrollExecutiveDashboard': 'Create a payroll dashboard with KPIs, payroll by department, monthly evolution, and a detail table.',
|
|
2351
|
+
'praxis.pageBuilder.agentic.suggestionPrompts.payrollDepartmentDrilldown': 'Create a payroll dashboard with a department chart that filters a detail table when a bar is selected.',
|
|
2352
|
+
'praxis.pageBuilder.agentic.suggestionPrompts.payrollDetailTable': 'Create a payroll detail table with filters, formatted currency values, and employee-level columns.',
|
|
2353
|
+
'praxis.pageBuilder.agentic.suggestionPrompts.dashboardSuggestion': 'Create a dashboard with KPIs, a chart, and a detail table.',
|
|
2354
|
+
'praxis.pageBuilder.agentic.suggestionPrompts.formSuggestion': 'Create a form with only the fields required for the selected business process.',
|
|
2355
|
+
'praxis.pageBuilder.agentic.suggestionPrompts.masterDetailSuggestion': 'Create a master-detail page with a summary list and a linked detail area.',
|
|
2356
|
+
'praxis.pageBuilder.agentic.exploratory.payrollOptions': 'For payroll, the best options are: 1. executive dashboard with KPIs and total payroll; 2. department drill-down with chart filtering a detail table; 3. monthly evolution to identify cost trends; 4. detailed table with filters and currency formatting. Choose one option or describe the change you want me to create.',
|
|
2357
|
+
'praxis.pageBuilder.agentic.exploratory.genericOptions': 'I can help you choose before creating. Common options are dashboards for analysis, forms for data entry, master-detail pages for navigation, and tables for operational detail. Choose one option or describe what you want me to create.',
|
|
2358
|
+
'praxis.pageBuilder.agentic.exploratory.capability.chart': 'charts',
|
|
2359
|
+
'praxis.pageBuilder.agentic.exploratory.capability.table': 'tables',
|
|
2360
|
+
'praxis.pageBuilder.agentic.exploratory.capability.form': 'forms',
|
|
2361
|
+
'praxis.pageBuilder.agentic.exploratory.capability.masterDetail': 'master-detail pages',
|
|
2362
|
+
'praxis.pageBuilder.agentic.resourceDiscovery.found': 'I found APIs that can feed this screen. Choose one before generating the preview.',
|
|
2363
|
+
'praxis.pageBuilder.agentic.resourceDiscovery.empty': 'I did not find a matching API yet. Describe the business data this screen should use.',
|
|
2364
|
+
'praxis.pageBuilder.agentic.resourceDiscovery.useResource': 'Use {resourcePath}',
|
|
2365
|
+
'praxis.pageBuilder.agentic.diagnostics.title': 'LLM diagnostics',
|
|
2366
|
+
'praxis.pageBuilder.agentic.diagnostics.badge': 'Debug',
|
|
2367
|
+
'praxis.pageBuilder.agentic.diagnostics.description': 'Prompt, context bundle, and tool catalog returned by the backend for this turn.',
|
|
2368
|
+
'praxis.pageBuilder.agentic.dragHandleAria': 'Move AI assistant',
|
|
2369
|
+
'praxis.pageBuilder.agentic.resizeHandleAria': 'Resize AI assistant',
|
|
2370
|
+
'praxis.pageBuilder.agentic.resizeHandleTooltip': 'Resize',
|
|
2371
|
+
'praxis.pageBuilder.agentic.preview': 'Preview',
|
|
2372
|
+
'praxis.pageBuilder.agentic.persist': 'Save',
|
|
2373
|
+
'praxis.pageBuilder.agentic.status.resolvingIntent': 'Resolving intent...',
|
|
2374
|
+
'praxis.pageBuilder.agentic.status.waitingRevision': 'Refine your prompt and preview again.',
|
|
2375
|
+
'praxis.pageBuilder.agentic.status.cancelled': 'Request cancelled.',
|
|
2376
|
+
'praxis.pageBuilder.agentic.status.contextBundle': 'Preparing context...',
|
|
2377
|
+
'praxis.pageBuilder.agentic.status.resourceDiscovery': 'Finding API resources...',
|
|
2378
|
+
'praxis.pageBuilder.agentic.status.resourceDiscoveryBackend': 'Found API resources in the backend catalog.',
|
|
2379
|
+
'praxis.pageBuilder.agentic.status.refinedCandidates': 'Reviewing the retrieved resources with the AI...',
|
|
2380
|
+
'praxis.pageBuilder.agentic.status.previewing': 'Generating preview...',
|
|
2381
|
+
'praxis.pageBuilder.agentic.status.previewCompile': 'Compiling preview...',
|
|
2382
|
+
'praxis.pageBuilder.agentic.status.previewReady': 'Preview applied to the page.',
|
|
2383
|
+
'praxis.pageBuilder.agentic.status.acceptedAddLocalField': 'Local field added to the form.',
|
|
2384
|
+
'praxis.pageBuilder.agentic.status.acceptedRemoveLocalField': 'Local field removed from the form.',
|
|
2385
|
+
'praxis.pageBuilder.agentic.status.acceptedRelabelField': 'Field label updated.',
|
|
2386
|
+
'praxis.pageBuilder.agentic.status.saving': 'Saving page...',
|
|
2387
|
+
'praxis.pageBuilder.agentic.status.saved': 'Page saved.',
|
|
2388
|
+
'praxis.pageBuilder.agentic.errors.applyLocal': 'Preview could not be applied.',
|
|
2389
|
+
'praxis.pageBuilder.agentic.errors.componentId': 'Configure a component id before saving.',
|
|
2390
|
+
'praxis.pageBuilder.agentic.errors.invalidPreview': 'Generated preview is invalid.',
|
|
2391
|
+
'praxis.pageBuilder.agentic.errors.intentResolution': 'Intent could not be resolved.',
|
|
2392
|
+
'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.',
|
|
2393
|
+
'praxis.pageBuilder.agentic.errors.streamProcessing': 'The assistant could not finish this authoring request. Try again or ask support to review the diagnostics.',
|
|
2394
|
+
'praxis.pageBuilder.agentic.errors.streamConnection': 'The assistant stream was interrupted before the turn finished. Try again or ask support to check the stream connection.',
|
|
2395
|
+
'praxis.pageBuilder.agentic.errors.duplicateField': 'This field already exists in the selected form.',
|
|
2396
|
+
'praxis.pageBuilder.agentic.errors.nonLocalFieldRemoval': 'Only local fields created by AI can be removed in this flow.',
|
|
2397
|
+
'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.',
|
|
2398
|
+
'praxis.pageBuilder.agentic.errors.generic': 'AI authoring failed.',
|
|
2303
2399
|
};
|
|
2304
2400
|
|
|
2305
2401
|
const PRAXIS_PAGE_BUILDER_PT_BR = {
|
|
@@ -2463,6 +2559,100 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
|
|
|
2463
2559
|
'praxis.pageBuilder.connections.details.policy': 'Policy',
|
|
2464
2560
|
'praxis.pageBuilder.connections.details.diagnostics': 'Diagnostics',
|
|
2465
2561
|
'praxis.pageBuilder.connections.palette.insertComponent': 'Inserir componente',
|
|
2562
|
+
'praxis.pageBuilder.agentic.toggle': 'Criar com IA',
|
|
2563
|
+
'praxis.pageBuilder.agentic.panelAria': 'Autoria de página com IA',
|
|
2564
|
+
'praxis.pageBuilder.agentic.title': 'Assistente de IA',
|
|
2565
|
+
'praxis.pageBuilder.agentic.subtitle': 'Converse, confirme a intenção e revise o resultado antes de salvar.',
|
|
2566
|
+
'praxis.pageBuilder.agentic.close': 'Fechar',
|
|
2567
|
+
'praxis.pageBuilder.agentic.promptLabel': 'Mensagem',
|
|
2568
|
+
'praxis.pageBuilder.agentic.promptPlaceholder': 'Descreva a página, dashboard, formulário ou alteração que você precisa.',
|
|
2569
|
+
'praxis.pageBuilder.agentic.emptyConversation': 'Diga o que você quer criar ou alterar. Vou fazer perguntas antes de aplicar a pré-visualização.',
|
|
2570
|
+
'praxis.pageBuilder.agentic.conversationAria': 'Conversa com IA',
|
|
2571
|
+
'praxis.pageBuilder.agentic.quickRepliesAria': 'Respostas rápidas',
|
|
2572
|
+
'praxis.pageBuilder.agentic.contextAria': 'Contexto ativo',
|
|
2573
|
+
'praxis.pageBuilder.agentic.attachmentsAria': 'Contexto anexado',
|
|
2574
|
+
'praxis.pageBuilder.agentic.context.component': 'Componente',
|
|
2575
|
+
'praxis.pageBuilder.agentic.context.pageBuilder': 'Page Builder',
|
|
2576
|
+
'praxis.pageBuilder.agentic.context.route': 'Rota',
|
|
2577
|
+
'praxis.pageBuilder.agentic.context.selection': 'Seleção',
|
|
2578
|
+
'praxis.pageBuilder.agentic.editMessage': 'Editar',
|
|
2579
|
+
'praxis.pageBuilder.agentic.resendMessage': 'Reenviar',
|
|
2580
|
+
'praxis.pageBuilder.agentic.removeAttachment': 'Remover anexo',
|
|
2581
|
+
'praxis.pageBuilder.agentic.mode.config': 'Configuração',
|
|
2582
|
+
'praxis.pageBuilder.agentic.mode.agenticAuthoring': 'Autoria',
|
|
2583
|
+
'praxis.pageBuilder.agentic.mode.chat': 'Chat',
|
|
2584
|
+
'praxis.pageBuilder.agentic.mode.diagnostic': 'Diagnóstico',
|
|
2585
|
+
'praxis.pageBuilder.agentic.mode.review': 'Revisão',
|
|
2586
|
+
'praxis.pageBuilder.agentic.mode.inlineHelp': 'Ajuda',
|
|
2587
|
+
'praxis.pageBuilder.agentic.state.idle': 'Ocioso',
|
|
2588
|
+
'praxis.pageBuilder.agentic.state.listening': 'Pronto',
|
|
2589
|
+
'praxis.pageBuilder.agentic.state.processing': 'Processando',
|
|
2590
|
+
'praxis.pageBuilder.agentic.state.clarification': 'Aguardando resposta',
|
|
2591
|
+
'praxis.pageBuilder.agentic.state.review': 'Revisão',
|
|
2592
|
+
'praxis.pageBuilder.agentic.state.applying': 'Aplicando',
|
|
2593
|
+
'praxis.pageBuilder.agentic.state.success': 'Concluído',
|
|
2594
|
+
'praxis.pageBuilder.agentic.state.error': 'Erro',
|
|
2595
|
+
'praxis.pageBuilder.agentic.quickReplies.confirm': 'Sim, criar',
|
|
2596
|
+
'praxis.pageBuilder.agentic.quickReplies.revise': 'Quero ajustar',
|
|
2597
|
+
'praxis.pageBuilder.agentic.quickReplies.cancel': 'Cancelar',
|
|
2598
|
+
'praxis.pageBuilder.agentic.quickReplies.payrollExecutiveDashboard': 'Dashboard executivo',
|
|
2599
|
+
'praxis.pageBuilder.agentic.quickReplies.payrollDepartmentDrilldown': 'Drill-down por departamento',
|
|
2600
|
+
'praxis.pageBuilder.agentic.quickReplies.payrollDetailTable': 'Tabela detalhada',
|
|
2601
|
+
'praxis.pageBuilder.agentic.quickReplies.dashboardSuggestion': 'Dashboard',
|
|
2602
|
+
'praxis.pageBuilder.agentic.quickReplies.formSuggestion': 'Formulário',
|
|
2603
|
+
'praxis.pageBuilder.agentic.quickReplies.masterDetailSuggestion': 'Master detail',
|
|
2604
|
+
'praxis.pageBuilder.agentic.quickReplies.confirmPromptSuffix': 'Confirmado:',
|
|
2605
|
+
'praxis.pageBuilder.agentic.quickReplies.resourceSelectionPrompt': 'Usar {label} ({resourcePath}) como fonte de dados.',
|
|
2606
|
+
'praxis.pageBuilder.agentic.attachments.currentPage': 'Página atual',
|
|
2607
|
+
'praxis.pageBuilder.agentic.suggestionPrompts.payrollExecutiveDashboard': 'Crie um dashboard de folha de pagamento com KPIs, folha por departamento, evolução mensal e tabela de detalhes.',
|
|
2608
|
+
'praxis.pageBuilder.agentic.suggestionPrompts.payrollDepartmentDrilldown': 'Crie um dashboard de folha de pagamento com gráfico por departamento que filtre uma tabela detalhada ao selecionar uma barra.',
|
|
2609
|
+
'praxis.pageBuilder.agentic.suggestionPrompts.payrollDetailTable': 'Crie uma tabela detalhada de folha de pagamento com filtros, valores monetários formatados e colunas por funcionário.',
|
|
2610
|
+
'praxis.pageBuilder.agentic.suggestionPrompts.dashboardSuggestion': 'Crie um dashboard com indicadores, gráfico e tabela de detalhes.',
|
|
2611
|
+
'praxis.pageBuilder.agentic.suggestionPrompts.formSuggestion': 'Crie um formulário com apenas os campos necessários para o processo de negócio selecionado.',
|
|
2612
|
+
'praxis.pageBuilder.agentic.suggestionPrompts.masterDetailSuggestion': 'Crie uma página master-detail com lista resumida e área de detalhes vinculada.',
|
|
2613
|
+
'praxis.pageBuilder.agentic.exploratory.payrollOptions': 'Para folha de pagamento, as melhores opções são: 1. dashboard executivo com KPIs e total da folha; 2. drill-down por departamento com gráfico filtrando uma tabela; 3. evolução mensal para identificar tendência de custo; 4. tabela detalhada com filtros e valores monetários. Escolha uma opção ou descreva o que você quer que eu crie.',
|
|
2614
|
+
'praxis.pageBuilder.agentic.exploratory.genericOptions': 'Posso ajudar você a escolher antes de criar. As opções mais comuns são dashboards para análise, formulários para entrada de dados, páginas master-detail para navegação e tabelas para detalhe operacional. Escolha uma opção ou descreva o que você quer que eu crie.',
|
|
2615
|
+
'praxis.pageBuilder.agentic.exploratory.capability.chart': 'gráficos',
|
|
2616
|
+
'praxis.pageBuilder.agentic.exploratory.capability.table': 'tabelas',
|
|
2617
|
+
'praxis.pageBuilder.agentic.exploratory.capability.form': 'formulários',
|
|
2618
|
+
'praxis.pageBuilder.agentic.exploratory.capability.masterDetail': 'páginas master-detail',
|
|
2619
|
+
'praxis.pageBuilder.agentic.resourceDiscovery.found': 'Encontrei APIs que podem alimentar esta tela. Escolha uma antes de gerar a pré-visualização.',
|
|
2620
|
+
'praxis.pageBuilder.agentic.resourceDiscovery.empty': 'Ainda não encontrei uma API correspondente. Descreva quais dados de negócio esta tela deve usar.',
|
|
2621
|
+
'praxis.pageBuilder.agentic.resourceDiscovery.useResource': 'Usar {resourcePath}',
|
|
2622
|
+
'praxis.pageBuilder.agentic.diagnostics.title': 'Diagnóstico do LLM',
|
|
2623
|
+
'praxis.pageBuilder.agentic.diagnostics.badge': 'Debug',
|
|
2624
|
+
'praxis.pageBuilder.agentic.diagnostics.description': 'Prompt, pacote de contexto e catálogo de ferramentas retornados pelo backend para este turno.',
|
|
2625
|
+
'praxis.pageBuilder.agentic.dragHandleAria': 'Mover assistente de IA',
|
|
2626
|
+
'praxis.pageBuilder.agentic.resizeHandleAria': 'Redimensionar assistente de IA',
|
|
2627
|
+
'praxis.pageBuilder.agentic.resizeHandleTooltip': 'Redimensionar',
|
|
2628
|
+
'praxis.pageBuilder.agentic.preview': 'Pré-visualizar',
|
|
2629
|
+
'praxis.pageBuilder.agentic.persist': 'Salvar',
|
|
2630
|
+
'praxis.pageBuilder.agentic.status.resolvingIntent': 'Resolvendo intenção...',
|
|
2631
|
+
'praxis.pageBuilder.agentic.status.waitingRevision': 'Ajuste o prompt e pré-visualize novamente.',
|
|
2632
|
+
'praxis.pageBuilder.agentic.status.cancelled': 'Solicitação cancelada.',
|
|
2633
|
+
'praxis.pageBuilder.agentic.status.contextBundle': 'Preparando contexto...',
|
|
2634
|
+
'praxis.pageBuilder.agentic.status.resourceDiscovery': 'Buscando recursos de API...',
|
|
2635
|
+
'praxis.pageBuilder.agentic.status.resourceDiscoveryBackend': 'Encontrei recursos de API no catálogo do backend.',
|
|
2636
|
+
'praxis.pageBuilder.agentic.status.refinedCandidates': 'Estou revisando os recursos encontrados com a IA...',
|
|
2637
|
+
'praxis.pageBuilder.agentic.status.previewing': 'Gerando pré-visualização...',
|
|
2638
|
+
'praxis.pageBuilder.agentic.status.previewCompile': 'Compilando pré-visualização...',
|
|
2639
|
+
'praxis.pageBuilder.agentic.status.previewReady': 'Pré-visualização aplicada à página.',
|
|
2640
|
+
'praxis.pageBuilder.agentic.status.acceptedAddLocalField': 'Campo local adicionado ao formulário.',
|
|
2641
|
+
'praxis.pageBuilder.agentic.status.acceptedRemoveLocalField': 'Campo local removido do formulário.',
|
|
2642
|
+
'praxis.pageBuilder.agentic.status.acceptedRelabelField': 'Rótulo do campo atualizado.',
|
|
2643
|
+
'praxis.pageBuilder.agentic.status.saving': 'Salvando página...',
|
|
2644
|
+
'praxis.pageBuilder.agentic.status.saved': 'Página salva.',
|
|
2645
|
+
'praxis.pageBuilder.agentic.errors.applyLocal': 'A pré-visualização não pôde ser aplicada.',
|
|
2646
|
+
'praxis.pageBuilder.agentic.errors.componentId': 'Configure um id de componente antes de salvar.',
|
|
2647
|
+
'praxis.pageBuilder.agentic.errors.invalidPreview': 'A pré-visualização gerada é inválida.',
|
|
2648
|
+
'praxis.pageBuilder.agentic.errors.intentResolution': 'A intenção não pôde ser resolvida.',
|
|
2649
|
+
'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.',
|
|
2650
|
+
'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.',
|
|
2651
|
+
'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.',
|
|
2652
|
+
'praxis.pageBuilder.agentic.errors.duplicateField': 'Este campo já existe no formulário selecionado.',
|
|
2653
|
+
'praxis.pageBuilder.agentic.errors.nonLocalFieldRemoval': 'Somente campos locais criados pela IA podem ser removidos neste fluxo.',
|
|
2654
|
+
'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.',
|
|
2655
|
+
'praxis.pageBuilder.agentic.errors.generic': 'Falha na autoria com IA.',
|
|
2466
2656
|
};
|
|
2467
2657
|
|
|
2468
2658
|
function createPraxisPageBuilderI18nConfig(options = {}) {
|
|
@@ -3964,7 +4154,7 @@ class PageConfigEditorComponent {
|
|
|
3964
4154
|
</div>
|
|
3965
4155
|
}
|
|
3966
4156
|
</div>
|
|
3967
|
-
`, isInline: true, styles: [".page-config{display:grid;gap:12px;padding:16px;background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.page-head{display:flex;align-items:flex-start;gap:12px}.page-head__copy{display:grid;gap:4px}.page-title{font-weight:600;font-size:18px;line-height:1.2}.page-subtitle{max-width:72ch;color:var(--md-sys-color-on-surface-variant);font-size:13px;line-height:1.45}.spacer{flex:1}.page-summary{display:flex;flex-wrap:wrap;gap:8px}.page-tabs{border-radius:16px;overflow:hidden;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 78%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent)}.page-tabs ::ng-deep .mdc-tab{min-width:120px}.page-tabs ::ng-deep .mdc-tab__text-label{font-size:13px;font-weight:600}.page-tab-panel{display:grid;gap:12px;padding:16px 4px 4px}.page-chip{display:inline-flex;align-items:center;gap:8px;min-height:36px;padding:0 12px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 88%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 82%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:12px;font-weight:500}.page-chip mat-icon{width:18px;height:18px;font-size:18px}.page-chip--accent{border-color:color-mix(in srgb,var(--md-sys-color-primary) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 30%,transparent)}.page-chip--warning{border-color:color-mix(in srgb,var(--md-sys-color-error) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 35%,transparent)}.page-identity{display:grid;gap:4px;padding:12px 14px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 70%,transparent);font-size:13px;color:var(--md-sys-color-on-surface-variant)}.page-section{font-weight:600;margin-top:8px}.page-section-help{margin-top:-4px;color:var(--md-sys-color-on-surface-variant);font-size:13px;line-height:1.45}.grid-form{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.state-grid{display:grid;gap:16px}.state-values,.state-group{padding:14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:14px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-surface-container-low) 92%,transparent),transparent),var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface))}.state-group{display:grid;gap:12px}.state-group-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.state-group-title{font-weight:600}.state-group-help{color:var(--md-sys-color-on-surface-variant);font-size:13px}.state-list{display:grid;gap:12px}.state-card{display:grid;gap:12px;padding:12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 80%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container) 84%,transparent)}.state-card-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.state-card-title{font-weight:600}.state-card-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.span-2{grid-column:span 2}.span-3{grid-column:1 / -1}.state-empty{color:var(--md-sys-color-on-surface-variant);font-size:13px}.state-operator-hint{display:flex;align-items:center;gap:8px;min-height:48px;padding:0 12px;border-radius:12px;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-secondary-container) 35%,transparent)}.state-operator-hint mat-icon{color:var(--md-sys-color-secondary)}.page-actions{display:flex;justify-content:flex-end}.page-error{color:var(--md-sys-color-error);font-size:13px}.page-config .mat-mdc-form-field{width:100%;--mdc-outlined-text-field-container-height: 48px;--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-outline);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-error-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-focus-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-hover-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-supporting-text-color: var(--md-sys-color-on-surface-variant)}.help-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 18px;width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;margin-right:-4px}.help-icon-button mat-icon{font-size:18px;width:18px;height:18px}.mat-mdc-form-field-icon-suffix{align-self:center}@media(max-width:720px){.span-2,.span-3{grid-column:auto}.page-head{flex-direction:column}.state-group-head{align-items:stretch;flex-direction:column}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i9.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i7.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i7.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4157
|
+
`, isInline: true, styles: [".page-config{display:grid;gap:12px;padding:16px;background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.page-head{display:flex;align-items:flex-start;gap:12px}.page-head__copy{display:grid;gap:4px}.page-title{font-weight:600;font-size:18px;line-height:1.2}.page-subtitle{max-width:72ch;color:var(--md-sys-color-on-surface-variant);font-size:13px;line-height:1.45}.spacer{flex:1}.page-summary{display:flex;flex-wrap:wrap;gap:8px}.page-tabs{border-radius:16px;overflow:hidden;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 78%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent)}.page-tabs ::ng-deep .mdc-tab{min-width:120px}.page-tabs ::ng-deep .mdc-tab__text-label{font-size:13px;font-weight:600}.page-tab-panel{display:grid;gap:12px;padding:16px 4px 4px}.page-chip{display:inline-flex;align-items:center;gap:8px;min-height:36px;padding:0 12px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 88%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 82%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:12px;font-weight:500}.page-chip mat-icon{width:18px;height:18px;font-size:18px}.page-chip--accent{border-color:color-mix(in srgb,var(--md-sys-color-primary) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 30%,transparent)}.page-chip--warning{border-color:color-mix(in srgb,var(--md-sys-color-error) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 35%,transparent)}.page-identity{display:grid;gap:4px;padding:12px 14px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 70%,transparent);font-size:13px;color:var(--md-sys-color-on-surface-variant)}.page-section{font-weight:600;margin-top:8px}.page-section-help{margin-top:-4px;color:var(--md-sys-color-on-surface-variant);font-size:13px;line-height:1.45}.grid-form{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.state-grid{display:grid;gap:16px}.state-values,.state-group{padding:14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:14px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-surface-container-low) 92%,transparent),transparent),var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface))}.state-group{display:grid;gap:12px}.state-group-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.state-group-title{font-weight:600}.state-group-help{color:var(--md-sys-color-on-surface-variant);font-size:13px}.state-list{display:grid;gap:12px}.state-card{display:grid;gap:12px;padding:12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 80%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container) 84%,transparent)}.state-card-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.state-card-title{font-weight:600}.state-card-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.span-2{grid-column:span 2}.span-3{grid-column:1 / -1}.state-empty{color:var(--md-sys-color-on-surface-variant);font-size:13px}.state-operator-hint{display:flex;align-items:center;gap:8px;min-height:48px;padding:0 12px;border-radius:12px;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-secondary-container) 35%,transparent)}.state-operator-hint mat-icon{color:var(--md-sys-color-secondary)}.page-actions{display:flex;justify-content:flex-end}.page-error{color:var(--md-sys-color-error);font-size:13px}.page-config .mat-mdc-form-field{width:100%;--mdc-outlined-text-field-container-height: 48px;--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-outline);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-error-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-focus-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-hover-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-supporting-text-color: var(--md-sys-color-on-surface-variant)}.help-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 18px;width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;margin-right:-4px}.help-icon-button mat-icon{font-size:18px;width:18px;height:18px}.mat-mdc-form-field-icon-suffix{align-self:center}@media(max-width:720px){.span-2,.span-3{grid-column:auto}.page-head{flex-direction:column}.state-group-head{align-items:stretch;flex-direction:column}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i9.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i7.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i7.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3968
4158
|
}
|
|
3969
4159
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PageConfigEditorComponent, decorators: [{
|
|
3970
4160
|
type: Component,
|
|
@@ -4603,7 +4793,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
4603
4793
|
* Capabilities catalog for the canonical dynamic page builder/runtime.
|
|
4604
4794
|
*/
|
|
4605
4795
|
const PAGE_BUILDER_AI_CAPABILITIES = {
|
|
4606
|
-
version: 'v1.
|
|
4796
|
+
version: 'v1.2',
|
|
4607
4797
|
enums: {},
|
|
4608
4798
|
targets: [
|
|
4609
4799
|
'page-builder',
|
|
@@ -4618,10 +4808,44 @@ const PAGE_BUILDER_AI_CAPABILITIES = {
|
|
|
4618
4808
|
'Edicao visual de inputs de widget deve usar ComponentDocMeta.configEditor publicado pela lib dona do componente; nao criar editor local no page-builder para semantica de outro pacote.',
|
|
4619
4809
|
'Canvas e o modelo espacial canonico da pagina quando houver posicionamento explicito.',
|
|
4620
4810
|
'Taxonomia editorial: condition usa Json Logic canonico; transform usa pipeline declarativo; policy cobre apenas comportamento operacional.',
|
|
4811
|
+
'Para criacao agentic de paginas, o preview pode trazer uiCompositionPlan como plano intermediario validavel; o page-builder compila esse plano para WidgetPageDefinition antes de aplicar.',
|
|
4812
|
+
'UiCompositionPlan usa widgets[].componentId e bindings declarativos. O JSON persistido continua sendo page.widgets[].definition.id e page.composition.links.',
|
|
4813
|
+
'Nested component ports usam endpoint component-port com nestedPath. O owner em ref.widget, bindings[].from.widget ou bindings[].to.widget continua sendo o widget top-level; a porta real do filho fica em port/direction e o caminho ate o filho fica em nestedPath.',
|
|
4814
|
+
'Nao gere links nested via owner.widgetEvent, bindingPath profundo, page.connections ou wrappers host-specific. widgetEvent e bridge legada/avancada, nao contrato principal de authoring.',
|
|
4621
4815
|
'Payloads legados de layout ainda podem ser ingeridos, mas sao normalizados para canvas e nao devem ser reemitidos.',
|
|
4622
4816
|
'pageIdentity identifica o escopo de persistencia e nao pertence ao objeto page.',
|
|
4623
4817
|
],
|
|
4624
4818
|
capabilities: [
|
|
4819
|
+
{ path: 'uiCompositionPlan', category: 'page', valueKind: 'object', description: 'Plano declarativo intermediario aceito em preview agentic antes do WidgetPageDefinition.' },
|
|
4820
|
+
{ path: 'uiCompositionPlan.version', category: 'page', valueKind: 'string', description: 'Versao do plano. Valor atual: 1.0.' },
|
|
4821
|
+
{ path: 'uiCompositionPlan.kind', category: 'page', valueKind: 'string', description: 'Discriminador do plano. Valor atual: praxis.ui-composition-plan.' },
|
|
4822
|
+
{ path: 'uiCompositionPlan.layoutPreset', category: 'layout', valueKind: 'string', description: 'Preset semantico opcional da composicao planejada.' },
|
|
4823
|
+
{ path: 'uiCompositionPlan.state', category: 'state', valueKind: 'object', description: 'Estado inicial/declarativo que sera compilado para page.state.' },
|
|
4824
|
+
{ path: 'uiCompositionPlan.widgets', category: 'widgets', valueKind: 'array', description: 'Widgets planejados antes da compilacao para page.widgets.' },
|
|
4825
|
+
{ path: 'uiCompositionPlan.widgets[].key', category: 'widgets', valueKind: 'string', description: 'ID estavel do widget planejado.', critical: true },
|
|
4826
|
+
{ path: 'uiCompositionPlan.widgets[].componentId', category: 'widgets', valueKind: 'string', description: 'Componente registrado que sera compilado para definition.id.', critical: true },
|
|
4827
|
+
{ path: 'uiCompositionPlan.widgets[].inputs', category: 'widgets', valueKind: 'object', description: 'Inputs canonicos do componente, compilados para definition.inputs.' },
|
|
4828
|
+
{ path: 'uiCompositionPlan.widgets[].bindingOrder', category: 'widgets', valueKind: 'array', description: 'Ordem declarativa de binding, compilada para definition.bindingOrder.' },
|
|
4829
|
+
{ path: 'uiCompositionPlan.bindings', category: 'connections', valueKind: 'array', description: 'Bindings declarativos que serao compilados para page.composition.links.' },
|
|
4830
|
+
{ path: 'uiCompositionPlan.bindings[].id', category: 'connections', valueKind: 'string', description: 'Identificador estavel do binding planejado.' },
|
|
4831
|
+
{ path: 'uiCompositionPlan.bindings[].from', category: 'connections', valueKind: 'object', description: 'Endpoint de origem: component-port ou state.' },
|
|
4832
|
+
{ path: 'uiCompositionPlan.bindings[].to', category: 'connections', valueKind: 'object', description: 'Endpoint de destino: component-port ou state.' },
|
|
4833
|
+
{ path: 'uiCompositionPlan.bindings[].from.nestedPath', category: 'connections', valueKind: 'array', description: 'Caminho estruturado para porta nested de origem. Use apenas com endpoint component-port; o owner top-level continua em from.widget.' },
|
|
4834
|
+
{ path: 'uiCompositionPlan.bindings[].to.nestedPath', category: 'connections', valueKind: 'array', description: 'Caminho estruturado para porta nested de destino. Use apenas com endpoint component-port; o owner top-level continua em to.widget.' },
|
|
4835
|
+
{ path: 'uiCompositionPlan.bindings[].from.nestedPath[].kind', category: 'connections', valueKind: 'string', description: 'Tipo do segmento nested de origem, como tab, nav, link, expansion, panel ou widget. O ultimo segmento deve ser widget.' },
|
|
4836
|
+
{ path: 'uiCompositionPlan.bindings[].from.nestedPath[].id', category: 'connections', valueKind: 'string', description: 'Identificador estrutural estavel do container de origem no segmento nested, quando existir.' },
|
|
4837
|
+
{ path: 'uiCompositionPlan.bindings[].from.nestedPath[].key', category: 'connections', valueKind: 'string', description: 'Chave estavel do widget filho no segmento terminal widget de origem. Obrigatoria para endpoint nested persistido.', critical: true },
|
|
4838
|
+
{ path: 'uiCompositionPlan.bindings[].from.nestedPath[].index', category: 'connections', valueKind: 'number', description: 'Indice auxiliar de origem para contexto visual/diagnostico; nao use como identidade primaria persistida.' },
|
|
4839
|
+
{ path: 'uiCompositionPlan.bindings[].from.nestedPath[].componentType', category: 'connections', valueKind: 'string', description: 'Tipo do componente real do widget filho de origem, usado como verificacao auxiliar, nao como identidade primaria.' },
|
|
4840
|
+
{ path: 'uiCompositionPlan.bindings[].to.nestedPath[].kind', category: 'connections', valueKind: 'string', description: 'Tipo do segmento nested de destino, como tab, nav, link, expansion, panel ou widget. O ultimo segmento deve ser widget.' },
|
|
4841
|
+
{ path: 'uiCompositionPlan.bindings[].to.nestedPath[].id', category: 'connections', valueKind: 'string', description: 'Identificador estrutural estavel do container de destino no segmento nested, quando existir.' },
|
|
4842
|
+
{ path: 'uiCompositionPlan.bindings[].to.nestedPath[].key', category: 'connections', valueKind: 'string', description: 'Chave estavel do widget filho no segmento terminal widget de destino. Obrigatoria para endpoint nested persistido.', critical: true },
|
|
4843
|
+
{ path: 'uiCompositionPlan.bindings[].to.nestedPath[].index', category: 'connections', valueKind: 'number', description: 'Indice auxiliar de destino para contexto visual/diagnostico; nao use como identidade primaria persistida.' },
|
|
4844
|
+
{ path: 'uiCompositionPlan.bindings[].to.nestedPath[].componentType', category: 'connections', valueKind: 'string', description: 'Tipo do componente real do widget filho de destino, usado como verificacao auxiliar, nao como identidade primaria.' },
|
|
4845
|
+
{ path: 'uiCompositionPlan.bindings[].intent', category: 'connections', valueKind: 'string', description: 'Intencao semantica do binding.' },
|
|
4846
|
+
{ path: 'uiCompositionPlan.bindings[].condition', category: 'connections', valueKind: 'expression', description: 'Guarda opcional em Json Logic.' },
|
|
4847
|
+
{ path: 'uiCompositionPlan.bindings[].transform', category: 'connections', valueKind: 'object', description: 'Transform declarativo: pick-path, query-context, template ou constant.' },
|
|
4848
|
+
{ path: 'uiCompositionPlan.bindings[].policy', category: 'connections', valueKind: 'object', description: 'Politica operacional opcional do binding.' },
|
|
4625
4849
|
{ path: 'page', category: 'page', valueKind: 'object', description: 'Definicao da pagina (WidgetPageDefinition).' },
|
|
4626
4850
|
{ path: 'context', category: 'context', valueKind: 'object', description: 'Contexto extra mesclado ao page.context.' },
|
|
4627
4851
|
{ path: 'enableCustomization', category: 'behavior', valueKind: 'boolean', description: 'Habilita modo de edicao.' },
|
|
@@ -4669,6 +4893,10 @@ const PAGE_BUILDER_AI_CAPABILITIES = {
|
|
|
4669
4893
|
{ path: 'page.composition.links[].id', category: 'connections', valueKind: 'string', description: 'Identificador estavel do link.' },
|
|
4670
4894
|
{ path: 'page.composition.links[].from', category: 'connections', valueKind: 'object', description: 'Endpoint de origem do link.' },
|
|
4671
4895
|
{ path: 'page.composition.links[].to', category: 'connections', valueKind: 'object', description: 'Endpoint de destino do link.' },
|
|
4896
|
+
{ path: 'page.composition.links[].from.ref.nestedPath', category: 'connections', valueKind: 'array', description: 'NestedPath canonico em endpoint component-port de origem persistido. Omita para top-level; nao serialize nestedPath: [].' },
|
|
4897
|
+
{ path: 'page.composition.links[].from.ref.nestedPath[].key', category: 'connections', valueKind: 'string', description: 'Chave estavel do widget filho no segmento terminal widget de origem. Obrigatoria para endpoint nested persistido.', critical: true },
|
|
4898
|
+
{ path: 'page.composition.links[].to.ref.nestedPath', category: 'connections', valueKind: 'array', description: 'NestedPath canonico em endpoint component-port de destino persistido. Omita para top-level; nao serialize nestedPath: [].' },
|
|
4899
|
+
{ path: 'page.composition.links[].to.ref.nestedPath[].key', category: 'connections', valueKind: 'string', description: 'Chave estavel do widget filho no segmento terminal widget de destino. Obrigatoria para endpoint nested persistido.', critical: true },
|
|
4672
4900
|
{ path: 'page.composition.links[].intent', category: 'connections', valueKind: 'string', description: 'Intencao semantica do link.' },
|
|
4673
4901
|
{ path: 'page.composition.links[].transform', category: 'connections', valueKind: 'object', description: 'Pipeline de transformacao do link.' },
|
|
4674
4902
|
{ path: 'page.composition.links[].condition', category: 'connections', valueKind: 'expression', description: 'Guarda semantica opcional do link, expressa como um unico AST Json Logic canonico.' },
|
|
@@ -4831,6 +5059,1676 @@ function providePageBuilderWidgetAiCatalogs() {
|
|
|
4831
5059
|
};
|
|
4832
5060
|
}
|
|
4833
5061
|
|
|
5062
|
+
const PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS = new InjectionToken('PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS');
|
|
5063
|
+
class PageBuilderAgenticAuthoringService {
|
|
5064
|
+
http = inject(HttpClient);
|
|
5065
|
+
options = inject(PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS, {
|
|
5066
|
+
optional: true,
|
|
5067
|
+
});
|
|
5068
|
+
baseUrl = (this.options?.baseUrl || '/api/praxis/config/ai/authoring').replace(/\/$/, '');
|
|
5069
|
+
headersFactory = this.options?.headersFactory || (() => ({}));
|
|
5070
|
+
getComponentCapabilities() {
|
|
5071
|
+
return this.http.get(`${this.baseUrl}/component-capabilities`, { headers: this.buildHeaders() });
|
|
5072
|
+
}
|
|
5073
|
+
previewPage(request) {
|
|
5074
|
+
return this.http.post(`${this.baseUrl}/page-preview`, request, { headers: this.buildHeaders() });
|
|
5075
|
+
}
|
|
5076
|
+
resolveIntent(request) {
|
|
5077
|
+
return this.http.post(`${this.baseUrl}/intent-resolution`, request, { headers: this.buildHeaders() });
|
|
5078
|
+
}
|
|
5079
|
+
searchResourceCandidates(request) {
|
|
5080
|
+
return this.http.post(`${this.baseUrl}/resource-candidates`, request, { headers: this.buildHeaders() });
|
|
5081
|
+
}
|
|
5082
|
+
streamTurn(request) {
|
|
5083
|
+
return this.http.post(`${this.baseUrl}/turn/stream/start`, request, { headers: this.buildHeaders() }).pipe(switchMap((start) => this.connectTurnStream(start)));
|
|
5084
|
+
}
|
|
5085
|
+
applyPage(request) {
|
|
5086
|
+
const { ifMatch, ...body } = request;
|
|
5087
|
+
return this.http.post(`${this.baseUrl}/page-apply`, {
|
|
5088
|
+
componentType: body.componentType || 'praxis-dynamic-page',
|
|
5089
|
+
componentId: body.componentId,
|
|
5090
|
+
scope: body.scope,
|
|
5091
|
+
tags: body.tags,
|
|
5092
|
+
compiledFormPatch: body.compiledFormPatch,
|
|
5093
|
+
}, {
|
|
5094
|
+
headers: this.buildHeaders(ifMatch ? { 'If-Match': this.formatEtag(ifMatch) } : undefined),
|
|
5095
|
+
});
|
|
5096
|
+
}
|
|
5097
|
+
buildHeaders(extra) {
|
|
5098
|
+
const merged = {
|
|
5099
|
+
...(this.options?.defaultHeaders ?? {}),
|
|
5100
|
+
};
|
|
5101
|
+
const runtime = this.headersFactory();
|
|
5102
|
+
for (const [key, value] of Object.entries(runtime)) {
|
|
5103
|
+
if (typeof value === 'string' && value.trim()) {
|
|
5104
|
+
merged[key] = value;
|
|
5105
|
+
}
|
|
5106
|
+
}
|
|
5107
|
+
for (const [key, value] of Object.entries(extra ?? {})) {
|
|
5108
|
+
if (typeof value === 'string' && value.trim()) {
|
|
5109
|
+
merged[key] = value;
|
|
5110
|
+
}
|
|
5111
|
+
}
|
|
5112
|
+
return new HttpHeaders(merged);
|
|
5113
|
+
}
|
|
5114
|
+
connectTurnStream(start) {
|
|
5115
|
+
return new Observable((observer) => {
|
|
5116
|
+
const url = this.buildStreamUrl(start);
|
|
5117
|
+
let source;
|
|
5118
|
+
let closed = false;
|
|
5119
|
+
let connectionErrorTimer = null;
|
|
5120
|
+
const connectionErrorGraceMs = Math.max(0, this.options?.streamConnectionErrorGraceMs ?? 1500);
|
|
5121
|
+
try {
|
|
5122
|
+
source = this.createEventSource(url);
|
|
5123
|
+
}
|
|
5124
|
+
catch (error) {
|
|
5125
|
+
observer.error(this.streamConnectionError(error));
|
|
5126
|
+
return undefined;
|
|
5127
|
+
}
|
|
5128
|
+
const clearConnectionErrorTimer = () => {
|
|
5129
|
+
if (connectionErrorTimer) {
|
|
5130
|
+
clearTimeout(connectionErrorTimer);
|
|
5131
|
+
connectionErrorTimer = null;
|
|
5132
|
+
}
|
|
5133
|
+
};
|
|
5134
|
+
const closeSource = () => {
|
|
5135
|
+
if (closed) {
|
|
5136
|
+
return;
|
|
5137
|
+
}
|
|
5138
|
+
closed = true;
|
|
5139
|
+
clearConnectionErrorTimer();
|
|
5140
|
+
source.close();
|
|
5141
|
+
};
|
|
5142
|
+
const failConnection = (event) => {
|
|
5143
|
+
if (closed) {
|
|
5144
|
+
return;
|
|
5145
|
+
}
|
|
5146
|
+
observer.error(this.streamConnectionError(event));
|
|
5147
|
+
closeSource();
|
|
5148
|
+
};
|
|
5149
|
+
const handleMessage = (event) => {
|
|
5150
|
+
try {
|
|
5151
|
+
clearConnectionErrorTimer();
|
|
5152
|
+
const parsed = JSON.parse(event.data);
|
|
5153
|
+
observer.next(parsed);
|
|
5154
|
+
if (parsed.type === 'result' || parsed.type === 'error' || parsed.type === 'cancelled') {
|
|
5155
|
+
observer.complete();
|
|
5156
|
+
closeSource();
|
|
5157
|
+
}
|
|
5158
|
+
}
|
|
5159
|
+
catch (error) {
|
|
5160
|
+
observer.error(this.streamConnectionError(error));
|
|
5161
|
+
closeSource();
|
|
5162
|
+
}
|
|
5163
|
+
};
|
|
5164
|
+
source.onmessage = handleMessage;
|
|
5165
|
+
if (source.addEventListener) {
|
|
5166
|
+
for (const type of AI_STREAM_EVENT_TYPES) {
|
|
5167
|
+
source.addEventListener(type, handleMessage);
|
|
5168
|
+
}
|
|
5169
|
+
}
|
|
5170
|
+
source.onerror = (event) => {
|
|
5171
|
+
if (closed || connectionErrorTimer) {
|
|
5172
|
+
return;
|
|
5173
|
+
}
|
|
5174
|
+
if (connectionErrorGraceMs === 0) {
|
|
5175
|
+
failConnection(event);
|
|
5176
|
+
return;
|
|
5177
|
+
}
|
|
5178
|
+
connectionErrorTimer = setTimeout(() => failConnection(event), connectionErrorGraceMs);
|
|
5179
|
+
};
|
|
5180
|
+
return () => closeSource();
|
|
5181
|
+
});
|
|
5182
|
+
}
|
|
5183
|
+
streamConnectionError(cause) {
|
|
5184
|
+
return {
|
|
5185
|
+
praxisAgenticTurnStreamConnectionError: true,
|
|
5186
|
+
cause,
|
|
5187
|
+
};
|
|
5188
|
+
}
|
|
5189
|
+
buildStreamUrl(start) {
|
|
5190
|
+
const url = new URL(`${this.baseUrl}/turn/stream/${start.streamId}`, typeof window !== 'undefined' ? window.location.origin : 'http://localhost');
|
|
5191
|
+
if (start.streamAccessToken) {
|
|
5192
|
+
url.searchParams.set('accessToken', start.streamAccessToken);
|
|
5193
|
+
}
|
|
5194
|
+
return /^https?:\/\//i.test(this.baseUrl)
|
|
5195
|
+
? url.toString()
|
|
5196
|
+
: url.pathname + url.search;
|
|
5197
|
+
}
|
|
5198
|
+
createEventSource(url) {
|
|
5199
|
+
const factory = this.options?.eventSourceFactory;
|
|
5200
|
+
if (factory) {
|
|
5201
|
+
return factory(url);
|
|
5202
|
+
}
|
|
5203
|
+
return new EventSource(url);
|
|
5204
|
+
}
|
|
5205
|
+
formatEtag(etag) {
|
|
5206
|
+
const trimmed = etag.trim();
|
|
5207
|
+
return trimmed.startsWith('"') ? trimmed : `"${trimmed}"`;
|
|
5208
|
+
}
|
|
5209
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PageBuilderAgenticAuthoringService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
5210
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PageBuilderAgenticAuthoringService, providedIn: 'root' });
|
|
5211
|
+
}
|
|
5212
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PageBuilderAgenticAuthoringService, decorators: [{
|
|
5213
|
+
type: Injectable,
|
|
5214
|
+
args: [{ providedIn: 'root' }]
|
|
5215
|
+
}] });
|
|
5216
|
+
|
|
5217
|
+
function compileUiCompositionPlan(plan) {
|
|
5218
|
+
const diagnostics = validateUiCompositionPlan(plan);
|
|
5219
|
+
if (diagnostics.length) {
|
|
5220
|
+
return {
|
|
5221
|
+
valid: false,
|
|
5222
|
+
page: null,
|
|
5223
|
+
diagnostics,
|
|
5224
|
+
};
|
|
5225
|
+
}
|
|
5226
|
+
return {
|
|
5227
|
+
valid: true,
|
|
5228
|
+
page: {
|
|
5229
|
+
layoutPreset: plan.layoutPreset,
|
|
5230
|
+
canvas: clone$1(plan.canvas),
|
|
5231
|
+
state: clone$1(plan.state),
|
|
5232
|
+
widgets: plan.widgets.map(toWidgetInstance),
|
|
5233
|
+
composition: {
|
|
5234
|
+
version: '1.0.0',
|
|
5235
|
+
links: (plan.bindings ?? []).map(toCompositionLink),
|
|
5236
|
+
},
|
|
5237
|
+
},
|
|
5238
|
+
diagnostics: [],
|
|
5239
|
+
};
|
|
5240
|
+
}
|
|
5241
|
+
function validateUiCompositionPlan(plan) {
|
|
5242
|
+
const diagnostics = [];
|
|
5243
|
+
const widgetKeys = new Set();
|
|
5244
|
+
if (plan.kind !== 'praxis.ui-composition-plan') {
|
|
5245
|
+
diagnostics.push({
|
|
5246
|
+
code: 'invalid-kind',
|
|
5247
|
+
message: 'UiCompositionPlan.kind must be "praxis.ui-composition-plan".',
|
|
5248
|
+
path: 'kind',
|
|
5249
|
+
});
|
|
5250
|
+
}
|
|
5251
|
+
if (plan.version !== '1.0') {
|
|
5252
|
+
diagnostics.push({
|
|
5253
|
+
code: 'invalid-version',
|
|
5254
|
+
message: 'UiCompositionPlan.version must be "1.0".',
|
|
5255
|
+
path: 'version',
|
|
5256
|
+
});
|
|
5257
|
+
}
|
|
5258
|
+
for (const [index, widget] of (plan.widgets ?? []).entries()) {
|
|
5259
|
+
if (!widget.key?.trim()) {
|
|
5260
|
+
diagnostics.push({
|
|
5261
|
+
code: 'widget-key-required',
|
|
5262
|
+
message: 'Every planned widget must declare a stable key.',
|
|
5263
|
+
path: `widgets.${index}.key`,
|
|
5264
|
+
});
|
|
5265
|
+
continue;
|
|
5266
|
+
}
|
|
5267
|
+
if (widgetKeys.has(widget.key)) {
|
|
5268
|
+
diagnostics.push({
|
|
5269
|
+
code: 'widget-key-duplicated',
|
|
5270
|
+
message: `Widget key "${widget.key}" is duplicated.`,
|
|
5271
|
+
path: `widgets.${index}.key`,
|
|
5272
|
+
});
|
|
5273
|
+
}
|
|
5274
|
+
widgetKeys.add(widget.key);
|
|
5275
|
+
if (!widget.componentId?.trim()) {
|
|
5276
|
+
diagnostics.push({
|
|
5277
|
+
code: 'component-id-required',
|
|
5278
|
+
message: `Widget "${widget.key}" must declare a componentId.`,
|
|
5279
|
+
path: `widgets.${index}.componentId`,
|
|
5280
|
+
});
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
for (const [index, binding] of (plan.bindings ?? []).entries()) {
|
|
5284
|
+
validateEndpoint(binding.from, widgetKeys, diagnostics, `bindings.${index}.from`);
|
|
5285
|
+
validateEndpoint(binding.to, widgetKeys, diagnostics, `bindings.${index}.to`);
|
|
5286
|
+
if (!binding.id?.trim()) {
|
|
5287
|
+
diagnostics.push({
|
|
5288
|
+
code: 'binding-id-required',
|
|
5289
|
+
message: 'Every planned binding must declare a stable id.',
|
|
5290
|
+
path: `bindings.${index}.id`,
|
|
5291
|
+
});
|
|
5292
|
+
}
|
|
5293
|
+
}
|
|
5294
|
+
validateCanvas(plan.canvas, widgetKeys, diagnostics);
|
|
5295
|
+
return diagnostics;
|
|
5296
|
+
}
|
|
5297
|
+
function validateCanvas(canvas, widgetKeys, diagnostics) {
|
|
5298
|
+
if (!canvas)
|
|
5299
|
+
return;
|
|
5300
|
+
for (const key of Object.keys(canvas.items ?? {})) {
|
|
5301
|
+
if (!widgetKeys.has(key)) {
|
|
5302
|
+
diagnostics.push({
|
|
5303
|
+
code: 'canvas-widget-not-found',
|
|
5304
|
+
message: `Canvas item references unknown widget "${key}".`,
|
|
5305
|
+
path: `canvas.items.${key}`,
|
|
5306
|
+
});
|
|
5307
|
+
}
|
|
5308
|
+
}
|
|
5309
|
+
}
|
|
5310
|
+
function validateEndpoint(endpoint, widgetKeys, diagnostics, path) {
|
|
5311
|
+
if (endpoint.kind === 'component-port') {
|
|
5312
|
+
if (!widgetKeys.has(endpoint.widget)) {
|
|
5313
|
+
diagnostics.push({
|
|
5314
|
+
code: 'endpoint-widget-not-found',
|
|
5315
|
+
message: `Endpoint references unknown widget "${endpoint.widget}".`,
|
|
5316
|
+
path: `${path}.widget`,
|
|
5317
|
+
});
|
|
5318
|
+
}
|
|
5319
|
+
if (!endpoint.port?.trim()) {
|
|
5320
|
+
diagnostics.push({
|
|
5321
|
+
code: 'endpoint-port-required',
|
|
5322
|
+
message: 'Component endpoint must declare a port.',
|
|
5323
|
+
path: `${path}.port`,
|
|
5324
|
+
});
|
|
5325
|
+
}
|
|
5326
|
+
validateNestedPath(endpoint.nestedPath, diagnostics, `${path}.nestedPath`);
|
|
5327
|
+
return;
|
|
5328
|
+
}
|
|
5329
|
+
if (!endpoint.path?.trim()) {
|
|
5330
|
+
diagnostics.push({
|
|
5331
|
+
code: 'endpoint-state-path-required',
|
|
5332
|
+
message: 'State endpoint must declare a path.',
|
|
5333
|
+
path: `${path}.path`,
|
|
5334
|
+
});
|
|
5335
|
+
}
|
|
5336
|
+
}
|
|
5337
|
+
function validateNestedPath(nestedPath, diagnostics, path) {
|
|
5338
|
+
if (!nestedPath?.length)
|
|
5339
|
+
return;
|
|
5340
|
+
const terminal = nestedPath[nestedPath.length - 1];
|
|
5341
|
+
if (terminal?.kind !== 'widget' || !terminal.key?.trim()) {
|
|
5342
|
+
diagnostics.push({
|
|
5343
|
+
code: 'endpoint-nested-terminal-widget-key-required',
|
|
5344
|
+
message: 'Nested component endpoint must end with a widget segment with a stable key.',
|
|
5345
|
+
path,
|
|
5346
|
+
});
|
|
5347
|
+
}
|
|
5348
|
+
}
|
|
5349
|
+
function toWidgetInstance(widget) {
|
|
5350
|
+
return {
|
|
5351
|
+
key: widget.key,
|
|
5352
|
+
definition: {
|
|
5353
|
+
id: widget.componentId,
|
|
5354
|
+
bindingOrder: widget.bindingOrder,
|
|
5355
|
+
inputs: clone$1(widget.inputs ?? {}),
|
|
5356
|
+
outputs: clone$1(widget.outputs ?? {}),
|
|
5357
|
+
},
|
|
5358
|
+
};
|
|
5359
|
+
}
|
|
5360
|
+
function toCompositionLink(binding) {
|
|
5361
|
+
const transform = binding.transform ? toCompositionTransform(binding.transform) : undefined;
|
|
5362
|
+
return {
|
|
5363
|
+
id: binding.id,
|
|
5364
|
+
from: toCompositionEndpoint(binding.from),
|
|
5365
|
+
to: toCompositionEndpoint(binding.to),
|
|
5366
|
+
intent: binding.intent,
|
|
5367
|
+
condition: clone$1(binding.condition),
|
|
5368
|
+
transform,
|
|
5369
|
+
policy: clone$1(binding.policy),
|
|
5370
|
+
metadata: clone$1(binding.metadata),
|
|
5371
|
+
};
|
|
5372
|
+
}
|
|
5373
|
+
function toCompositionEndpoint(endpoint) {
|
|
5374
|
+
if (endpoint.kind === 'component-port') {
|
|
5375
|
+
return {
|
|
5376
|
+
kind: 'component-port',
|
|
5377
|
+
ref: {
|
|
5378
|
+
widget: endpoint.widget,
|
|
5379
|
+
port: endpoint.port,
|
|
5380
|
+
direction: endpoint.direction,
|
|
5381
|
+
...(endpoint.nestedPath?.length ? { nestedPath: clone$1(endpoint.nestedPath) } : {}),
|
|
5382
|
+
},
|
|
5383
|
+
};
|
|
5384
|
+
}
|
|
5385
|
+
return {
|
|
5386
|
+
kind: 'state',
|
|
5387
|
+
ref: {
|
|
5388
|
+
path: endpoint.path,
|
|
5389
|
+
layer: endpoint.layer,
|
|
5390
|
+
},
|
|
5391
|
+
};
|
|
5392
|
+
}
|
|
5393
|
+
function toCompositionTransform(transform) {
|
|
5394
|
+
if (transform.kind === 'query-context') {
|
|
5395
|
+
const valuePath = transform.valueVar?.trim() || 'payload';
|
|
5396
|
+
return {
|
|
5397
|
+
version: '2.0',
|
|
5398
|
+
phase: 'link-propagation',
|
|
5399
|
+
mode: 'single-value',
|
|
5400
|
+
steps: [
|
|
5401
|
+
{
|
|
5402
|
+
id: transform.id,
|
|
5403
|
+
kind: 'template',
|
|
5404
|
+
phase: 'link-propagation',
|
|
5405
|
+
input: { source: transform.inputSource ?? 'event' },
|
|
5406
|
+
config: {
|
|
5407
|
+
template: {
|
|
5408
|
+
filters: {
|
|
5409
|
+
[transform.field]: `\${${valuePath}}`,
|
|
5410
|
+
},
|
|
5411
|
+
},
|
|
5412
|
+
},
|
|
5413
|
+
},
|
|
5414
|
+
],
|
|
5415
|
+
};
|
|
5416
|
+
}
|
|
5417
|
+
if (transform.kind === 'template') {
|
|
5418
|
+
return {
|
|
5419
|
+
version: '2.0',
|
|
5420
|
+
phase: 'link-propagation',
|
|
5421
|
+
mode: 'single-value',
|
|
5422
|
+
steps: [
|
|
5423
|
+
{
|
|
5424
|
+
id: transform.id,
|
|
5425
|
+
kind: 'template',
|
|
5426
|
+
phase: 'link-propagation',
|
|
5427
|
+
input: { source: transform.inputSource ?? 'event' },
|
|
5428
|
+
config: {
|
|
5429
|
+
template: clone$1(transform.template),
|
|
5430
|
+
},
|
|
5431
|
+
},
|
|
5432
|
+
],
|
|
5433
|
+
};
|
|
5434
|
+
}
|
|
5435
|
+
if (transform.kind === 'constant') {
|
|
5436
|
+
return {
|
|
5437
|
+
version: '2.0',
|
|
5438
|
+
phase: 'link-propagation',
|
|
5439
|
+
mode: 'single-value',
|
|
5440
|
+
steps: [
|
|
5441
|
+
{
|
|
5442
|
+
id: transform.id,
|
|
5443
|
+
kind: 'constant',
|
|
5444
|
+
phase: 'link-propagation',
|
|
5445
|
+
config: {
|
|
5446
|
+
value: clone$1(transform.value),
|
|
5447
|
+
},
|
|
5448
|
+
},
|
|
5449
|
+
],
|
|
5450
|
+
};
|
|
5451
|
+
}
|
|
5452
|
+
return {
|
|
5453
|
+
version: '2.0',
|
|
5454
|
+
phase: 'link-propagation',
|
|
5455
|
+
mode: 'single-value',
|
|
5456
|
+
steps: [
|
|
5457
|
+
{
|
|
5458
|
+
id: transform.id,
|
|
5459
|
+
kind: 'pick-path',
|
|
5460
|
+
phase: 'link-propagation',
|
|
5461
|
+
input: { source: transform.inputSource ?? 'event' },
|
|
5462
|
+
config: {
|
|
5463
|
+
path: transform.path,
|
|
5464
|
+
},
|
|
5465
|
+
},
|
|
5466
|
+
],
|
|
5467
|
+
};
|
|
5468
|
+
}
|
|
5469
|
+
function clone$1(value) {
|
|
5470
|
+
if (value == null || typeof value !== 'object')
|
|
5471
|
+
return value;
|
|
5472
|
+
try {
|
|
5473
|
+
return structuredClone(value);
|
|
5474
|
+
}
|
|
5475
|
+
catch {
|
|
5476
|
+
return JSON.parse(JSON.stringify(value));
|
|
5477
|
+
}
|
|
5478
|
+
}
|
|
5479
|
+
|
|
5480
|
+
const LEGACY_OPTIONS_KEY = 'options';
|
|
5481
|
+
const LEGACY_LAYOUT_KEY = 'layout';
|
|
5482
|
+
class PageBuilderAiAdapter {
|
|
5483
|
+
host;
|
|
5484
|
+
registry;
|
|
5485
|
+
componentName = 'Page Builder';
|
|
5486
|
+
componentId = 'praxis-dynamic-page-builder';
|
|
5487
|
+
componentType = 'page';
|
|
5488
|
+
constructor(host, registry) {
|
|
5489
|
+
this.host = host;
|
|
5490
|
+
this.registry = registry;
|
|
5491
|
+
}
|
|
5492
|
+
getCurrentConfig() {
|
|
5493
|
+
const page = this.normalizePageForAi(this.parsePage(this.host.page));
|
|
5494
|
+
const config = {
|
|
5495
|
+
page: page ? this.clone(page) : { widgets: [] },
|
|
5496
|
+
context: this.clone(this.host.context ?? null),
|
|
5497
|
+
enableCustomization: this.host.enableCustomization,
|
|
5498
|
+
showSettingsButton: this.host.showSettingsButton,
|
|
5499
|
+
strictValidation: this.host.strictValidation,
|
|
5500
|
+
layoutOptions: this.pickLayoutOptions(this.host.layoutOptions),
|
|
5501
|
+
pageIdentity: this.clone(this.host.pageIdentity),
|
|
5502
|
+
};
|
|
5503
|
+
return config;
|
|
5504
|
+
}
|
|
5505
|
+
getCapabilities() {
|
|
5506
|
+
return getPageAiCatalog(this.getCurrentConfig()).capabilities;
|
|
5507
|
+
}
|
|
5508
|
+
getRuntimeState() {
|
|
5509
|
+
const page = this.normalizePageForAi(this.parsePage(this.host.page));
|
|
5510
|
+
const widgets = page?.widgets || [];
|
|
5511
|
+
const links = page?.composition?.links || [];
|
|
5512
|
+
return {
|
|
5513
|
+
widgetsCount: widgets.length,
|
|
5514
|
+
linksCount: links.length,
|
|
5515
|
+
widgetKeys: widgets.map((w) => w.key),
|
|
5516
|
+
widgetTypes: widgets.map((w) => w.definition?.id).filter((id) => !!id),
|
|
5517
|
+
componentCatalog: this.buildComponentCatalog(),
|
|
5518
|
+
};
|
|
5519
|
+
}
|
|
5520
|
+
createSnapshot() {
|
|
5521
|
+
return this.getCurrentConfig();
|
|
5522
|
+
}
|
|
5523
|
+
async restoreSnapshot(snapshot) {
|
|
5524
|
+
if (!snapshot)
|
|
5525
|
+
return;
|
|
5526
|
+
this.applyConfig(snapshot);
|
|
5527
|
+
}
|
|
5528
|
+
async applyPatch(patch, _intent) {
|
|
5529
|
+
try {
|
|
5530
|
+
const warnings = [];
|
|
5531
|
+
const current = this.getCurrentConfig();
|
|
5532
|
+
const normalizedPatch = this.normalizePatch(patch, current, warnings);
|
|
5533
|
+
const merged = deepMerge(current, normalizedPatch);
|
|
5534
|
+
const next = this.normalizeConfigForRuntime(merged, warnings);
|
|
5535
|
+
this.applyConfig(next);
|
|
5536
|
+
return warnings.length ? { success: true, warnings } : { success: true };
|
|
5537
|
+
}
|
|
5538
|
+
catch (error) {
|
|
5539
|
+
const message = error instanceof Error ? error.message : 'Unknown error applying patch';
|
|
5540
|
+
return { success: false, error: message };
|
|
5541
|
+
}
|
|
5542
|
+
}
|
|
5543
|
+
async applyCompiledFormPatch(compiledFormPatch) {
|
|
5544
|
+
const page = compiledFormPatch?.patch?.page;
|
|
5545
|
+
if (!page) {
|
|
5546
|
+
return {
|
|
5547
|
+
success: false,
|
|
5548
|
+
error: 'CompiledFormPatch must contain patch.page.',
|
|
5549
|
+
};
|
|
5550
|
+
}
|
|
5551
|
+
const materializedPage = this.clone(page);
|
|
5552
|
+
if (this.shouldPreserveLocalTransientFields(compiledFormPatch)) {
|
|
5553
|
+
this.preserveLocalTransientFields(materializedPage);
|
|
5554
|
+
}
|
|
5555
|
+
return this.applyPatch({ page: materializedPage }, 'agentic-authoring.compiled-form-patch');
|
|
5556
|
+
}
|
|
5557
|
+
async applyUiCompositionPlan(plan) {
|
|
5558
|
+
const compiled = compileUiCompositionPlan(plan);
|
|
5559
|
+
if (!compiled.valid) {
|
|
5560
|
+
return {
|
|
5561
|
+
success: false,
|
|
5562
|
+
error: compiled.diagnostics.map((diagnostic) => diagnostic.message).join('\n'),
|
|
5563
|
+
warnings: compiled.diagnostics.map((diagnostic) => diagnostic.path
|
|
5564
|
+
? `${diagnostic.code} at ${diagnostic.path}`
|
|
5565
|
+
: diagnostic.code),
|
|
5566
|
+
};
|
|
5567
|
+
}
|
|
5568
|
+
return this.applyPatch({ page: compiled.page }, 'agentic-authoring.ui-composition-plan');
|
|
5569
|
+
}
|
|
5570
|
+
applyConfig(config) {
|
|
5571
|
+
this.host.applyConfigFromAdapter(config);
|
|
5572
|
+
}
|
|
5573
|
+
parsePage(input) {
|
|
5574
|
+
if (!input)
|
|
5575
|
+
return undefined;
|
|
5576
|
+
if (typeof input === 'string') {
|
|
5577
|
+
try {
|
|
5578
|
+
return JSON.parse(input);
|
|
5579
|
+
}
|
|
5580
|
+
catch {
|
|
5581
|
+
return undefined;
|
|
5582
|
+
}
|
|
5583
|
+
}
|
|
5584
|
+
return input;
|
|
5585
|
+
}
|
|
5586
|
+
normalizePageForAi(page) {
|
|
5587
|
+
if (!page)
|
|
5588
|
+
return page;
|
|
5589
|
+
const cloned = this.clone(page);
|
|
5590
|
+
const { [LEGACY_OPTIONS_KEY]: _legacyOptions, ...rest } = cloned;
|
|
5591
|
+
const widgets = (cloned.widgets || []).map((w) => this.stripLegacyLayoutFields(w));
|
|
5592
|
+
return {
|
|
5593
|
+
...rest,
|
|
5594
|
+
widgets,
|
|
5595
|
+
canvas: this.ensureCanvasLayout(cloned),
|
|
5596
|
+
};
|
|
5597
|
+
}
|
|
5598
|
+
normalizeConfigForRuntime(config, warnings) {
|
|
5599
|
+
const page = this.normalizePageForRuntime(config.page, warnings);
|
|
5600
|
+
return {
|
|
5601
|
+
...config,
|
|
5602
|
+
page,
|
|
5603
|
+
layoutOptions: config.layoutOptions || this.deriveLayoutOptionsFromCanvas(page) || this.host.layoutOptions,
|
|
5604
|
+
};
|
|
5605
|
+
}
|
|
5606
|
+
normalizePageForRuntime(page, warnings) {
|
|
5607
|
+
if (!page)
|
|
5608
|
+
return page;
|
|
5609
|
+
const cloned = this.clone(page);
|
|
5610
|
+
const { [LEGACY_OPTIONS_KEY]: _legacyOptions, ...rest } = cloned;
|
|
5611
|
+
const widgets = (cloned.widgets || []).map((w) => this.stripLegacyLayoutFields(w));
|
|
5612
|
+
return {
|
|
5613
|
+
...rest,
|
|
5614
|
+
widgets,
|
|
5615
|
+
canvas: this.ensureCanvasLayout(cloned, warnings),
|
|
5616
|
+
};
|
|
5617
|
+
}
|
|
5618
|
+
normalizePatch(patch, base, warnings) {
|
|
5619
|
+
if (!patch || typeof patch !== 'object')
|
|
5620
|
+
return {};
|
|
5621
|
+
const cloned = this.clone(patch);
|
|
5622
|
+
const legacyPage = cloned.page;
|
|
5623
|
+
if (cloned.page?.widgets) {
|
|
5624
|
+
cloned.page = {
|
|
5625
|
+
...cloned.page,
|
|
5626
|
+
widgets: cloned.page.widgets.map((w) => this.clone(w)),
|
|
5627
|
+
};
|
|
5628
|
+
}
|
|
5629
|
+
if (cloned.page?.composition?.links) {
|
|
5630
|
+
cloned.page = {
|
|
5631
|
+
...cloned.page,
|
|
5632
|
+
composition: {
|
|
5633
|
+
...(cloned.page.composition || {}),
|
|
5634
|
+
links: cloned.page.composition.links.filter((link) => {
|
|
5635
|
+
if (!this.linkKey(link)) {
|
|
5636
|
+
warnings.push('Composition link missing from/to information was ignored.');
|
|
5637
|
+
return false;
|
|
5638
|
+
}
|
|
5639
|
+
return true;
|
|
5640
|
+
}),
|
|
5641
|
+
},
|
|
5642
|
+
};
|
|
5643
|
+
}
|
|
5644
|
+
if (legacyPage?.[LEGACY_OPTIONS_KEY]) {
|
|
5645
|
+
cloned.layoutOptions = deepMerge(cloned.layoutOptions || {}, legacyPage[LEGACY_OPTIONS_KEY]);
|
|
5646
|
+
}
|
|
5647
|
+
if (cloned.page?.widgets) {
|
|
5648
|
+
const mergedWidgets = this.mergeWidgets(base.page?.widgets || [], cloned.page.widgets, warnings);
|
|
5649
|
+
cloned.page = { ...cloned.page, widgets: mergedWidgets };
|
|
5650
|
+
}
|
|
5651
|
+
if (cloned.page?.composition?.links) {
|
|
5652
|
+
const mergedLinks = this.mergeLinks(base.page?.composition?.links || [], cloned.page.composition.links);
|
|
5653
|
+
cloned.page = {
|
|
5654
|
+
...cloned.page,
|
|
5655
|
+
composition: {
|
|
5656
|
+
...(cloned.page.composition || {}),
|
|
5657
|
+
links: mergedLinks,
|
|
5658
|
+
},
|
|
5659
|
+
};
|
|
5660
|
+
}
|
|
5661
|
+
return cloned;
|
|
5662
|
+
}
|
|
5663
|
+
mergeWidgets(baseWidgets, patchWidgets, warnings) {
|
|
5664
|
+
const normalizedPatch = patchWidgets.map((w) => this.clone(w));
|
|
5665
|
+
// Process updates and removals
|
|
5666
|
+
const merged = baseWidgets
|
|
5667
|
+
.map((orig) => {
|
|
5668
|
+
const key = this.getWidgetKey(orig);
|
|
5669
|
+
const match = key
|
|
5670
|
+
? normalizedPatch.find((p) => this.getWidgetKey(p) === key)
|
|
5671
|
+
: undefined;
|
|
5672
|
+
if (match && match._delete) {
|
|
5673
|
+
return null; // Mark for removal
|
|
5674
|
+
}
|
|
5675
|
+
return match ? deepMerge(orig, match) : orig;
|
|
5676
|
+
})
|
|
5677
|
+
.filter((w) => w !== null);
|
|
5678
|
+
// Process additions
|
|
5679
|
+
for (const patch of normalizedPatch) {
|
|
5680
|
+
if (patch._delete)
|
|
5681
|
+
continue; // Skip deletion patches here
|
|
5682
|
+
const key = this.getWidgetKey(patch) || this.generateWidgetKey(patch);
|
|
5683
|
+
if (!key) {
|
|
5684
|
+
warnings.push('Widget without key/id was ignored.');
|
|
5685
|
+
continue;
|
|
5686
|
+
}
|
|
5687
|
+
if (!baseWidgets.find((w) => this.getWidgetKey(w) === key)) {
|
|
5688
|
+
const next = { ...patch, key };
|
|
5689
|
+
merged.push(next);
|
|
5690
|
+
}
|
|
5691
|
+
}
|
|
5692
|
+
return merged;
|
|
5693
|
+
}
|
|
5694
|
+
shouldPreserveLocalTransientFields(compiledFormPatch) {
|
|
5695
|
+
const warnings = compiledFormPatch['warnings'];
|
|
5696
|
+
return Array.isArray(warnings) && warnings.includes('server-backed-field-labels-customized-locally');
|
|
5697
|
+
}
|
|
5698
|
+
preserveLocalTransientFields(patchPage) {
|
|
5699
|
+
const basePage = this.normalizePageForAi(this.parsePage(this.host.page));
|
|
5700
|
+
const baseWidgets = basePage?.widgets ?? [];
|
|
5701
|
+
for (const patchWidget of patchPage.widgets ?? []) {
|
|
5702
|
+
if (patchWidget.definition?.id !== 'praxis-dynamic-form')
|
|
5703
|
+
continue;
|
|
5704
|
+
const key = this.getWidgetKey(patchWidget);
|
|
5705
|
+
if (!key)
|
|
5706
|
+
continue;
|
|
5707
|
+
const baseWidget = baseWidgets.find((widget) => this.getWidgetKey(widget) === key);
|
|
5708
|
+
if (!baseWidget)
|
|
5709
|
+
continue;
|
|
5710
|
+
this.preserveLocalTransientFieldsForWidget(baseWidget, patchWidget);
|
|
5711
|
+
}
|
|
5712
|
+
}
|
|
5713
|
+
preserveLocalTransientFieldsForWidget(baseWidget, patchWidget) {
|
|
5714
|
+
const baseConfig = (baseWidget.definition?.inputs?.['config'] ?? {});
|
|
5715
|
+
const patchInputs = patchWidget.definition.inputs ??= {};
|
|
5716
|
+
const patchConfig = (patchInputs['config'] ??= {});
|
|
5717
|
+
const baseFields = Array.isArray(baseConfig['fieldMetadata']) ? baseConfig['fieldMetadata'] : [];
|
|
5718
|
+
const patchFields = Array.isArray(patchConfig['fieldMetadata'])
|
|
5719
|
+
? patchConfig['fieldMetadata']
|
|
5720
|
+
: (patchConfig['fieldMetadata'] = []);
|
|
5721
|
+
const preservedNames = [];
|
|
5722
|
+
for (const field of baseFields) {
|
|
5723
|
+
if (!this.isLocalTransientField(field) || patchFields.some((entry) => entry?.name === field.name))
|
|
5724
|
+
continue;
|
|
5725
|
+
patchFields.push(this.clone(field));
|
|
5726
|
+
preservedNames.push(field.name);
|
|
5727
|
+
}
|
|
5728
|
+
if (preservedNames.length === 0)
|
|
5729
|
+
return;
|
|
5730
|
+
const baseSections = Array.isArray(baseConfig['sections']) ? baseConfig['sections'] : [];
|
|
5731
|
+
const patchSections = Array.isArray(patchConfig['sections'])
|
|
5732
|
+
? patchConfig['sections']
|
|
5733
|
+
: (patchConfig['sections'] = []);
|
|
5734
|
+
for (const section of baseSections) {
|
|
5735
|
+
if (!this.sectionContainsAnyField(section, preservedNames))
|
|
5736
|
+
continue;
|
|
5737
|
+
if (this.sectionContainsAnyField({ rows: [{ columns: [{ fields: this.flattenSectionFields(patchSections) }] }] }, preservedNames)) {
|
|
5738
|
+
continue;
|
|
5739
|
+
}
|
|
5740
|
+
patchSections.push(this.clone(section));
|
|
5741
|
+
}
|
|
5742
|
+
}
|
|
5743
|
+
isLocalTransientField(field) {
|
|
5744
|
+
return field?.source === 'local' || field?.transient === true || field?.submitPolicy === 'omit';
|
|
5745
|
+
}
|
|
5746
|
+
sectionContainsAnyField(section, names) {
|
|
5747
|
+
const fields = this.flattenSectionFields([section]);
|
|
5748
|
+
return names.some((name) => fields.includes(name));
|
|
5749
|
+
}
|
|
5750
|
+
flattenSectionFields(sections) {
|
|
5751
|
+
const fields = [];
|
|
5752
|
+
for (const section of sections) {
|
|
5753
|
+
for (const row of section?.rows ?? []) {
|
|
5754
|
+
for (const column of row?.columns ?? []) {
|
|
5755
|
+
for (const field of column?.fields ?? []) {
|
|
5756
|
+
if (typeof field === 'string')
|
|
5757
|
+
fields.push(field);
|
|
5758
|
+
}
|
|
5759
|
+
}
|
|
5760
|
+
}
|
|
5761
|
+
}
|
|
5762
|
+
return fields;
|
|
5763
|
+
}
|
|
5764
|
+
mergeLinks(baseLinks, patchLinks) {
|
|
5765
|
+
const base = baseLinks || [];
|
|
5766
|
+
const patch = patchLinks || [];
|
|
5767
|
+
if (patch.length === 0)
|
|
5768
|
+
return base;
|
|
5769
|
+
// Process updates and removals
|
|
5770
|
+
const merged = base
|
|
5771
|
+
.map((orig) => {
|
|
5772
|
+
const key = this.linkKey(orig);
|
|
5773
|
+
const match = key ? patch.find((p) => this.linkKey(p) === key) : undefined;
|
|
5774
|
+
if (match && match._delete) {
|
|
5775
|
+
return null; // Mark for removal
|
|
5776
|
+
}
|
|
5777
|
+
return match ? deepMerge(orig, match) : orig;
|
|
5778
|
+
})
|
|
5779
|
+
.filter((c) => c !== null);
|
|
5780
|
+
// Process additions
|
|
5781
|
+
for (const conn of patch) {
|
|
5782
|
+
if (conn._delete)
|
|
5783
|
+
continue;
|
|
5784
|
+
const key = this.linkKey(conn);
|
|
5785
|
+
if (!key)
|
|
5786
|
+
continue;
|
|
5787
|
+
if (!base.find((c) => this.linkKey(c) === key)) {
|
|
5788
|
+
merged.push(conn);
|
|
5789
|
+
}
|
|
5790
|
+
}
|
|
5791
|
+
return merged;
|
|
5792
|
+
}
|
|
5793
|
+
layoutFromLegacy(widget) {
|
|
5794
|
+
if (widget[LEGACY_LAYOUT_KEY])
|
|
5795
|
+
return widget[LEGACY_LAYOUT_KEY];
|
|
5796
|
+
if (typeof widget.x !== 'number' || typeof widget.y !== 'number')
|
|
5797
|
+
return undefined;
|
|
5798
|
+
const colSpan = typeof widget.cols === 'number' ? widget.cols : 3;
|
|
5799
|
+
const rowSpan = typeof widget.rows === 'number' ? widget.rows : 3;
|
|
5800
|
+
return { col: widget.x + 1, row: widget.y + 1, colSpan, rowSpan };
|
|
5801
|
+
}
|
|
5802
|
+
ensureCanvasLayout(page, warnings = []) {
|
|
5803
|
+
const widgets = page.widgets || [];
|
|
5804
|
+
const legacyOptions = page[LEGACY_OPTIONS_KEY] ?? this.host.layoutOptions;
|
|
5805
|
+
const baseCanvas = this.clone(page.canvas || {
|
|
5806
|
+
mode: 'grid',
|
|
5807
|
+
columns: legacyOptions?.cols || 12,
|
|
5808
|
+
rowUnit: typeof legacyOptions?.rowHeight === 'number' ? `${legacyOptions.rowHeight}px` : '80px',
|
|
5809
|
+
gap: typeof legacyOptions?.gap === 'number' ? `${legacyOptions.gap}px` : '16px',
|
|
5810
|
+
autoRows: 'fixed',
|
|
5811
|
+
items: {},
|
|
5812
|
+
});
|
|
5813
|
+
const items = { ...(baseCanvas.items || {}) };
|
|
5814
|
+
let nextRow = this.maxCanvasRow(items);
|
|
5815
|
+
for (const widget of widgets) {
|
|
5816
|
+
const key = this.getWidgetKey(widget);
|
|
5817
|
+
if (!key || items[key])
|
|
5818
|
+
continue;
|
|
5819
|
+
const layout = this.layoutFromLegacy(widget);
|
|
5820
|
+
if (layout) {
|
|
5821
|
+
items[key] = {
|
|
5822
|
+
col: this.coerceNumber(layout.col, 1),
|
|
5823
|
+
row: this.coerceNumber(layout.row, 1),
|
|
5824
|
+
colSpan: this.coerceNumber(layout.colSpan, 3),
|
|
5825
|
+
rowSpan: this.coerceNumber(layout.rowSpan, 3),
|
|
5826
|
+
};
|
|
5827
|
+
nextRow = Math.max(nextRow, items[key].row + items[key].rowSpan - 1);
|
|
5828
|
+
continue;
|
|
5829
|
+
}
|
|
5830
|
+
items[key] = { col: 1, row: nextRow + 1, colSpan: 3, rowSpan: 3 };
|
|
5831
|
+
nextRow = items[key].row + items[key].rowSpan - 1;
|
|
5832
|
+
warnings.push(`Widget "${key}" missing canvas placement; using defaults.`);
|
|
5833
|
+
}
|
|
5834
|
+
return {
|
|
5835
|
+
mode: 'grid',
|
|
5836
|
+
columns: baseCanvas.columns || legacyOptions?.cols || 12,
|
|
5837
|
+
rowUnit: baseCanvas.rowUnit || (typeof legacyOptions?.rowHeight === 'number' ? `${legacyOptions.rowHeight}px` : '80px'),
|
|
5838
|
+
gap: baseCanvas.gap || (typeof legacyOptions?.gap === 'number' ? `${legacyOptions.gap}px` : '16px'),
|
|
5839
|
+
autoRows: baseCanvas.autoRows || 'fixed',
|
|
5840
|
+
collisionPolicy: baseCanvas.collisionPolicy,
|
|
5841
|
+
items,
|
|
5842
|
+
};
|
|
5843
|
+
}
|
|
5844
|
+
stripLegacyLayoutFields(widget) {
|
|
5845
|
+
const { x: _x, y: _y, cols: _cols, rows: _rows, minItemCols: _minItemCols, minItemRows: _minItemRows, maxItemCols: _maxItemCols, maxItemRows: _maxItemRows, ...rest } = widget;
|
|
5846
|
+
delete rest[LEGACY_LAYOUT_KEY];
|
|
5847
|
+
return rest;
|
|
5848
|
+
}
|
|
5849
|
+
deriveLayoutOptionsFromCanvas(page) {
|
|
5850
|
+
const canvas = page?.canvas;
|
|
5851
|
+
if (!canvas)
|
|
5852
|
+
return undefined;
|
|
5853
|
+
const derived = {};
|
|
5854
|
+
if (typeof canvas.columns === 'number')
|
|
5855
|
+
derived.cols = canvas.columns;
|
|
5856
|
+
const rowHeight = this.parsePixelValue(canvas.rowUnit);
|
|
5857
|
+
if (typeof rowHeight === 'number')
|
|
5858
|
+
derived.rowHeight = rowHeight;
|
|
5859
|
+
const gap = this.parsePixelValue(canvas.gap);
|
|
5860
|
+
if (typeof gap === 'number')
|
|
5861
|
+
derived.gap = gap;
|
|
5862
|
+
return Object.keys(derived).length ? derived : undefined;
|
|
5863
|
+
}
|
|
5864
|
+
maxCanvasRow(items) {
|
|
5865
|
+
return Object.values(items).reduce((max, item) => Math.max(max, item.row + item.rowSpan - 1), 0);
|
|
5866
|
+
}
|
|
5867
|
+
getWidgetKey(widget) {
|
|
5868
|
+
if (!widget)
|
|
5869
|
+
return undefined;
|
|
5870
|
+
const key = widget.key;
|
|
5871
|
+
if (typeof key !== 'string')
|
|
5872
|
+
return undefined;
|
|
5873
|
+
const trimmed = key.trim();
|
|
5874
|
+
return trimmed ? trimmed : undefined;
|
|
5875
|
+
}
|
|
5876
|
+
generateWidgetKey(widget) {
|
|
5877
|
+
const id = widget.definition?.id;
|
|
5878
|
+
const prefix = typeof id === 'string' && id.trim() ? id.trim() : 'widget';
|
|
5879
|
+
return `${prefix}-${generateId()}`;
|
|
5880
|
+
}
|
|
5881
|
+
linkKey(link) {
|
|
5882
|
+
if (!link)
|
|
5883
|
+
return null;
|
|
5884
|
+
const from = this.endpointKey(link.from);
|
|
5885
|
+
const to = this.endpointKey(link.to);
|
|
5886
|
+
if (!from || !to)
|
|
5887
|
+
return null;
|
|
5888
|
+
return `${from}->${to}`;
|
|
5889
|
+
}
|
|
5890
|
+
endpointKey(endpoint) {
|
|
5891
|
+
if (endpoint.kind === 'component-port') {
|
|
5892
|
+
if (!endpoint.ref.widget || !endpoint.ref.port)
|
|
5893
|
+
return null;
|
|
5894
|
+
return [
|
|
5895
|
+
'widget',
|
|
5896
|
+
endpoint.ref.widget,
|
|
5897
|
+
endpoint.ref.port,
|
|
5898
|
+
endpoint.ref.direction,
|
|
5899
|
+
this.nestedPathKey(endpoint.ref.nestedPath),
|
|
5900
|
+
].filter((part) => part !== '').join('::');
|
|
5901
|
+
}
|
|
5902
|
+
return endpoint.ref.path ? `state:${endpoint.ref.path}::${endpoint.ref.layer || 'values'}` : null;
|
|
5903
|
+
}
|
|
5904
|
+
nestedPathKey(nestedPath) {
|
|
5905
|
+
if (!nestedPath?.length)
|
|
5906
|
+
return '';
|
|
5907
|
+
return `nested:${JSON.stringify(nestedPath.map((segment) => ({
|
|
5908
|
+
kind: segment.kind,
|
|
5909
|
+
id: segment.id,
|
|
5910
|
+
key: segment.key,
|
|
5911
|
+
index: segment.index,
|
|
5912
|
+
componentType: segment.componentType,
|
|
5913
|
+
})))}`;
|
|
5914
|
+
}
|
|
5915
|
+
pickLayoutOptions(options) {
|
|
5916
|
+
if (!options)
|
|
5917
|
+
return undefined;
|
|
5918
|
+
const picked = {};
|
|
5919
|
+
if (typeof options.cols === 'number')
|
|
5920
|
+
picked.cols = options.cols;
|
|
5921
|
+
if (typeof options.rowHeight === 'number')
|
|
5922
|
+
picked.rowHeight = options.rowHeight;
|
|
5923
|
+
if (typeof options.gap === 'number')
|
|
5924
|
+
picked.gap = options.gap;
|
|
5925
|
+
return Object.keys(picked).length ? picked : undefined;
|
|
5926
|
+
}
|
|
5927
|
+
buildComponentCatalog() {
|
|
5928
|
+
if (!this.registry)
|
|
5929
|
+
return [];
|
|
5930
|
+
return this.registry.getAll().map((meta) => ({
|
|
5931
|
+
id: meta.id,
|
|
5932
|
+
friendlyName: meta.friendlyName,
|
|
5933
|
+
description: meta.description,
|
|
5934
|
+
icon: meta.icon,
|
|
5935
|
+
tags: meta.tags,
|
|
5936
|
+
inputs: (meta.inputs || []).map((input) => input.name),
|
|
5937
|
+
outputs: (meta.outputs || []).map((output) => output.name),
|
|
5938
|
+
layoutHints: meta.layoutHints,
|
|
5939
|
+
}));
|
|
5940
|
+
}
|
|
5941
|
+
coerceNumber(value, fallback) {
|
|
5942
|
+
return typeof value === 'number' && !Number.isNaN(value) ? value : fallback;
|
|
5943
|
+
}
|
|
5944
|
+
parsePixelValue(value) {
|
|
5945
|
+
if (typeof value !== 'string')
|
|
5946
|
+
return undefined;
|
|
5947
|
+
const match = value.trim().match(/^(\d+(?:\.\d+)?)px$/);
|
|
5948
|
+
if (!match)
|
|
5949
|
+
return undefined;
|
|
5950
|
+
return Number(match[1]);
|
|
5951
|
+
}
|
|
5952
|
+
clone(value) {
|
|
5953
|
+
if (value == null || typeof value !== 'object')
|
|
5954
|
+
return value;
|
|
5955
|
+
try {
|
|
5956
|
+
return structuredClone(value);
|
|
5957
|
+
}
|
|
5958
|
+
catch {
|
|
5959
|
+
return JSON.parse(JSON.stringify(value));
|
|
5960
|
+
}
|
|
5961
|
+
}
|
|
5962
|
+
}
|
|
5963
|
+
|
|
5964
|
+
class PageBuilderAgenticAuthoringTurnFlow {
|
|
5965
|
+
service;
|
|
5966
|
+
context;
|
|
5967
|
+
mode = 'agentic-authoring';
|
|
5968
|
+
constructor(service, context) {
|
|
5969
|
+
this.service = service;
|
|
5970
|
+
this.context = context;
|
|
5971
|
+
}
|
|
5972
|
+
submit(request) {
|
|
5973
|
+
const prompt = request.prompt?.trim();
|
|
5974
|
+
if (!prompt) {
|
|
5975
|
+
return Promise.resolve({
|
|
5976
|
+
state: 'listening',
|
|
5977
|
+
phase: 'capture',
|
|
5978
|
+
});
|
|
5979
|
+
}
|
|
5980
|
+
if (this.isResourceDiscoveryTool(request)) {
|
|
5981
|
+
return this.handleResourceDiscoveryTool(request, prompt);
|
|
5982
|
+
}
|
|
5983
|
+
if (this.context.enableTurnStream?.() === true && this.service.streamTurn) {
|
|
5984
|
+
return this.submitWithTurnStream(request, prompt);
|
|
5985
|
+
}
|
|
5986
|
+
return this.submitSynchronously(request, prompt);
|
|
5987
|
+
}
|
|
5988
|
+
async submitSynchronously(request, prompt) {
|
|
5989
|
+
try {
|
|
5990
|
+
const authoringContext = this.buildAuthoringContext(request);
|
|
5991
|
+
const componentCapabilities = await this.context.loadComponentCapabilities();
|
|
5992
|
+
const selectedWidgetKey = this.context.selectedWidgetKey();
|
|
5993
|
+
const intentResolution = await firstValueFrom(this.service.resolveIntent(this.buildIntentResolutionRequest(prompt, selectedWidgetKey, componentCapabilities, authoringContext)));
|
|
5994
|
+
const intentAssistantMessage = this.resolveIntentAssistantMessage(intentResolution);
|
|
5995
|
+
if (intentAssistantMessage) {
|
|
5996
|
+
const quickReplies = this.toShellQuickReplies(intentResolution.quickReplies ?? []);
|
|
5997
|
+
const explicitPendingClarification = this.toShellPendingClarification(intentResolution.pendingClarification);
|
|
5998
|
+
const intentClarification = this.resolveIntentClarification(intentResolution);
|
|
5999
|
+
const pendingClarification = explicitPendingClarification
|
|
6000
|
+
?? (intentClarification
|
|
6001
|
+
? this.buildPendingClarificationForNextTurn(request, this.resolveEffectivePrompt(intentResolution, prompt), intentClarification)
|
|
6002
|
+
: null);
|
|
6003
|
+
if (!this.hasPendingClarificationQuestion(pendingClarification) && quickReplies.length === 0) {
|
|
6004
|
+
return {
|
|
6005
|
+
state: 'success',
|
|
6006
|
+
phase: 'summarize',
|
|
6007
|
+
assistantMessage: intentAssistantMessage,
|
|
6008
|
+
quickReplies,
|
|
6009
|
+
canApply: false,
|
|
6010
|
+
statusText: '',
|
|
6011
|
+
errorText: '',
|
|
6012
|
+
preview: null,
|
|
6013
|
+
diagnostics: { intentResolution },
|
|
6014
|
+
};
|
|
6015
|
+
}
|
|
6016
|
+
return {
|
|
6017
|
+
state: 'clarification',
|
|
6018
|
+
phase: 'clarify',
|
|
6019
|
+
assistantMessage: intentAssistantMessage,
|
|
6020
|
+
quickReplies,
|
|
6021
|
+
canApply: false,
|
|
6022
|
+
statusText: '',
|
|
6023
|
+
errorText: '',
|
|
6024
|
+
preview: null,
|
|
6025
|
+
pendingClarification,
|
|
6026
|
+
diagnostics: { intentResolution },
|
|
6027
|
+
};
|
|
6028
|
+
}
|
|
6029
|
+
const clarification = this.resolveIntentClarification(intentResolution);
|
|
6030
|
+
if (clarification) {
|
|
6031
|
+
return {
|
|
6032
|
+
state: 'clarification',
|
|
6033
|
+
phase: 'clarify',
|
|
6034
|
+
assistantMessage: clarification,
|
|
6035
|
+
quickReplies: this.toShellQuickReplies(intentResolution.quickReplies ?? []),
|
|
6036
|
+
canApply: false,
|
|
6037
|
+
statusText: '',
|
|
6038
|
+
errorText: '',
|
|
6039
|
+
preview: null,
|
|
6040
|
+
pendingClarification: this.resolvePendingClarificationForNextTurn(intentResolution, request, this.resolveEffectivePrompt(intentResolution, prompt), clarification),
|
|
6041
|
+
diagnostics: { intentResolution },
|
|
6042
|
+
};
|
|
6043
|
+
}
|
|
6044
|
+
const intentFailure = this.describeIntentResolutionFailure(intentResolution);
|
|
6045
|
+
if (intentFailure) {
|
|
6046
|
+
return {
|
|
6047
|
+
state: 'error',
|
|
6048
|
+
phase: 'contextualize',
|
|
6049
|
+
assistantMessage: intentFailure,
|
|
6050
|
+
canApply: false,
|
|
6051
|
+
statusText: '',
|
|
6052
|
+
errorText: intentFailure,
|
|
6053
|
+
preview: null,
|
|
6054
|
+
diagnostics: { intentResolution },
|
|
6055
|
+
};
|
|
6056
|
+
}
|
|
6057
|
+
const preview = await firstValueFrom(this.service.previewPage({
|
|
6058
|
+
userPrompt: prompt,
|
|
6059
|
+
provider: this.context.provider(),
|
|
6060
|
+
model: this.context.model(),
|
|
6061
|
+
apiKey: this.context.apiKey(),
|
|
6062
|
+
currentPage: this.context.currentPage(),
|
|
6063
|
+
selectedWidgetKey,
|
|
6064
|
+
intentResolution,
|
|
6065
|
+
componentCapabilities,
|
|
6066
|
+
...authoringContext,
|
|
6067
|
+
}));
|
|
6068
|
+
if (!preview.valid) {
|
|
6069
|
+
const message = this.context.describePreviewFailure(preview);
|
|
6070
|
+
return {
|
|
6071
|
+
state: 'error',
|
|
6072
|
+
phase: 'preview',
|
|
6073
|
+
assistantMessage: message,
|
|
6074
|
+
canApply: false,
|
|
6075
|
+
statusText: '',
|
|
6076
|
+
errorText: message,
|
|
6077
|
+
preview: null,
|
|
6078
|
+
diagnostics: { intentResolution, preview },
|
|
6079
|
+
};
|
|
6080
|
+
}
|
|
6081
|
+
const applied = await this.context.applyLocalPreview(preview);
|
|
6082
|
+
if (!applied.success) {
|
|
6083
|
+
const message = applied.error || this.context.tx('agentic.errors.applyLocal', 'Preview could not be applied.');
|
|
6084
|
+
return {
|
|
6085
|
+
state: 'error',
|
|
6086
|
+
phase: 'preview',
|
|
6087
|
+
assistantMessage: message,
|
|
6088
|
+
canApply: false,
|
|
6089
|
+
statusText: '',
|
|
6090
|
+
errorText: message,
|
|
6091
|
+
preview: null,
|
|
6092
|
+
diagnostics: { intentResolution, preview },
|
|
6093
|
+
};
|
|
6094
|
+
}
|
|
6095
|
+
const status = this.context.describePreviewStatus(preview);
|
|
6096
|
+
return {
|
|
6097
|
+
state: 'review',
|
|
6098
|
+
phase: 'review',
|
|
6099
|
+
assistantMessage: status,
|
|
6100
|
+
quickReplies: [],
|
|
6101
|
+
canApply: true,
|
|
6102
|
+
statusText: status,
|
|
6103
|
+
errorText: '',
|
|
6104
|
+
preview,
|
|
6105
|
+
diagnostics: { intentResolution },
|
|
6106
|
+
};
|
|
6107
|
+
}
|
|
6108
|
+
catch (error) {
|
|
6109
|
+
const message = this.context.describeError(error);
|
|
6110
|
+
return {
|
|
6111
|
+
state: 'error',
|
|
6112
|
+
phase: 'contextualize',
|
|
6113
|
+
assistantMessage: message,
|
|
6114
|
+
canApply: false,
|
|
6115
|
+
statusText: '',
|
|
6116
|
+
errorText: message,
|
|
6117
|
+
preview: null,
|
|
6118
|
+
};
|
|
6119
|
+
}
|
|
6120
|
+
}
|
|
6121
|
+
submitWithTurnStream(request, prompt) {
|
|
6122
|
+
return from(this.buildTurnStreamRequest(request, prompt)).pipe(concatMap((streamRequest) => this.service.streamTurn(streamRequest)), concatMap((event) => from(this.toTurnResultFromStreamEvent(event))), catchError((error) => this.shouldFallbackFromTurnStreamError(error)
|
|
6123
|
+
? from(this.submitSynchronously(request, prompt))
|
|
6124
|
+
: of(this.toTurnStreamTransportErrorResult(error))));
|
|
6125
|
+
}
|
|
6126
|
+
async cancel() {
|
|
6127
|
+
return {
|
|
6128
|
+
state: 'listening',
|
|
6129
|
+
phase: 'capture',
|
|
6130
|
+
assistantMessage: this.context.tx('agentic.status.cancelled', 'Request cancelled.'),
|
|
6131
|
+
quickReplies: [],
|
|
6132
|
+
canApply: false,
|
|
6133
|
+
statusText: '',
|
|
6134
|
+
errorText: '',
|
|
6135
|
+
preview: null,
|
|
6136
|
+
pendingPatch: null,
|
|
6137
|
+
};
|
|
6138
|
+
}
|
|
6139
|
+
async buildTurnStreamRequest(request, prompt) {
|
|
6140
|
+
const componentCapabilities = await this.context.loadComponentCapabilities();
|
|
6141
|
+
const selectedWidgetKey = this.context.selectedWidgetKey();
|
|
6142
|
+
return {
|
|
6143
|
+
userPrompt: prompt,
|
|
6144
|
+
targetApp: this.context.targetApp,
|
|
6145
|
+
targetComponentId: this.context.targetComponentId,
|
|
6146
|
+
currentRoute: null,
|
|
6147
|
+
currentPage: this.context.currentPage(),
|
|
6148
|
+
selectedWidgetKey,
|
|
6149
|
+
provider: this.context.provider(),
|
|
6150
|
+
model: this.context.model(),
|
|
6151
|
+
apiKey: this.context.apiKey(),
|
|
6152
|
+
componentCapabilities,
|
|
6153
|
+
...this.buildAuthoringContext(request),
|
|
6154
|
+
};
|
|
6155
|
+
}
|
|
6156
|
+
async toTurnResultFromStreamEvent(event) {
|
|
6157
|
+
const payload = this.toJsonObject(event.payload) ?? {};
|
|
6158
|
+
if (event.type === 'result') {
|
|
6159
|
+
return this.toResultTurnFromStreamPayload(payload);
|
|
6160
|
+
}
|
|
6161
|
+
if (event.type === 'error') {
|
|
6162
|
+
const message = this.describeStreamError(payload);
|
|
6163
|
+
return {
|
|
6164
|
+
state: 'error',
|
|
6165
|
+
phase: 'contextualize',
|
|
6166
|
+
assistantMessage: message,
|
|
6167
|
+
canApply: false,
|
|
6168
|
+
statusText: '',
|
|
6169
|
+
errorText: message,
|
|
6170
|
+
preview: null,
|
|
6171
|
+
diagnostics: { streamError: payload },
|
|
6172
|
+
};
|
|
6173
|
+
}
|
|
6174
|
+
if (event.type === 'cancelled') {
|
|
6175
|
+
return {
|
|
6176
|
+
state: 'listening',
|
|
6177
|
+
phase: 'capture',
|
|
6178
|
+
assistantMessage: this.context.tx('agentic.status.cancelled', 'Request cancelled.'),
|
|
6179
|
+
quickReplies: [],
|
|
6180
|
+
canApply: false,
|
|
6181
|
+
statusText: '',
|
|
6182
|
+
errorText: '',
|
|
6183
|
+
preview: null,
|
|
6184
|
+
pendingPatch: null,
|
|
6185
|
+
};
|
|
6186
|
+
}
|
|
6187
|
+
return {
|
|
6188
|
+
state: 'processing',
|
|
6189
|
+
phase: this.phaseForStreamPayload(payload),
|
|
6190
|
+
assistantMessage: undefined,
|
|
6191
|
+
canApply: false,
|
|
6192
|
+
statusText: this.statusForStreamPayload(payload),
|
|
6193
|
+
errorText: '',
|
|
6194
|
+
preview: null,
|
|
6195
|
+
};
|
|
6196
|
+
}
|
|
6197
|
+
async toResultTurnFromStreamPayload(payload) {
|
|
6198
|
+
const intentResolution = payload['intentResolution'];
|
|
6199
|
+
const preview = payload['preview'];
|
|
6200
|
+
if (!intentResolution) {
|
|
6201
|
+
const message = this.context.tx('agentic.errors.intentResolution', 'Intent could not be resolved.');
|
|
6202
|
+
return {
|
|
6203
|
+
state: 'error',
|
|
6204
|
+
phase: 'contextualize',
|
|
6205
|
+
assistantMessage: message,
|
|
6206
|
+
canApply: false,
|
|
6207
|
+
statusText: '',
|
|
6208
|
+
errorText: message,
|
|
6209
|
+
preview: null,
|
|
6210
|
+
};
|
|
6211
|
+
}
|
|
6212
|
+
const assistantMessage = this.readString(payload, 'assistantMessage')
|
|
6213
|
+
|| this.resolveIntentAssistantMessage(intentResolution)
|
|
6214
|
+
|| (preview ? this.context.describePreviewStatus(preview) : '');
|
|
6215
|
+
const quickReplies = Array.isArray(payload['quickReplies'])
|
|
6216
|
+
? this.toShellQuickReplies(payload['quickReplies'])
|
|
6217
|
+
: [];
|
|
6218
|
+
const canApply = payload['canApply'] === true && !!preview?.valid;
|
|
6219
|
+
if (!canApply) {
|
|
6220
|
+
const pendingClarification = this.toShellPendingClarification(intentResolution?.pendingClarification);
|
|
6221
|
+
const requiresChoice = quickReplies.length > 0;
|
|
6222
|
+
return {
|
|
6223
|
+
state: pendingClarification || requiresChoice ? 'clarification' : 'success',
|
|
6224
|
+
phase: pendingClarification || requiresChoice ? 'clarify' : 'summarize',
|
|
6225
|
+
assistantMessage,
|
|
6226
|
+
quickReplies,
|
|
6227
|
+
canApply: false,
|
|
6228
|
+
statusText: '',
|
|
6229
|
+
errorText: '',
|
|
6230
|
+
preview: null,
|
|
6231
|
+
pendingClarification,
|
|
6232
|
+
diagnostics: { intentResolution, preview },
|
|
6233
|
+
};
|
|
6234
|
+
}
|
|
6235
|
+
const applied = await this.context.applyLocalPreview(preview);
|
|
6236
|
+
if (!applied.success) {
|
|
6237
|
+
const message = applied.error || this.context.tx('agentic.errors.applyLocal', 'Preview could not be applied.');
|
|
6238
|
+
return {
|
|
6239
|
+
state: 'error',
|
|
6240
|
+
phase: 'preview',
|
|
6241
|
+
assistantMessage: message,
|
|
6242
|
+
canApply: false,
|
|
6243
|
+
statusText: '',
|
|
6244
|
+
errorText: message,
|
|
6245
|
+
preview: null,
|
|
6246
|
+
diagnostics: { intentResolution, preview },
|
|
6247
|
+
};
|
|
6248
|
+
}
|
|
6249
|
+
const status = assistantMessage || this.context.describePreviewStatus(preview);
|
|
6250
|
+
return {
|
|
6251
|
+
state: 'review',
|
|
6252
|
+
phase: 'review',
|
|
6253
|
+
assistantMessage: status,
|
|
6254
|
+
quickReplies: [],
|
|
6255
|
+
canApply: true,
|
|
6256
|
+
statusText: status,
|
|
6257
|
+
errorText: '',
|
|
6258
|
+
preview,
|
|
6259
|
+
diagnostics: { intentResolution, preview },
|
|
6260
|
+
};
|
|
6261
|
+
}
|
|
6262
|
+
phaseForStreamPayload(payload) {
|
|
6263
|
+
const phase = this.readString(payload, 'phase');
|
|
6264
|
+
if (phase === 'intent.resolve')
|
|
6265
|
+
return 'contextualize';
|
|
6266
|
+
if (phase === 'resource.discovery')
|
|
6267
|
+
return 'contextualize';
|
|
6268
|
+
if (phase.startsWith('preview.'))
|
|
6269
|
+
return 'preview';
|
|
6270
|
+
if (phase === 'review')
|
|
6271
|
+
return 'review';
|
|
6272
|
+
return 'contextualize';
|
|
6273
|
+
}
|
|
6274
|
+
statusForStreamPayload(payload) {
|
|
6275
|
+
const phase = this.readString(payload, 'phase');
|
|
6276
|
+
switch (phase) {
|
|
6277
|
+
case 'context.bundle':
|
|
6278
|
+
return this.context.tx('agentic.status.contextBundle', 'Preparing context...');
|
|
6279
|
+
case 'intent.resolve':
|
|
6280
|
+
if (this.isSecondPassStreamPayload(payload)) {
|
|
6281
|
+
return this.context.tx('agentic.status.refinedCandidates', 'Reviewing the retrieved resources with the AI...');
|
|
6282
|
+
}
|
|
6283
|
+
return this.context.tx('agentic.status.resolvingIntent', 'Resolving intent...');
|
|
6284
|
+
case 'resource.discovery':
|
|
6285
|
+
if (this.isBackendResourceDiscoveryPayload(payload)) {
|
|
6286
|
+
return this.context.tx('agentic.status.resourceDiscoveryBackend', 'Found API resources in the backend catalog.');
|
|
6287
|
+
}
|
|
6288
|
+
return this.context.tx('agentic.status.resourceDiscovery', 'Finding API resources...');
|
|
6289
|
+
case 'preview.plan':
|
|
6290
|
+
return this.context.tx('agentic.status.previewing', 'Generating preview...');
|
|
6291
|
+
case 'preview.compile':
|
|
6292
|
+
return this.context.tx('agentic.status.previewCompile', 'Compiling preview...');
|
|
6293
|
+
default:
|
|
6294
|
+
return this.readString(payload, 'summary') || this.readString(payload, 'message');
|
|
6295
|
+
}
|
|
6296
|
+
}
|
|
6297
|
+
isBackendResourceDiscoveryPayload(payload) {
|
|
6298
|
+
const diagnostics = this.toJsonObject(payload['diagnostics']);
|
|
6299
|
+
return diagnostics?.['source'] === 'backend-resource-catalog';
|
|
6300
|
+
}
|
|
6301
|
+
isSecondPassStreamPayload(payload) {
|
|
6302
|
+
const diagnostics = this.toJsonObject(payload['diagnostics']);
|
|
6303
|
+
return diagnostics?.['secondPass'] === true;
|
|
6304
|
+
}
|
|
6305
|
+
describeStreamError(payload) {
|
|
6306
|
+
const code = this.readString(payload, 'code');
|
|
6307
|
+
if (code === 'agentic-authoring-timeout') {
|
|
6308
|
+
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.');
|
|
6309
|
+
}
|
|
6310
|
+
if (code === 'agentic-authoring-processing-failed') {
|
|
6311
|
+
return this.context.tx('agentic.errors.streamProcessing', 'The assistant could not finish this authoring request. Try again or ask support to review the diagnostics.');
|
|
6312
|
+
}
|
|
6313
|
+
return this.readString(payload, 'assistantMessage')
|
|
6314
|
+
|| this.context.tx('agentic.errors.generic', 'AI authoring failed.');
|
|
6315
|
+
}
|
|
6316
|
+
toTurnStreamTransportErrorResult(error) {
|
|
6317
|
+
const message = this.isTurnStreamConnectionError(error)
|
|
6318
|
+
? this.context.tx('agentic.errors.streamConnection', 'The assistant stream was interrupted before the turn finished. Try again or ask support to check the stream connection.')
|
|
6319
|
+
: this.context.describeError(error);
|
|
6320
|
+
return {
|
|
6321
|
+
state: 'error',
|
|
6322
|
+
phase: 'contextualize',
|
|
6323
|
+
assistantMessage: message,
|
|
6324
|
+
canApply: false,
|
|
6325
|
+
statusText: '',
|
|
6326
|
+
errorText: message,
|
|
6327
|
+
preview: null,
|
|
6328
|
+
diagnostics: { streamTransportError: this.toJsonObject(error) ?? { reason: 'stream-transport-error' } },
|
|
6329
|
+
};
|
|
6330
|
+
}
|
|
6331
|
+
shouldFallbackFromTurnStreamError(error) {
|
|
6332
|
+
if (this.isTurnStreamConnectionError(error)) {
|
|
6333
|
+
return false;
|
|
6334
|
+
}
|
|
6335
|
+
const status = this.readErrorStatus(error);
|
|
6336
|
+
if (status === 401 || status === 403) {
|
|
6337
|
+
return false;
|
|
6338
|
+
}
|
|
6339
|
+
return status === 404 || status === 501 || status === 503;
|
|
6340
|
+
}
|
|
6341
|
+
isTurnStreamConnectionError(error) {
|
|
6342
|
+
return this.toJsonObject(error)?.['praxisAgenticTurnStreamConnectionError'] === true;
|
|
6343
|
+
}
|
|
6344
|
+
readErrorStatus(error) {
|
|
6345
|
+
const status = this.toJsonObject(error)?.['status'];
|
|
6346
|
+
return typeof status === 'number' && Number.isFinite(status) ? status : null;
|
|
6347
|
+
}
|
|
6348
|
+
async handleResourceDiscoveryTool(request, prompt) {
|
|
6349
|
+
const contextHints = this.toJsonObject(request.action?.contextHints) ?? {};
|
|
6350
|
+
const retrievalQuery = this.readString(contextHints, 'retrievalQuery') || prompt;
|
|
6351
|
+
const artifactKind = this.readString(contextHints, 'artifactKind') || null;
|
|
6352
|
+
const limit = this.readNumber(contextHints, 'limit');
|
|
6353
|
+
const result = await firstValueFrom(this.service.searchResourceCandidates({
|
|
6354
|
+
retrievalQuery,
|
|
6355
|
+
userPrompt: prompt,
|
|
6356
|
+
artifactKind,
|
|
6357
|
+
limit,
|
|
6358
|
+
}));
|
|
6359
|
+
const quickReplies = result.quickReplies?.length
|
|
6360
|
+
? this.toShellQuickReplies(result.quickReplies)
|
|
6361
|
+
: this.toResourceCandidateQuickReplies(result.candidates, result.artifactKind);
|
|
6362
|
+
const assistantMessage = result.assistantMessage?.trim()
|
|
6363
|
+
|| (quickReplies.length
|
|
6364
|
+
? this.context.tx('agentic.resourceDiscovery.found', 'I found APIs that can feed this screen. Choose one before generating the preview.')
|
|
6365
|
+
: this.context.tx('agentic.resourceDiscovery.empty', 'I did not find a matching API yet. Describe the business data this screen should use.'));
|
|
6366
|
+
const intentResult = await this.resolveIntentAfterResourceDiscovery(request, request.pendingClarification?.sourcePrompt || prompt, contextHints, result, assistantMessage, quickReplies);
|
|
6367
|
+
if (intentResult) {
|
|
6368
|
+
return intentResult;
|
|
6369
|
+
}
|
|
6370
|
+
return {
|
|
6371
|
+
state: 'clarification',
|
|
6372
|
+
phase: 'clarify',
|
|
6373
|
+
assistantMessage,
|
|
6374
|
+
quickReplies,
|
|
6375
|
+
canApply: false,
|
|
6376
|
+
statusText: '',
|
|
6377
|
+
errorText: '',
|
|
6378
|
+
preview: null,
|
|
6379
|
+
pendingClarification: {
|
|
6380
|
+
sourcePrompt: request.pendingClarification?.sourcePrompt || prompt,
|
|
6381
|
+
assistantMessage,
|
|
6382
|
+
questions: [
|
|
6383
|
+
{
|
|
6384
|
+
id: 'resource',
|
|
6385
|
+
type: 'text',
|
|
6386
|
+
label: assistantMessage,
|
|
6387
|
+
},
|
|
6388
|
+
],
|
|
6389
|
+
clientTurnId: request.clientTurnId,
|
|
6390
|
+
diagnostics: {
|
|
6391
|
+
resourceDiscovery: {
|
|
6392
|
+
tool: result.tool,
|
|
6393
|
+
retrievalQuery: result.retrievalQuery,
|
|
6394
|
+
artifactKind: result.artifactKind,
|
|
6395
|
+
warnings: result.warnings,
|
|
6396
|
+
},
|
|
6397
|
+
},
|
|
6398
|
+
},
|
|
6399
|
+
diagnostics: { resourceDiscovery: result },
|
|
6400
|
+
};
|
|
6401
|
+
}
|
|
6402
|
+
async resolveIntentAfterResourceDiscovery(request, prompt, contextHints, result, fallbackAssistantMessage, fallbackQuickReplies) {
|
|
6403
|
+
if (!result.valid || !result.candidates?.length) {
|
|
6404
|
+
return null;
|
|
6405
|
+
}
|
|
6406
|
+
const componentCapabilities = await this.context.loadComponentCapabilities();
|
|
6407
|
+
const authoringContext = this.buildAuthoringContext(request);
|
|
6408
|
+
const intentResolution = await firstValueFrom(this.service.resolveIntent(this.buildIntentResolutionRequest(prompt, this.context.selectedWidgetKey(), componentCapabilities, {
|
|
6409
|
+
...authoringContext,
|
|
6410
|
+
contextHints: this.resourceDiscoveryContextHints(contextHints, result),
|
|
6411
|
+
})));
|
|
6412
|
+
const assistantMessage = this.resolveIntentAssistantMessage(intentResolution)
|
|
6413
|
+
|| this.resolveIntentClarification(intentResolution)
|
|
6414
|
+
|| fallbackAssistantMessage;
|
|
6415
|
+
const quickReplies = intentResolution.quickReplies?.length
|
|
6416
|
+
? this.toShellQuickReplies(intentResolution.quickReplies)
|
|
6417
|
+
: fallbackQuickReplies;
|
|
6418
|
+
const explicitPendingClarification = this.toShellPendingClarification(intentResolution.pendingClarification);
|
|
6419
|
+
const pendingClarification = explicitPendingClarification
|
|
6420
|
+
?? this.buildPendingClarificationForNextTurn(request, this.resolveEffectivePrompt(intentResolution, prompt), assistantMessage);
|
|
6421
|
+
if (!assistantMessage && quickReplies.length === 0) {
|
|
6422
|
+
return null;
|
|
6423
|
+
}
|
|
6424
|
+
return {
|
|
6425
|
+
state: quickReplies.length > 0 || this.hasPendingClarificationQuestion(pendingClarification)
|
|
6426
|
+
? 'clarification'
|
|
6427
|
+
: 'success',
|
|
6428
|
+
phase: quickReplies.length > 0 || this.hasPendingClarificationQuestion(pendingClarification)
|
|
6429
|
+
? 'clarify'
|
|
6430
|
+
: 'summarize',
|
|
6431
|
+
assistantMessage,
|
|
6432
|
+
quickReplies,
|
|
6433
|
+
canApply: false,
|
|
6434
|
+
statusText: '',
|
|
6435
|
+
errorText: '',
|
|
6436
|
+
preview: null,
|
|
6437
|
+
pendingClarification,
|
|
6438
|
+
diagnostics: { resourceDiscovery: result, intentResolution },
|
|
6439
|
+
};
|
|
6440
|
+
}
|
|
6441
|
+
resourceDiscoveryContextHints(contextHints, result) {
|
|
6442
|
+
const { tool: _tool, ...baseContextHints } = contextHints;
|
|
6443
|
+
return {
|
|
6444
|
+
...baseContextHints,
|
|
6445
|
+
resourceDiscovery: {
|
|
6446
|
+
tool: result.tool,
|
|
6447
|
+
retrievalQuery: result.retrievalQuery,
|
|
6448
|
+
artifactKind: result.artifactKind,
|
|
6449
|
+
assistantMessage: result.assistantMessage ?? null,
|
|
6450
|
+
candidates: result.candidates.map((candidate) => ({
|
|
6451
|
+
resourcePath: candidate.resourcePath,
|
|
6452
|
+
operation: candidate.operation,
|
|
6453
|
+
schemaUrl: candidate.schemaUrl,
|
|
6454
|
+
submitUrl: candidate.submitUrl,
|
|
6455
|
+
submitMethod: candidate.submitMethod,
|
|
6456
|
+
score: candidate.score,
|
|
6457
|
+
reason: candidate.reason,
|
|
6458
|
+
evidence: candidate.evidence,
|
|
6459
|
+
})),
|
|
6460
|
+
quickReplies: (result.quickReplies ?? []).map((reply) => ({
|
|
6461
|
+
id: reply.id,
|
|
6462
|
+
kind: reply.kind,
|
|
6463
|
+
label: reply.label,
|
|
6464
|
+
prompt: reply.prompt,
|
|
6465
|
+
description: reply.description ?? null,
|
|
6466
|
+
icon: reply.icon ?? null,
|
|
6467
|
+
tone: reply.tone ?? null,
|
|
6468
|
+
contextHints: this.toJsonObject(reply.contextHints) ?? null,
|
|
6469
|
+
})),
|
|
6470
|
+
warnings: result.warnings,
|
|
6471
|
+
},
|
|
6472
|
+
};
|
|
6473
|
+
}
|
|
6474
|
+
isResourceDiscoveryTool(request) {
|
|
6475
|
+
const contextHints = this.toJsonObject(request.action?.contextHints);
|
|
6476
|
+
return this.readString(contextHints, 'tool') === 'searchApiResources';
|
|
6477
|
+
}
|
|
6478
|
+
toResourceCandidateQuickReplies(candidates, artifactKind) {
|
|
6479
|
+
return candidates
|
|
6480
|
+
.filter((candidate) => !!candidate.resourcePath?.trim())
|
|
6481
|
+
.map((candidate) => {
|
|
6482
|
+
const resourcePath = candidate.resourcePath.trim();
|
|
6483
|
+
const submitUrl = candidate.submitUrl?.trim() || resourcePath;
|
|
6484
|
+
return {
|
|
6485
|
+
id: this.resourceCandidateId(resourcePath),
|
|
6486
|
+
kind: 'suggestion',
|
|
6487
|
+
label: this.resourceCandidateLabel(resourcePath),
|
|
6488
|
+
prompt: this.formatResourceCandidatePrompt(resourcePath),
|
|
6489
|
+
description: this.resourceCandidateDescription(candidate),
|
|
6490
|
+
icon: 'dataset',
|
|
6491
|
+
tone: 'resource',
|
|
6492
|
+
contextHints: {
|
|
6493
|
+
resourcePath,
|
|
6494
|
+
submitUrl,
|
|
6495
|
+
operation: candidate.operation,
|
|
6496
|
+
schemaUrl: candidate.schemaUrl,
|
|
6497
|
+
submitMethod: candidate.submitMethod,
|
|
6498
|
+
artifactKind,
|
|
6499
|
+
},
|
|
6500
|
+
};
|
|
6501
|
+
});
|
|
6502
|
+
}
|
|
6503
|
+
formatResourceCandidatePrompt(resourcePath) {
|
|
6504
|
+
return this.context
|
|
6505
|
+
.tx('agentic.resourceDiscovery.useResource', 'Use {resourcePath}')
|
|
6506
|
+
.replace('{resourcePath}', resourcePath);
|
|
6507
|
+
}
|
|
6508
|
+
resourceCandidateId(resourcePath) {
|
|
6509
|
+
const slug = resourcePath
|
|
6510
|
+
.toLowerCase()
|
|
6511
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
6512
|
+
.replace(/^-+|-+$/g, '');
|
|
6513
|
+
return slug ? `resource-${slug}` : 'resource-candidate';
|
|
6514
|
+
}
|
|
6515
|
+
resourceCandidateLabel(resourcePath) {
|
|
6516
|
+
const segment = resourcePath.split('/').filter((part) => !!part).pop() || resourcePath;
|
|
6517
|
+
const label = segment
|
|
6518
|
+
.replace(/[-_]+/g, ' ')
|
|
6519
|
+
.replace(/\s+/g, ' ')
|
|
6520
|
+
.trim();
|
|
6521
|
+
return label
|
|
6522
|
+
? label.charAt(0).toUpperCase() + label.slice(1)
|
|
6523
|
+
: resourcePath;
|
|
6524
|
+
}
|
|
6525
|
+
resourceCandidateDescription(candidate) {
|
|
6526
|
+
const method = candidate.submitMethod?.trim();
|
|
6527
|
+
const url = candidate.submitUrl?.trim();
|
|
6528
|
+
return method && url ? `${method} ${url}` : url || undefined;
|
|
6529
|
+
}
|
|
6530
|
+
resolveIntentAssistantMessage(intentResolution) {
|
|
6531
|
+
if (this.isExecutableIntent(intentResolution)) {
|
|
6532
|
+
return null;
|
|
6533
|
+
}
|
|
6534
|
+
const message = intentResolution.assistantMessage?.trim();
|
|
6535
|
+
return message || null;
|
|
6536
|
+
}
|
|
6537
|
+
isExecutableIntent(intentResolution) {
|
|
6538
|
+
const operationKind = intentResolution.operationKind;
|
|
6539
|
+
const artifactKind = intentResolution.artifactKind;
|
|
6540
|
+
return !!intentResolution.valid
|
|
6541
|
+
&& intentResolution.gate?.status === 'eligible'
|
|
6542
|
+
&& !!intentResolution.selectedCandidate
|
|
6543
|
+
&& (artifactKind === 'form' || artifactKind === 'dashboard' || artifactKind === 'table' || artifactKind === 'page')
|
|
6544
|
+
&& (operationKind === 'create' || operationKind === 'modify' || operationKind === 'remove' || operationKind === 'compose');
|
|
6545
|
+
}
|
|
6546
|
+
resolveIntentClarification(intentResolution) {
|
|
6547
|
+
const questions = intentResolution.clarificationQuestions?.filter((question) => !!question) ?? [];
|
|
6548
|
+
if (!intentResolution.valid && questions.length) {
|
|
6549
|
+
return questions.join(' ');
|
|
6550
|
+
}
|
|
6551
|
+
return null;
|
|
6552
|
+
}
|
|
6553
|
+
describeIntentResolutionFailure(intentResolution) {
|
|
6554
|
+
if (this.isExecutableIntent(intentResolution)) {
|
|
6555
|
+
return null;
|
|
6556
|
+
}
|
|
6557
|
+
const questions = intentResolution.clarificationQuestions?.filter((question) => !!question) ?? [];
|
|
6558
|
+
if (questions.length) {
|
|
6559
|
+
return questions.join(' ');
|
|
6560
|
+
}
|
|
6561
|
+
const failures = intentResolution.failureCodes?.filter((code) => !!code) ?? [];
|
|
6562
|
+
if (failures.length) {
|
|
6563
|
+
return `${this.context.tx('agentic.errors.intentResolution', 'Intent could not be resolved.')}: ${failures.join(', ')}`;
|
|
6564
|
+
}
|
|
6565
|
+
const gateMessages = intentResolution.gate?.messages?.filter((message) => !!message) ?? [];
|
|
6566
|
+
if (gateMessages.length) {
|
|
6567
|
+
return gateMessages.join(' ');
|
|
6568
|
+
}
|
|
6569
|
+
return this.context.tx('agentic.errors.intentResolution', 'Intent could not be resolved.');
|
|
6570
|
+
}
|
|
6571
|
+
toShellQuickReplies(quickReplies) {
|
|
6572
|
+
return quickReplies
|
|
6573
|
+
.filter((reply) => !!reply.id && !!reply.label && (!!reply.prompt || reply.kind === 'cancel'))
|
|
6574
|
+
.map((reply) => ({
|
|
6575
|
+
id: reply.id,
|
|
6576
|
+
kind: reply.kind,
|
|
6577
|
+
label: reply.label,
|
|
6578
|
+
prompt: reply.prompt,
|
|
6579
|
+
description: reply.description,
|
|
6580
|
+
icon: reply.icon,
|
|
6581
|
+
tone: reply.tone,
|
|
6582
|
+
contextHints: this.toJsonObject(reply.contextHints),
|
|
6583
|
+
}));
|
|
6584
|
+
}
|
|
6585
|
+
buildPendingClarificationForNextTurn(request, sourcePrompt, clarification) {
|
|
6586
|
+
return {
|
|
6587
|
+
sourcePrompt,
|
|
6588
|
+
assistantMessage: clarification,
|
|
6589
|
+
questions: [
|
|
6590
|
+
{
|
|
6591
|
+
id: 'clarification',
|
|
6592
|
+
type: 'text',
|
|
6593
|
+
label: clarification,
|
|
6594
|
+
},
|
|
6595
|
+
],
|
|
6596
|
+
clientTurnId: request.clientTurnId,
|
|
6597
|
+
};
|
|
6598
|
+
}
|
|
6599
|
+
resolvePendingClarificationForNextTurn(intentResolution, request, fallbackSourcePrompt, fallbackClarification) {
|
|
6600
|
+
return this.toShellPendingClarification(intentResolution.pendingClarification)
|
|
6601
|
+
?? this.buildPendingClarificationForNextTurn(request, fallbackSourcePrompt, fallbackClarification);
|
|
6602
|
+
}
|
|
6603
|
+
toShellPendingClarification(pending) {
|
|
6604
|
+
const sourcePrompt = pending?.sourcePrompt?.trim();
|
|
6605
|
+
if (!sourcePrompt) {
|
|
6606
|
+
return null;
|
|
6607
|
+
}
|
|
6608
|
+
const questionLabels = (pending?.questions ?? [])
|
|
6609
|
+
.map((question) => question?.trim())
|
|
6610
|
+
.filter((question) => !!question);
|
|
6611
|
+
const assistantMessage = pending?.assistantMessage?.trim() || questionLabels[0] || '';
|
|
6612
|
+
const questions = questionLabels.length
|
|
6613
|
+
? questionLabels.map((label, index) => ({
|
|
6614
|
+
id: `clarification-${index + 1}`,
|
|
6615
|
+
type: 'text',
|
|
6616
|
+
label,
|
|
6617
|
+
}))
|
|
6618
|
+
: assistantMessage
|
|
6619
|
+
? [{
|
|
6620
|
+
id: 'clarification',
|
|
6621
|
+
type: 'text',
|
|
6622
|
+
label: assistantMessage,
|
|
6623
|
+
}]
|
|
6624
|
+
: [];
|
|
6625
|
+
return {
|
|
6626
|
+
sourcePrompt,
|
|
6627
|
+
assistantMessage,
|
|
6628
|
+
questions,
|
|
6629
|
+
clientTurnId: pending?.clientTurnId ?? undefined,
|
|
6630
|
+
diagnostics: this.toJsonObject(pending?.diagnostics) ?? undefined,
|
|
6631
|
+
};
|
|
6632
|
+
}
|
|
6633
|
+
hasPendingClarificationQuestion(pending) {
|
|
6634
|
+
return !!pending?.sourcePrompt?.trim() && pending.questions.some((question) => !!question.label?.trim());
|
|
6635
|
+
}
|
|
6636
|
+
resolveEffectivePrompt(intentResolution, fallbackPrompt) {
|
|
6637
|
+
return intentResolution.effectivePrompt?.trim() || fallbackPrompt;
|
|
6638
|
+
}
|
|
6639
|
+
buildAuthoringContext(request) {
|
|
6640
|
+
const contextHints = this.buildContextHints(request);
|
|
6641
|
+
return {
|
|
6642
|
+
sessionId: request.sessionId,
|
|
6643
|
+
clientTurnId: request.clientTurnId,
|
|
6644
|
+
conversationMessages: this.toConversationMessages(request.messages ?? []),
|
|
6645
|
+
pendingClarification: this.toPendingClarification(request.pendingClarification),
|
|
6646
|
+
attachmentSummaries: this.toAttachmentSummaries(request.attachments ?? []),
|
|
6647
|
+
contextHints,
|
|
6648
|
+
};
|
|
6649
|
+
}
|
|
6650
|
+
buildIntentResolutionRequest(prompt, selectedWidgetKey, componentCapabilities, authoringContext) {
|
|
6651
|
+
return {
|
|
6652
|
+
userPrompt: prompt,
|
|
6653
|
+
targetApp: this.context.targetApp,
|
|
6654
|
+
targetComponentId: this.context.targetComponentId,
|
|
6655
|
+
currentPage: this.context.currentPage(),
|
|
6656
|
+
selectedWidgetKey,
|
|
6657
|
+
provider: this.context.provider(),
|
|
6658
|
+
model: this.context.model(),
|
|
6659
|
+
apiKey: this.context.apiKey(),
|
|
6660
|
+
componentCapabilities,
|
|
6661
|
+
...authoringContext,
|
|
6662
|
+
};
|
|
6663
|
+
}
|
|
6664
|
+
buildContextHints(request) {
|
|
6665
|
+
const base = this.toJsonObject(request.action?.contextHints)
|
|
6666
|
+
?? this.toJsonObject(request.contextHints);
|
|
6667
|
+
const includeLlmDiagnostics = this.context.includeLlmDiagnostics?.() === true;
|
|
6668
|
+
if (!includeLlmDiagnostics) {
|
|
6669
|
+
return base ?? undefined;
|
|
6670
|
+
}
|
|
6671
|
+
return {
|
|
6672
|
+
...(base ?? {}),
|
|
6673
|
+
includeLlmDiagnostics: true,
|
|
6674
|
+
};
|
|
6675
|
+
}
|
|
6676
|
+
toAttachmentSummaries(attachments) {
|
|
6677
|
+
return attachments.map((attachment) => ({
|
|
6678
|
+
id: attachment.id,
|
|
6679
|
+
name: attachment.name,
|
|
6680
|
+
kind: attachment.kind,
|
|
6681
|
+
mimeType: attachment.mimeType ?? null,
|
|
6682
|
+
sizeBytes: attachment.sizeBytes ?? null,
|
|
6683
|
+
source: attachment.source ?? null,
|
|
6684
|
+
hasPreview: !!attachment.previewUrl,
|
|
6685
|
+
}));
|
|
6686
|
+
}
|
|
6687
|
+
toConversationMessages(messages) {
|
|
6688
|
+
return messages
|
|
6689
|
+
.filter((message) => !!message.text?.trim() && this.isAuthoringConversationRole(message.role))
|
|
6690
|
+
.slice(-12)
|
|
6691
|
+
.flatMap((message) => {
|
|
6692
|
+
if (!this.isAuthoringConversationRole(message.role)) {
|
|
6693
|
+
return [];
|
|
6694
|
+
}
|
|
6695
|
+
return [{
|
|
6696
|
+
id: message.id,
|
|
6697
|
+
role: message.role,
|
|
6698
|
+
text: message.text,
|
|
6699
|
+
}];
|
|
6700
|
+
});
|
|
6701
|
+
}
|
|
6702
|
+
toPendingClarification(pending) {
|
|
6703
|
+
if (!pending?.sourcePrompt) {
|
|
6704
|
+
return null;
|
|
6705
|
+
}
|
|
6706
|
+
return {
|
|
6707
|
+
sourcePrompt: pending.sourcePrompt,
|
|
6708
|
+
questions: pending.questions.map((question) => question.label),
|
|
6709
|
+
assistantMessage: pending.assistantMessage,
|
|
6710
|
+
clientTurnId: pending.clientTurnId,
|
|
6711
|
+
diagnostics: this.toJsonObject(pending.diagnostics),
|
|
6712
|
+
};
|
|
6713
|
+
}
|
|
6714
|
+
isAuthoringConversationRole(role) {
|
|
6715
|
+
return role === 'user' || role === 'assistant' || role === 'system';
|
|
6716
|
+
}
|
|
6717
|
+
toJsonObject(value) {
|
|
6718
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
6719
|
+
? value
|
|
6720
|
+
: null;
|
|
6721
|
+
}
|
|
6722
|
+
readString(value, key) {
|
|
6723
|
+
const raw = value?.[key];
|
|
6724
|
+
return typeof raw === 'string' ? raw.trim() : '';
|
|
6725
|
+
}
|
|
6726
|
+
readNumber(value, key) {
|
|
6727
|
+
const raw = value?.[key];
|
|
6728
|
+
return typeof raw === 'number' && Number.isFinite(raw) ? raw : null;
|
|
6729
|
+
}
|
|
6730
|
+
}
|
|
6731
|
+
|
|
4834
6732
|
function buildConnectionsViewerModel(page) {
|
|
4835
6733
|
const widgets = page?.widgets ?? [];
|
|
4836
6734
|
const links = page?.composition?.links ?? [];
|
|
@@ -4841,6 +6739,12 @@ function buildConnectionsViewerModel(page) {
|
|
|
4841
6739
|
const edges = links.map((link) => {
|
|
4842
6740
|
const fromWidgetId = link.from.kind === 'component-port' ? link.from.ref.widget : null;
|
|
4843
6741
|
const toWidgetId = link.to.kind === 'component-port' ? link.to.ref.widget : null;
|
|
6742
|
+
const fromNestedPath = link.from.kind === 'component-port' && link.from.ref.nestedPath?.length
|
|
6743
|
+
? clone(link.from.ref.nestedPath)
|
|
6744
|
+
: null;
|
|
6745
|
+
const toNestedPath = link.to.kind === 'component-port' && link.to.ref.nestedPath?.length
|
|
6746
|
+
? clone(link.to.ref.nestedPath)
|
|
6747
|
+
: null;
|
|
4844
6748
|
const toStatePath = link.to.kind === 'state' ? link.to.ref.path : null;
|
|
4845
6749
|
const diagnosticReasons = [];
|
|
4846
6750
|
if (fromWidgetId && !counts.has(fromWidgetId)) {
|
|
@@ -4863,9 +6767,17 @@ function buildConnectionsViewerModel(page) {
|
|
|
4863
6767
|
id: link.id,
|
|
4864
6768
|
fromKind: link.from.kind,
|
|
4865
6769
|
fromWidgetId,
|
|
6770
|
+
fromEndpointId: link.from.kind === 'component-port'
|
|
6771
|
+
? buildComponentEndpointId(link.from.ref.widget, link.from.ref.nestedPath)
|
|
6772
|
+
: null,
|
|
6773
|
+
fromNestedPath,
|
|
4866
6774
|
fromPort: link.from.kind === 'component-port' ? link.from.ref.port : null,
|
|
4867
6775
|
toKind: link.to.kind,
|
|
4868
6776
|
toWidgetId,
|
|
6777
|
+
toEndpointId: link.to.kind === 'component-port'
|
|
6778
|
+
? buildComponentEndpointId(link.to.ref.widget, link.to.ref.nestedPath)
|
|
6779
|
+
: null,
|
|
6780
|
+
toNestedPath,
|
|
4869
6781
|
toPort: link.to.kind === 'component-port' ? link.to.ref.port : null,
|
|
4870
6782
|
toStatePath,
|
|
4871
6783
|
intent: link.intent,
|
|
@@ -4896,6 +6808,31 @@ function buildConnectionsViewerModel(page) {
|
|
|
4896
6808
|
diagnosticLinks: edges.filter((edge) => edge.hasDiagnostics).length,
|
|
4897
6809
|
};
|
|
4898
6810
|
}
|
|
6811
|
+
function buildComponentEndpointId(ownerWidgetKey, nestedPath) {
|
|
6812
|
+
if (!nestedPath?.length) {
|
|
6813
|
+
return ownerWidgetKey;
|
|
6814
|
+
}
|
|
6815
|
+
return `${ownerWidgetKey}${nestedPath
|
|
6816
|
+
.map((segment) => `/${formatPathSegment(segment)}`)
|
|
6817
|
+
.join('')}`;
|
|
6818
|
+
}
|
|
6819
|
+
function formatPathSegment(segment) {
|
|
6820
|
+
if (segment.kind === 'widget') {
|
|
6821
|
+
const identity = segment.key
|
|
6822
|
+
|| segment.componentType
|
|
6823
|
+
|| (typeof segment.index === 'number' ? String(segment.index) : 'unknown');
|
|
6824
|
+
return `widget:${identity}`;
|
|
6825
|
+
}
|
|
6826
|
+
return [
|
|
6827
|
+
segment.kind,
|
|
6828
|
+
segment.id || segment.key || segment.index,
|
|
6829
|
+
].filter((part) => part !== undefined && part !== '').join(':');
|
|
6830
|
+
}
|
|
6831
|
+
function clone(value) {
|
|
6832
|
+
if (value == null || typeof value !== 'object')
|
|
6833
|
+
return value;
|
|
6834
|
+
return JSON.parse(JSON.stringify(value));
|
|
6835
|
+
}
|
|
4899
6836
|
|
|
4900
6837
|
class ConnectionsViewerPanelComponent {
|
|
4901
6838
|
i18n = inject(PraxisI18nService);
|
|
@@ -5327,19 +7264,53 @@ class DynamicPageBuilderComponent {
|
|
|
5327
7264
|
settingsPanel;
|
|
5328
7265
|
i18n = inject(PraxisI18nService);
|
|
5329
7266
|
componentMetadata = inject(ComponentMetadataRegistry);
|
|
7267
|
+
agenticAuthoring = inject(PageBuilderAgenticAuthoringService);
|
|
7268
|
+
agenticTurnOrchestrator = inject(PraxisAssistantTurnOrchestratorService);
|
|
5330
7269
|
runtime;
|
|
5331
7270
|
page;
|
|
5332
7271
|
context = null;
|
|
5333
7272
|
strictValidation = true;
|
|
7273
|
+
autoPersist = true;
|
|
5334
7274
|
enableCustomization = false;
|
|
5335
7275
|
showSettingsButton = true;
|
|
5336
7276
|
pageIdentity;
|
|
5337
7277
|
componentInstanceId;
|
|
5338
7278
|
pageEditorComponent = DynamicPageConfigEditorComponent;
|
|
7279
|
+
enableAgenticAuthoring = false;
|
|
7280
|
+
agenticAuthoringProvider;
|
|
7281
|
+
agenticAuthoringModel;
|
|
7282
|
+
agenticAuthoringApiKey;
|
|
7283
|
+
agenticAuthoringComponentId;
|
|
7284
|
+
agenticAuthoringScope = 'user';
|
|
7285
|
+
agenticAuthoringEtag;
|
|
7286
|
+
agenticAuthoringIncludeLlmDiagnostics = false;
|
|
7287
|
+
agenticAuthoringEnableStreaming = false;
|
|
5339
7288
|
pageChange = new EventEmitter();
|
|
7289
|
+
agenticAuthoringApplied = new EventEmitter();
|
|
5340
7290
|
currentPage = signal({ widgets: [] }, ...(ngDevMode ? [{ debugName: "currentPage" }] : []));
|
|
5341
7291
|
connectionsViewerOpen = signal(false, ...(ngDevMode ? [{ debugName: "connectionsViewerOpen" }] : []));
|
|
7292
|
+
agenticAuthoringOpen = signal(false, ...(ngDevMode ? [{ debugName: "agenticAuthoringOpen" }] : []));
|
|
7293
|
+
agenticAuthoringPrompt = signal('', ...(ngDevMode ? [{ debugName: "agenticAuthoringPrompt" }] : []));
|
|
7294
|
+
agenticAuthoringBusy = signal(false, ...(ngDevMode ? [{ debugName: "agenticAuthoringBusy" }] : []));
|
|
7295
|
+
agenticAuthoringStatus = signal('', ...(ngDevMode ? [{ debugName: "agenticAuthoringStatus" }] : []));
|
|
7296
|
+
agenticAuthoringError = signal('', ...(ngDevMode ? [{ debugName: "agenticAuthoringError" }] : []));
|
|
7297
|
+
agenticAuthoringPreviewResult = signal(null, ...(ngDevMode ? [{ debugName: "agenticAuthoringPreviewResult" }] : []));
|
|
7298
|
+
agenticAuthoringLastEtag = signal(null, ...(ngDevMode ? [{ debugName: "agenticAuthoringLastEtag" }] : []));
|
|
7299
|
+
agenticAuthoringConversation = signal([], ...(ngDevMode ? [{ debugName: "agenticAuthoringConversation" }] : []));
|
|
7300
|
+
agenticAuthoringQuickReplies = signal([], ...(ngDevMode ? [{ debugName: "agenticAuthoringQuickReplies" }] : []));
|
|
7301
|
+
agenticAuthoringAttachments = signal([], ...(ngDevMode ? [{ debugName: "agenticAuthoringAttachments" }] : []));
|
|
7302
|
+
agenticAuthoringLlmDiagnostics = signal(null, ...(ngDevMode ? [{ debugName: "agenticAuthoringLlmDiagnostics" }] : []));
|
|
7303
|
+
agenticAuthoringEditingMessageId = signal(null, ...(ngDevMode ? [{ debugName: "agenticAuthoringEditingMessageId" }] : []));
|
|
7304
|
+
agenticAuthoringPanelLayout = signal({
|
|
7305
|
+
left: 16,
|
|
7306
|
+
top: 16,
|
|
7307
|
+
width: 440,
|
|
7308
|
+
height: 560,
|
|
7309
|
+
}, ...(ngDevMode ? [{ debugName: "agenticAuthoringPanelLayout" }] : []));
|
|
5342
7310
|
previewMode = false;
|
|
7311
|
+
agenticComponentCapabilities;
|
|
7312
|
+
agenticComponentCapabilitiesPromise;
|
|
7313
|
+
agenticTurnController;
|
|
5343
7314
|
constructor(dialog, settingsPanel) {
|
|
5344
7315
|
this.dialog = dialog;
|
|
5345
7316
|
this.settingsPanel = settingsPanel;
|
|
@@ -5361,6 +7332,7 @@ class DynamicPageBuilderComponent {
|
|
|
5361
7332
|
this.previewMode = !this.previewMode;
|
|
5362
7333
|
if (this.previewMode) {
|
|
5363
7334
|
this.connectionsViewerOpen.set(false);
|
|
7335
|
+
this.agenticAuthoringLlmDiagnostics.set(null);
|
|
5364
7336
|
}
|
|
5365
7337
|
}
|
|
5366
7338
|
toggleConnectionsViewer() {
|
|
@@ -5409,6 +7381,402 @@ class DynamicPageBuilderComponent {
|
|
|
5409
7381
|
this.currentPage.set(cloned);
|
|
5410
7382
|
this.pageChange.emit(cloned);
|
|
5411
7383
|
}
|
|
7384
|
+
applyConfigFromAdapter(config) {
|
|
7385
|
+
if (!config.page)
|
|
7386
|
+
return;
|
|
7387
|
+
const cloned = this.clonePage(config.page);
|
|
7388
|
+
this.currentPage.set(cloned);
|
|
7389
|
+
this.pageChange.emit(cloned);
|
|
7390
|
+
}
|
|
7391
|
+
createAdapterHost() {
|
|
7392
|
+
return {
|
|
7393
|
+
page: this.currentPage(),
|
|
7394
|
+
context: this.context,
|
|
7395
|
+
enableCustomization: this.enableCustomization,
|
|
7396
|
+
showSettingsButton: this.showSettingsButton,
|
|
7397
|
+
strictValidation: this.strictValidation,
|
|
7398
|
+
pageIdentity: this.pageIdentity,
|
|
7399
|
+
applyConfigFromAdapter: (config) => this.applyConfigFromAdapter(config),
|
|
7400
|
+
};
|
|
7401
|
+
}
|
|
7402
|
+
toggleAgenticAuthoring() {
|
|
7403
|
+
this.agenticAuthoringOpen.update((current) => !current);
|
|
7404
|
+
this.agenticAuthoringError.set('');
|
|
7405
|
+
}
|
|
7406
|
+
agenticAuthoringShellLabels() {
|
|
7407
|
+
return {
|
|
7408
|
+
title: this.tx('agentic.title', 'AI assistant'),
|
|
7409
|
+
subtitle: this.tx('agentic.subtitle', 'Chat, confirm the intent, and review the result before saving.'),
|
|
7410
|
+
close: this.tx('agentic.close', 'Close'),
|
|
7411
|
+
prompt: this.tx('agentic.promptLabel', 'Message'),
|
|
7412
|
+
promptPlaceholder: this.tx('agentic.promptPlaceholder', 'Describe the page, dashboard, form or change you need.'),
|
|
7413
|
+
emptyConversation: this.tx('agentic.emptyConversation', 'Tell me what you want to create or change. I will ask follow-up questions before applying the preview.'),
|
|
7414
|
+
submit: this.tx('agentic.preview', 'Preview'),
|
|
7415
|
+
apply: this.tx('agentic.persist', 'Save'),
|
|
7416
|
+
conversationAria: this.tx('agentic.conversationAria', 'AI conversation'),
|
|
7417
|
+
quickRepliesAria: this.tx('agentic.quickRepliesAria', 'Quick replies'),
|
|
7418
|
+
dragHandleAria: this.tx('agentic.dragHandleAria', 'Move AI assistant'),
|
|
7419
|
+
resizeHandleAria: this.tx('agentic.resizeHandleAria', 'Resize AI assistant'),
|
|
7420
|
+
contextAria: this.tx('agentic.contextAria', 'Active context'),
|
|
7421
|
+
attachmentsAria: this.tx('agentic.attachmentsAria', 'Attached context'),
|
|
7422
|
+
attach: this.tx('agentic.attach', 'Attach'),
|
|
7423
|
+
removeAttachment: this.tx('agentic.removeAttachment', 'Remove attachment'),
|
|
7424
|
+
editMessage: this.tx('agentic.editMessage', 'Edit'),
|
|
7425
|
+
resendMessage: this.tx('agentic.resendMessage', 'Resend'),
|
|
7426
|
+
modeAgenticAuthoring: this.tx('agentic.mode.agenticAuthoring', 'Authoring'),
|
|
7427
|
+
modeConfig: this.tx('agentic.mode.config', 'Configuration'),
|
|
7428
|
+
modeChat: this.tx('agentic.mode.chat', 'Chat'),
|
|
7429
|
+
modeDiagnostic: this.tx('agentic.mode.diagnostic', 'Diagnostic'),
|
|
7430
|
+
modeReview: this.tx('agentic.mode.review', 'Review'),
|
|
7431
|
+
modeInlineHelp: this.tx('agentic.mode.inlineHelp', 'Help'),
|
|
7432
|
+
stateIdle: this.tx('agentic.state.idle', 'Idle'),
|
|
7433
|
+
stateListening: this.tx('agentic.state.listening', 'Ready'),
|
|
7434
|
+
stateProcessing: this.tx('agentic.state.processing', 'Processing'),
|
|
7435
|
+
stateClarification: this.tx('agentic.state.clarification', 'Waiting for input'),
|
|
7436
|
+
stateReview: this.tx('agentic.state.review', 'Review'),
|
|
7437
|
+
stateApplying: this.tx('agentic.state.applying', 'Applying'),
|
|
7438
|
+
stateSuccess: this.tx('agentic.state.success', 'Done'),
|
|
7439
|
+
stateError: this.tx('agentic.state.error', 'Error'),
|
|
7440
|
+
};
|
|
7441
|
+
}
|
|
7442
|
+
agenticAuthoringShellState() {
|
|
7443
|
+
if (this.agenticAuthoringBusy())
|
|
7444
|
+
return 'processing';
|
|
7445
|
+
if (this.agenticAuthoringError())
|
|
7446
|
+
return 'error';
|
|
7447
|
+
if (this.agenticAuthoringPreviewResult()?.valid)
|
|
7448
|
+
return 'review';
|
|
7449
|
+
if (this.agenticAuthoringConversation().length)
|
|
7450
|
+
return 'listening';
|
|
7451
|
+
return 'idle';
|
|
7452
|
+
}
|
|
7453
|
+
agenticAuthoringContextItems() {
|
|
7454
|
+
const items = [
|
|
7455
|
+
{
|
|
7456
|
+
id: 'component',
|
|
7457
|
+
kind: 'component',
|
|
7458
|
+
label: this.tx('agentic.context.component', 'Component'),
|
|
7459
|
+
value: this.tx('agentic.context.pageBuilder', 'Page Builder'),
|
|
7460
|
+
icon: 'dashboard_customize',
|
|
7461
|
+
},
|
|
7462
|
+
];
|
|
7463
|
+
const routePath = this.pageIdentity?.routePath?.trim();
|
|
7464
|
+
if (routePath) {
|
|
7465
|
+
items.push({
|
|
7466
|
+
id: 'route',
|
|
7467
|
+
kind: 'route',
|
|
7468
|
+
label: this.tx('agentic.context.route', 'Route'),
|
|
7469
|
+
value: routePath,
|
|
7470
|
+
icon: 'route',
|
|
7471
|
+
});
|
|
7472
|
+
}
|
|
7473
|
+
const selectedWidgetKey = this.resolveSelectedWidgetKey();
|
|
7474
|
+
if (selectedWidgetKey) {
|
|
7475
|
+
items.push({
|
|
7476
|
+
id: 'selection',
|
|
7477
|
+
kind: 'selection',
|
|
7478
|
+
label: this.tx('agentic.context.selection', 'Selection'),
|
|
7479
|
+
value: selectedWidgetKey,
|
|
7480
|
+
icon: 'select_all',
|
|
7481
|
+
});
|
|
7482
|
+
}
|
|
7483
|
+
return items;
|
|
7484
|
+
}
|
|
7485
|
+
async previewAgenticAuthoring() {
|
|
7486
|
+
const prompt = this.agenticAuthoringPrompt().trim();
|
|
7487
|
+
if (!prompt || this.agenticAuthoringBusy())
|
|
7488
|
+
return;
|
|
7489
|
+
this.agenticAuthoringBusy.set(true);
|
|
7490
|
+
this.agenticAuthoringError.set('');
|
|
7491
|
+
this.agenticAuthoringPreviewResult.set(null);
|
|
7492
|
+
this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Resolving intent...'));
|
|
7493
|
+
try {
|
|
7494
|
+
const controller = this.ensureAgenticTurnController();
|
|
7495
|
+
const editingMessageId = this.agenticAuthoringEditingMessageId();
|
|
7496
|
+
await this.consumeAgenticTurn(editingMessageId
|
|
7497
|
+
? controller.submitEditedMessage(editingMessageId, prompt)
|
|
7498
|
+
: controller.submitPrompt(prompt));
|
|
7499
|
+
this.agenticAuthoringEditingMessageId.set(null);
|
|
7500
|
+
}
|
|
7501
|
+
catch (error) {
|
|
7502
|
+
this.agenticAuthoringStatus.set('');
|
|
7503
|
+
const message = this.describeAgenticError(error);
|
|
7504
|
+
this.agenticAuthoringError.set(message);
|
|
7505
|
+
this.appendAgenticMessage('error', message);
|
|
7506
|
+
}
|
|
7507
|
+
finally {
|
|
7508
|
+
this.agenticAuthoringBusy.set(false);
|
|
7509
|
+
}
|
|
7510
|
+
}
|
|
7511
|
+
async submitAgenticQuickReply(reply) {
|
|
7512
|
+
const replyKind = (reply.kind || 'suggestion').trim().toLowerCase();
|
|
7513
|
+
if (replyKind === 'cancel') {
|
|
7514
|
+
this.agenticAuthoringEditingMessageId.set(null);
|
|
7515
|
+
await this.consumeAgenticTurn(this.ensureAgenticTurnController().cancel());
|
|
7516
|
+
return;
|
|
7517
|
+
}
|
|
7518
|
+
if (replyKind === 'revise') {
|
|
7519
|
+
this.agenticAuthoringEditingMessageId.set(null);
|
|
7520
|
+
this.agenticAuthoringQuickReplies.set([]);
|
|
7521
|
+
this.agenticAuthoringStatus.set(this.tx('agentic.status.waitingRevision', 'Refine your prompt and preview again.'));
|
|
7522
|
+
return;
|
|
7523
|
+
}
|
|
7524
|
+
this.agenticAuthoringEditingMessageId.set(null);
|
|
7525
|
+
const contextHints = reply.contextHints ? { ...reply.contextHints } : undefined;
|
|
7526
|
+
const visiblePrompt = this.agenticQuickReplyVisiblePrompt(reply, contextHints);
|
|
7527
|
+
this.agenticAuthoringPrompt.set(visiblePrompt);
|
|
7528
|
+
this.agenticAuthoringBusy.set(true);
|
|
7529
|
+
this.agenticAuthoringError.set('');
|
|
7530
|
+
this.agenticAuthoringPreviewResult.set(null);
|
|
7531
|
+
this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Resolving intent...'));
|
|
7532
|
+
try {
|
|
7533
|
+
const controller = this.ensureAgenticTurnController();
|
|
7534
|
+
await this.consumeAgenticTurn(controller.snapshot().state === 'clarification'
|
|
7535
|
+
? controller.answerClarification({
|
|
7536
|
+
id: reply.id,
|
|
7537
|
+
label: visiblePrompt,
|
|
7538
|
+
value: reply.prompt,
|
|
7539
|
+
description: reply.description ?? undefined,
|
|
7540
|
+
contextHints,
|
|
7541
|
+
})
|
|
7542
|
+
: controller.submitPrompt(visiblePrompt, {
|
|
7543
|
+
kind: replyKind || 'quick-reply',
|
|
7544
|
+
id: reply.id,
|
|
7545
|
+
value: reply.prompt,
|
|
7546
|
+
contextHints,
|
|
7547
|
+
}));
|
|
7548
|
+
}
|
|
7549
|
+
catch (error) {
|
|
7550
|
+
this.agenticAuthoringStatus.set('');
|
|
7551
|
+
const message = this.describeAgenticError(error);
|
|
7552
|
+
this.agenticAuthoringError.set(message);
|
|
7553
|
+
this.appendAgenticMessage('error', message);
|
|
7554
|
+
}
|
|
7555
|
+
finally {
|
|
7556
|
+
this.agenticAuthoringBusy.set(false);
|
|
7557
|
+
}
|
|
7558
|
+
}
|
|
7559
|
+
agenticQuickReplyVisiblePrompt(reply, contextHints) {
|
|
7560
|
+
if (!this.isResourceQuickReply(reply, contextHints)) {
|
|
7561
|
+
return reply.prompt;
|
|
7562
|
+
}
|
|
7563
|
+
const label = (reply.label || this.describeResourceContext(contextHints) || reply.prompt).trim();
|
|
7564
|
+
const resourcePath = String(contextHints?.['resourcePath'] || '').trim();
|
|
7565
|
+
return this.tx('agentic.quickReplies.resourceSelectionPrompt', 'Use {label} ({resourcePath}) as the data source.')
|
|
7566
|
+
.replace('{label}', label)
|
|
7567
|
+
.replace('{resourcePath}', resourcePath);
|
|
7568
|
+
}
|
|
7569
|
+
isResourceQuickReply(reply, contextHints) {
|
|
7570
|
+
return reply.kind === 'suggestion'
|
|
7571
|
+
&& typeof contextHints?.['resourcePath'] === 'string'
|
|
7572
|
+
&& !!String(contextHints['resourcePath']).trim();
|
|
7573
|
+
}
|
|
7574
|
+
describeResourceContext(contextHints) {
|
|
7575
|
+
const resourcePath = typeof contextHints?.['resourcePath'] === 'string'
|
|
7576
|
+
? contextHints['resourcePath'].trim()
|
|
7577
|
+
: '';
|
|
7578
|
+
if (!resourcePath)
|
|
7579
|
+
return '';
|
|
7580
|
+
const segment = resourcePath.split('/').filter((part) => !!part).pop() || resourcePath;
|
|
7581
|
+
return segment
|
|
7582
|
+
.replace(/[-_]+/g, ' ')
|
|
7583
|
+
.replace(/\s+/g, ' ')
|
|
7584
|
+
.trim();
|
|
7585
|
+
}
|
|
7586
|
+
attachAgenticContext() {
|
|
7587
|
+
const controller = this.ensureAgenticTurnController();
|
|
7588
|
+
const pageSnapshot = JSON.stringify(this.currentPage());
|
|
7589
|
+
controller.addAttachment({
|
|
7590
|
+
id: `current-page-${Date.now()}`,
|
|
7591
|
+
name: this.tx('agentic.attachments.currentPage', 'Current page'),
|
|
7592
|
+
kind: 'json',
|
|
7593
|
+
mimeType: 'application/json',
|
|
7594
|
+
sizeBytes: pageSnapshot.length,
|
|
7595
|
+
status: 'ready',
|
|
7596
|
+
});
|
|
7597
|
+
this.applyAgenticTurnState(controller.snapshot());
|
|
7598
|
+
}
|
|
7599
|
+
addAgenticAttachments(attachments) {
|
|
7600
|
+
if (!attachments.length)
|
|
7601
|
+
return;
|
|
7602
|
+
const controller = this.ensureAgenticTurnController();
|
|
7603
|
+
for (const attachment of attachments) {
|
|
7604
|
+
controller.addAttachment(attachment);
|
|
7605
|
+
}
|
|
7606
|
+
this.applyAgenticTurnState(controller.snapshot());
|
|
7607
|
+
}
|
|
7608
|
+
removeAgenticAttachment(attachment) {
|
|
7609
|
+
const controller = this.ensureAgenticTurnController();
|
|
7610
|
+
controller.removeAttachment(attachment.id);
|
|
7611
|
+
this.applyAgenticTurnState(controller.snapshot());
|
|
7612
|
+
}
|
|
7613
|
+
editAgenticMessage(message) {
|
|
7614
|
+
if (message.role !== 'user')
|
|
7615
|
+
return;
|
|
7616
|
+
this.agenticAuthoringEditingMessageId.set(message.id);
|
|
7617
|
+
this.agenticAuthoringPrompt.set(message.text);
|
|
7618
|
+
this.agenticAuthoringStatus.set(this.tx('agentic.status.waitingRevision', 'Refine your prompt and preview again.'));
|
|
7619
|
+
}
|
|
7620
|
+
async resendAgenticMessage(message) {
|
|
7621
|
+
if (message.role !== 'user' || this.agenticAuthoringBusy())
|
|
7622
|
+
return;
|
|
7623
|
+
this.agenticAuthoringEditingMessageId.set(null);
|
|
7624
|
+
this.agenticAuthoringBusy.set(true);
|
|
7625
|
+
this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Resolving intent...'));
|
|
7626
|
+
this.agenticAuthoringError.set('');
|
|
7627
|
+
this.agenticAuthoringPreviewResult.set(null);
|
|
7628
|
+
try {
|
|
7629
|
+
await this.consumeAgenticTurn(this.ensureAgenticTurnController().resendMessage(message.id));
|
|
7630
|
+
}
|
|
7631
|
+
catch (error) {
|
|
7632
|
+
this.agenticAuthoringStatus.set('');
|
|
7633
|
+
const errorMessage = this.describeAgenticError(error);
|
|
7634
|
+
this.agenticAuthoringError.set(errorMessage);
|
|
7635
|
+
this.appendAgenticMessage('error', errorMessage);
|
|
7636
|
+
}
|
|
7637
|
+
finally {
|
|
7638
|
+
this.agenticAuthoringBusy.set(false);
|
|
7639
|
+
}
|
|
7640
|
+
}
|
|
7641
|
+
async persistAgenticAuthoring() {
|
|
7642
|
+
const preview = this.agenticAuthoringPreviewResult();
|
|
7643
|
+
if (!preview || this.agenticAuthoringBusy())
|
|
7644
|
+
return;
|
|
7645
|
+
const componentId = this.resolveAgenticComponentId();
|
|
7646
|
+
if (!componentId) {
|
|
7647
|
+
this.agenticAuthoringError.set(this.tx('agentic.errors.componentId', 'Configure a component id before saving.'));
|
|
7648
|
+
return;
|
|
7649
|
+
}
|
|
7650
|
+
this.agenticAuthoringBusy.set(true);
|
|
7651
|
+
this.agenticAuthoringError.set('');
|
|
7652
|
+
this.agenticAuthoringStatus.set(this.tx('agentic.status.saving', 'Saving page...'));
|
|
7653
|
+
try {
|
|
7654
|
+
const compiledFormPatch = this.resolvePreviewCompiledFormPatch(preview);
|
|
7655
|
+
const result = await firstValueFrom(this.agenticAuthoring.applyPage({
|
|
7656
|
+
compiledFormPatch,
|
|
7657
|
+
componentId,
|
|
7658
|
+
scope: this.agenticAuthoringScope,
|
|
7659
|
+
ifMatch: this.agenticAuthoringEtag || this.agenticAuthoringLastEtag() || undefined,
|
|
7660
|
+
tags: {
|
|
7661
|
+
source: 'page-builder-agentic-authoring',
|
|
7662
|
+
},
|
|
7663
|
+
}));
|
|
7664
|
+
this.agenticAuthoringLastEtag.set(result.etag ?? null);
|
|
7665
|
+
this.agenticAuthoringApplied.emit(result);
|
|
7666
|
+
this.agenticAuthoringStatus.set(this.tx('agentic.status.saved', 'Page saved.'));
|
|
7667
|
+
}
|
|
7668
|
+
catch (error) {
|
|
7669
|
+
this.agenticAuthoringStatus.set('');
|
|
7670
|
+
this.agenticAuthoringError.set(this.describeAgenticError(error));
|
|
7671
|
+
}
|
|
7672
|
+
finally {
|
|
7673
|
+
this.agenticAuthoringBusy.set(false);
|
|
7674
|
+
}
|
|
7675
|
+
}
|
|
7676
|
+
async loadAgenticComponentCapabilities() {
|
|
7677
|
+
if (this.agenticComponentCapabilities) {
|
|
7678
|
+
return this.agenticComponentCapabilities;
|
|
7679
|
+
}
|
|
7680
|
+
this.agenticComponentCapabilitiesPromise ??= firstValueFrom(this.agenticAuthoring.getComponentCapabilities()).then((result) => {
|
|
7681
|
+
this.agenticComponentCapabilities = result;
|
|
7682
|
+
return result;
|
|
7683
|
+
}).finally(() => {
|
|
7684
|
+
this.agenticComponentCapabilitiesPromise = undefined;
|
|
7685
|
+
});
|
|
7686
|
+
return this.agenticComponentCapabilitiesPromise;
|
|
7687
|
+
}
|
|
7688
|
+
ensureAgenticTurnController() {
|
|
7689
|
+
if (!this.agenticTurnController) {
|
|
7690
|
+
const flow = new PageBuilderAgenticAuthoringTurnFlow(this.agenticAuthoring, {
|
|
7691
|
+
targetApp: 'praxis-ui-angular',
|
|
7692
|
+
targetComponentId: 'praxis-dynamic-page-builder',
|
|
7693
|
+
currentPage: () => this.currentPage(),
|
|
7694
|
+
selectedWidgetKey: () => this.resolveSelectedWidgetKey(),
|
|
7695
|
+
provider: () => this.agenticAuthoringProvider,
|
|
7696
|
+
model: () => this.agenticAuthoringModel,
|
|
7697
|
+
apiKey: () => this.agenticAuthoringApiKey,
|
|
7698
|
+
enableTurnStream: () => this.agenticAuthoringEnableStreaming,
|
|
7699
|
+
includeLlmDiagnostics: () => this.agenticAuthoringIncludeLlmDiagnostics,
|
|
7700
|
+
loadComponentCapabilities: () => this.loadAgenticComponentCapabilities(),
|
|
7701
|
+
applyLocalPreview: (result) => this.applyAgenticPreviewLocally(result),
|
|
7702
|
+
describePreviewFailure: (result) => this.describeAgenticPreviewFailure(result),
|
|
7703
|
+
describePreviewStatus: (result) => this.describeAgenticPreviewStatus(result),
|
|
7704
|
+
describeError: (error) => this.describeAgenticError(error),
|
|
7705
|
+
tx: (key, fallback) => this.tx(key, fallback),
|
|
7706
|
+
});
|
|
7707
|
+
this.agenticTurnController = this.agenticTurnOrchestrator.createController(flow, {
|
|
7708
|
+
componentId: 'praxis-dynamic-page-builder',
|
|
7709
|
+
componentType: 'page-builder',
|
|
7710
|
+
contextItems: this.agenticAuthoringContextItems(),
|
|
7711
|
+
attachments: this.agenticAuthoringAttachments(),
|
|
7712
|
+
});
|
|
7713
|
+
}
|
|
7714
|
+
this.agenticTurnController.setContextItems(this.agenticAuthoringContextItems());
|
|
7715
|
+
this.agenticTurnController.setMessages(this.agenticAuthoringConversation());
|
|
7716
|
+
this.agenticTurnController.setAttachments(this.agenticAuthoringAttachments());
|
|
7717
|
+
return this.agenticTurnController;
|
|
7718
|
+
}
|
|
7719
|
+
async applyAgenticPreviewLocally(result) {
|
|
7720
|
+
const adapter = new PageBuilderAiAdapter(this.createAdapterHost(), this.componentMetadata);
|
|
7721
|
+
const applied = await (result.uiCompositionPlan
|
|
7722
|
+
? adapter.applyUiCompositionPlan(result.uiCompositionPlan)
|
|
7723
|
+
: adapter.applyCompiledFormPatch(result.compiledFormPatch));
|
|
7724
|
+
if (!applied.success && this.isAgenticTableContractError(applied.error)) {
|
|
7725
|
+
return {
|
|
7726
|
+
...applied,
|
|
7727
|
+
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.'),
|
|
7728
|
+
};
|
|
7729
|
+
}
|
|
7730
|
+
return applied;
|
|
7731
|
+
}
|
|
7732
|
+
applyAgenticTurnState(state) {
|
|
7733
|
+
const preview = state.preview ?? null;
|
|
7734
|
+
this.agenticAuthoringConversation.set(state.messages);
|
|
7735
|
+
this.agenticAuthoringQuickReplies.set(preview?.valid ? [] : state.quickReplies);
|
|
7736
|
+
this.agenticAuthoringStatus.set(state.statusText);
|
|
7737
|
+
this.agenticAuthoringError.set(state.errorText);
|
|
7738
|
+
this.agenticAuthoringPreviewResult.set(preview);
|
|
7739
|
+
this.agenticAuthoringAttachments.set(state.attachments);
|
|
7740
|
+
this.agenticAuthoringLlmDiagnostics.set(this.resolveAgenticLlmDiagnostics(state.diagnostics));
|
|
7741
|
+
}
|
|
7742
|
+
consumeAgenticTurn(states$) {
|
|
7743
|
+
return lastValueFrom(states$.pipe(tap((state) => this.applyAgenticTurnState(state))));
|
|
7744
|
+
}
|
|
7745
|
+
agenticAuthoringDiagnosticsTop() {
|
|
7746
|
+
return Math.max(16, this.agenticAuthoringPanelLayout().top);
|
|
7747
|
+
}
|
|
7748
|
+
agenticAuthoringLlmDiagnosticsText() {
|
|
7749
|
+
const diagnostics = this.agenticAuthoringLlmDiagnostics();
|
|
7750
|
+
if (!this.agenticAuthoringIncludeLlmDiagnostics || !diagnostics) {
|
|
7751
|
+
return '';
|
|
7752
|
+
}
|
|
7753
|
+
return JSON.stringify(diagnostics, null, 2);
|
|
7754
|
+
}
|
|
7755
|
+
resolveAgenticLlmDiagnostics(diagnostics) {
|
|
7756
|
+
if (!this.agenticAuthoringIncludeLlmDiagnostics) {
|
|
7757
|
+
return null;
|
|
7758
|
+
}
|
|
7759
|
+
const intentResolution = this.toRecord(diagnostics?.['intentResolution']);
|
|
7760
|
+
return this.toRecord(intentResolution?.['llmDiagnostics']);
|
|
7761
|
+
}
|
|
7762
|
+
toRecord(value) {
|
|
7763
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
7764
|
+
return null;
|
|
7765
|
+
}
|
|
7766
|
+
return value;
|
|
7767
|
+
}
|
|
7768
|
+
resolvePreviewCompiledFormPatch(preview) {
|
|
7769
|
+
if (preview.uiCompositionPlan || preview.compiledFormPatch?.patch?.page) {
|
|
7770
|
+
return {
|
|
7771
|
+
...preview.compiledFormPatch,
|
|
7772
|
+
patch: {
|
|
7773
|
+
...(preview.compiledFormPatch?.patch ?? {}),
|
|
7774
|
+
page: this.clonePage(this.currentPage()),
|
|
7775
|
+
},
|
|
7776
|
+
};
|
|
7777
|
+
}
|
|
7778
|
+
return preview.compiledFormPatch;
|
|
7779
|
+
}
|
|
5412
7780
|
focusCanvasWidget(widgetKey) {
|
|
5413
7781
|
if (!widgetKey)
|
|
5414
7782
|
return;
|
|
@@ -5440,6 +7808,94 @@ class DynamicPageBuilderComponent {
|
|
|
5440
7808
|
}
|
|
5441
7809
|
return inputs;
|
|
5442
7810
|
}
|
|
7811
|
+
resolveAgenticComponentId() {
|
|
7812
|
+
const explicit = this.agenticAuthoringComponentId?.trim();
|
|
7813
|
+
if (explicit)
|
|
7814
|
+
return explicit;
|
|
7815
|
+
const routePath = this.pageIdentity?.routePath?.trim();
|
|
7816
|
+
if (routePath)
|
|
7817
|
+
return `page:${routePath}`;
|
|
7818
|
+
return null;
|
|
7819
|
+
}
|
|
7820
|
+
resolveSelectedWidgetKey() {
|
|
7821
|
+
const runtime = this.runtime;
|
|
7822
|
+
if (!runtime)
|
|
7823
|
+
return null;
|
|
7824
|
+
for (const widget of this.currentPage().widgets ?? []) {
|
|
7825
|
+
if (widget?.key && runtime.isCanvasWidgetSelected(widget.key)) {
|
|
7826
|
+
return widget.key;
|
|
7827
|
+
}
|
|
7828
|
+
}
|
|
7829
|
+
return null;
|
|
7830
|
+
}
|
|
7831
|
+
formatAgenticFailures(failureCodes) {
|
|
7832
|
+
const codes = (failureCodes ?? []).filter((code) => !!code);
|
|
7833
|
+
if (codes.length === 0) {
|
|
7834
|
+
return this.tx('agentic.errors.invalidPreview', 'Generated preview is invalid.');
|
|
7835
|
+
}
|
|
7836
|
+
return `${this.tx('agentic.errors.invalidPreview', 'Generated preview is invalid.')}: ${codes.join(', ')}`;
|
|
7837
|
+
}
|
|
7838
|
+
describeAgenticPreviewFailure(result) {
|
|
7839
|
+
switch (result.diagnostics?.fieldScopeDecision) {
|
|
7840
|
+
case 'rejected-duplicate-field':
|
|
7841
|
+
return this.tx('agentic.errors.duplicateField', 'This field already exists in the selected form.');
|
|
7842
|
+
case 'rejected-non-local-field-removal':
|
|
7843
|
+
return this.tx('agentic.errors.nonLocalFieldRemoval', 'Only local fields created by AI can be removed in this flow.');
|
|
7844
|
+
default:
|
|
7845
|
+
return this.formatAgenticFailures(result.failureCodes);
|
|
7846
|
+
}
|
|
7847
|
+
}
|
|
7848
|
+
describeAgenticPreviewStatus(result) {
|
|
7849
|
+
const assistantMessage = typeof result.assistantMessage === 'string'
|
|
7850
|
+
? result.assistantMessage.trim()
|
|
7851
|
+
: '';
|
|
7852
|
+
if (assistantMessage) {
|
|
7853
|
+
return assistantMessage;
|
|
7854
|
+
}
|
|
7855
|
+
switch (result.diagnostics?.fieldScopeDecision) {
|
|
7856
|
+
case 'accepted-add-local-field':
|
|
7857
|
+
return this.tx('agentic.status.acceptedAddLocalField', 'Local field added to the form.');
|
|
7858
|
+
case 'accepted-remove-local-field':
|
|
7859
|
+
return this.tx('agentic.status.acceptedRemoveLocalField', 'Local field removed from the form.');
|
|
7860
|
+
case 'accepted-relabel-server-backed-field':
|
|
7861
|
+
return this.tx('agentic.status.acceptedRelabelField', 'Field label updated.');
|
|
7862
|
+
default:
|
|
7863
|
+
return this.tx('agentic.status.previewReady', 'Preview applied to the page.');
|
|
7864
|
+
}
|
|
7865
|
+
}
|
|
7866
|
+
isAgenticTableContractError(error) {
|
|
7867
|
+
const message = typeof error === 'string' ? error.toLowerCase() : '';
|
|
7868
|
+
return message.includes('praxis-table')
|
|
7869
|
+
&& (message.includes('unknown input') || message.includes('unknown inputs') || message.includes('unsupported'));
|
|
7870
|
+
}
|
|
7871
|
+
appendAgenticMessage(role, text) {
|
|
7872
|
+
const normalized = text.trim();
|
|
7873
|
+
if (!normalized)
|
|
7874
|
+
return;
|
|
7875
|
+
this.agenticAuthoringConversation.update((messages) => [
|
|
7876
|
+
...messages,
|
|
7877
|
+
{
|
|
7878
|
+
id: `${Date.now()}-${messages.length}-${role}`,
|
|
7879
|
+
role,
|
|
7880
|
+
text: normalized,
|
|
7881
|
+
},
|
|
7882
|
+
]);
|
|
7883
|
+
}
|
|
7884
|
+
describeAgenticError(error) {
|
|
7885
|
+
if (typeof error?.error?.message === 'string' && error.error.message.trim()) {
|
|
7886
|
+
return error.error.message.trim();
|
|
7887
|
+
}
|
|
7888
|
+
if (typeof error?.error === 'string' && error.error.trim()) {
|
|
7889
|
+
return error.error.trim();
|
|
7890
|
+
}
|
|
7891
|
+
if (typeof error?.message === 'string' && error.message.trim()) {
|
|
7892
|
+
return error.message.trim();
|
|
7893
|
+
}
|
|
7894
|
+
if (typeof error?.status === 'number') {
|
|
7895
|
+
return `HTTP ${error.status}`;
|
|
7896
|
+
}
|
|
7897
|
+
return this.tx('agentic.errors.generic', 'AI authoring failed.');
|
|
7898
|
+
}
|
|
5443
7899
|
cloneValue(value) {
|
|
5444
7900
|
if (value == null || typeof value !== 'object') {
|
|
5445
7901
|
return value;
|
|
@@ -5450,7 +7906,7 @@ class DynamicPageBuilderComponent {
|
|
|
5450
7906
|
return resolvePraxisPageBuilderText(this.i18n, key, fallback);
|
|
5451
7907
|
}
|
|
5452
7908
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicPageBuilderComponent, deps: [{ token: i1.MatDialog }, { token: SETTINGS_PANEL_BRIDGE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
5453
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: DynamicPageBuilderComponent, isStandalone: true, selector: "praxis-dynamic-page-builder", inputs: { page: "page", context: "context", strictValidation: "strictValidation", enableCustomization: "enableCustomization", showSettingsButton: "showSettingsButton", pageIdentity: "pageIdentity", componentInstanceId: "componentInstanceId", pageEditorComponent: "pageEditorComponent" }, outputs: { pageChange: "pageChange" }, providers: [
|
|
7909
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", 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" }, outputs: { pageChange: "pageChange", agenticAuthoringApplied: "agenticAuthoringApplied" }, providers: [
|
|
5454
7910
|
providePraxisPageBuilderI18n(),
|
|
5455
7911
|
{ provide: DYNAMIC_PAGE_SHELL_EDITOR, useValue: WidgetShellEditorComponent },
|
|
5456
7912
|
], viewQueries: [{ propertyName: "runtime", first: true, predicate: ["runtime"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
@@ -5460,6 +7916,7 @@ class DynamicPageBuilderComponent {
|
|
|
5460
7916
|
[page]="currentPage()"
|
|
5461
7917
|
[context]="context"
|
|
5462
7918
|
[strictValidation]="strictValidation"
|
|
7919
|
+
[autoPersist]="autoPersist"
|
|
5463
7920
|
[enableCustomization]="showSettings()"
|
|
5464
7921
|
[showPageSettingsButton]="false"
|
|
5465
7922
|
[pageIdentity]="pageIdentity"
|
|
@@ -5475,6 +7932,64 @@ class DynamicPageBuilderComponent {
|
|
|
5475
7932
|
(openPageSettings)="openPageSettings()"
|
|
5476
7933
|
/>
|
|
5477
7934
|
|
|
7935
|
+
<praxis-ai-assistant-shell
|
|
7936
|
+
*ngIf="showSettings() && enableAgenticAuthoring && agenticAuthoringOpen()"
|
|
7937
|
+
panelTestId="page-builder-agentic-authoring-panel"
|
|
7938
|
+
testIdPrefix="page-builder-agentic"
|
|
7939
|
+
submitTestId="page-builder-agentic-preview"
|
|
7940
|
+
applyTestId="page-builder-agentic-persist"
|
|
7941
|
+
[labels]="agenticAuthoringShellLabels()"
|
|
7942
|
+
mode="agentic-authoring"
|
|
7943
|
+
[state]="agenticAuthoringShellState()"
|
|
7944
|
+
[contextItems]="agenticAuthoringContextItems()"
|
|
7945
|
+
[attachments]="agenticAuthoringAttachments()"
|
|
7946
|
+
[messages]="agenticAuthoringConversation()"
|
|
7947
|
+
[quickReplies]="agenticAuthoringQuickReplies()"
|
|
7948
|
+
[prompt]="agenticAuthoringPrompt()"
|
|
7949
|
+
[statusText]="agenticAuthoringStatus()"
|
|
7950
|
+
[errorText]="agenticAuthoringError()"
|
|
7951
|
+
[busy]="agenticAuthoringBusy()"
|
|
7952
|
+
[canApply]="!!agenticAuthoringPreviewResult()?.valid"
|
|
7953
|
+
[enableFileAttachments]="true"
|
|
7954
|
+
attachmentAccept="image/*,application/json,text/plain,application/pdf"
|
|
7955
|
+
[layout]="agenticAuthoringPanelLayout()"
|
|
7956
|
+
[minWidth]="320"
|
|
7957
|
+
[minHeight]="280"
|
|
7958
|
+
[margin]="8"
|
|
7959
|
+
(promptChange)="agenticAuthoringPrompt.set($event)"
|
|
7960
|
+
(submitPrompt)="agenticAuthoringPrompt.set($event); previewAgenticAuthoring()"
|
|
7961
|
+
(apply)="persistAgenticAuthoring()"
|
|
7962
|
+
(quickReply)="submitAgenticQuickReply($event)"
|
|
7963
|
+
(attach)="attachAgenticContext()"
|
|
7964
|
+
(attachmentsPasted)="addAgenticAttachments($event)"
|
|
7965
|
+
(attachmentsSelected)="addAgenticAttachments($event)"
|
|
7966
|
+
(removeAttachment)="removeAgenticAttachment($event)"
|
|
7967
|
+
(editMessage)="editAgenticMessage($event)"
|
|
7968
|
+
(resendMessage)="resendAgenticMessage($event)"
|
|
7969
|
+
(layoutChange)="agenticAuthoringPanelLayout.set($event)"
|
|
7970
|
+
(close)="toggleAgenticAuthoring()"
|
|
7971
|
+
/>
|
|
7972
|
+
|
|
7973
|
+
<section
|
|
7974
|
+
*ngIf="agenticAuthoringIncludeLlmDiagnostics && agenticAuthoringLlmDiagnosticsText()"
|
|
7975
|
+
class="agentic-diagnostics-panel"
|
|
7976
|
+
data-testid="page-builder-agentic-llm-diagnostics"
|
|
7977
|
+
role="region"
|
|
7978
|
+
[attr.aria-label]="tx('agentic.diagnostics.title', 'LLM diagnostics')"
|
|
7979
|
+
[style.top.px]="agenticAuthoringDiagnosticsTop()"
|
|
7980
|
+
>
|
|
7981
|
+
<header class="agentic-diagnostics-panel__header">
|
|
7982
|
+
<span>{{ tx('agentic.diagnostics.title', 'LLM diagnostics') }}</span>
|
|
7983
|
+
<span class="agentic-diagnostics-panel__badge">
|
|
7984
|
+
{{ tx('agentic.diagnostics.badge', 'Debug') }}
|
|
7985
|
+
</span>
|
|
7986
|
+
</header>
|
|
7987
|
+
<p class="agentic-diagnostics-panel__description">
|
|
7988
|
+
{{ tx('agentic.diagnostics.description', 'Prompt, context bundle, and tool catalog returned by the backend for this turn.') }}
|
|
7989
|
+
</p>
|
|
7990
|
+
<pre>{{ agenticAuthoringLlmDiagnosticsText() }}</pre>
|
|
7991
|
+
</section>
|
|
7992
|
+
|
|
5478
7993
|
<praxis-floating-toolbar
|
|
5479
7994
|
[visible]="showSettings()"
|
|
5480
7995
|
[canUndo]="false"
|
|
@@ -5484,6 +7999,18 @@ class DynamicPageBuilderComponent {
|
|
|
5484
7999
|
(save)="saveCurrentPage()"
|
|
5485
8000
|
(preview)="togglePreview()"
|
|
5486
8001
|
>
|
|
8002
|
+
<button
|
|
8003
|
+
*ngIf="enableAgenticAuthoring"
|
|
8004
|
+
pdx-toolbar-extra
|
|
8005
|
+
mat-mini-fab
|
|
8006
|
+
type="button"
|
|
8007
|
+
[attr.data-testid]="'page-builder-agentic-toggle'"
|
|
8008
|
+
[matTooltip]="tx('agentic.toggle', 'Create with AI')"
|
|
8009
|
+
[attr.aria-label]="tx('agentic.toggle', 'Create with AI')"
|
|
8010
|
+
(click)="toggleAgenticAuthoring()"
|
|
8011
|
+
>
|
|
8012
|
+
<mat-icon [praxisIcon]="'auto_awesome'"></mat-icon>
|
|
8013
|
+
</button>
|
|
5487
8014
|
<button
|
|
5488
8015
|
pdx-toolbar-extra
|
|
5489
8016
|
mat-mini-fab
|
|
@@ -5497,7 +8024,7 @@ class DynamicPageBuilderComponent {
|
|
|
5497
8024
|
</button>
|
|
5498
8025
|
</praxis-floating-toolbar>
|
|
5499
8026
|
</div>
|
|
5500
|
-
`, isInline: true, styles: [":host
|
|
8027
|
+
`, 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%}.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__header{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:13px;font-weight:700}.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__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}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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: i4.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"], outputs: ["pageChange", "widgetEvent", "widgetDiagnosticsChange"] }, { kind: "component", type: FloatingToolbarComponent, selector: "praxis-floating-toolbar", inputs: ["visible", "canUndo", "canRedo"], outputs: ["add", "undo", "redo", "settings", "preview", "save"] }, { kind: "component", type: ConnectionsViewerPanelComponent, selector: "praxis-connections-viewer-panel", inputs: ["open", "page"], outputs: ["focusWidget", "openPageSettings"] }, { kind: "component", type: PraxisAiAssistantShellComponent, selector: "praxis-ai-assistant-shell", inputs: ["labels", "mode", "state", "contextItems", "attachments", "messages", "quickReplies", "prompt", "statusText", "errorText", "testIdPrefix", "panelTestId", "submitTestId", "applyTestId", "busy", "canSubmit", "canApply", "submitOnEnter", "enableFileAttachments", "attachmentAccept", "attachmentMultiple", "draggable", "resizable", "minWidth", "minHeight", "margin", "layout"], outputs: ["promptChange", "submitPrompt", "apply", "close", "attach", "attachmentsPasted", "attachmentsSelected", "removeAttachment", "messageAction", "editMessage", "resendMessage", "quickReply", "layoutChange"] }] });
|
|
5501
8028
|
}
|
|
5502
8029
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicPageBuilderComponent, decorators: [{
|
|
5503
8030
|
type: Component,
|
|
@@ -5510,6 +8037,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
5510
8037
|
DynamicWidgetPageComponent,
|
|
5511
8038
|
FloatingToolbarComponent,
|
|
5512
8039
|
ConnectionsViewerPanelComponent,
|
|
8040
|
+
PraxisAiAssistantShellComponent,
|
|
5513
8041
|
], providers: [
|
|
5514
8042
|
providePraxisPageBuilderI18n(),
|
|
5515
8043
|
{ provide: DYNAMIC_PAGE_SHELL_EDITOR, useValue: WidgetShellEditorComponent },
|
|
@@ -5520,6 +8048,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
5520
8048
|
[page]="currentPage()"
|
|
5521
8049
|
[context]="context"
|
|
5522
8050
|
[strictValidation]="strictValidation"
|
|
8051
|
+
[autoPersist]="autoPersist"
|
|
5523
8052
|
[enableCustomization]="showSettings()"
|
|
5524
8053
|
[showPageSettingsButton]="false"
|
|
5525
8054
|
[pageIdentity]="pageIdentity"
|
|
@@ -5535,6 +8064,64 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
5535
8064
|
(openPageSettings)="openPageSettings()"
|
|
5536
8065
|
/>
|
|
5537
8066
|
|
|
8067
|
+
<praxis-ai-assistant-shell
|
|
8068
|
+
*ngIf="showSettings() && enableAgenticAuthoring && agenticAuthoringOpen()"
|
|
8069
|
+
panelTestId="page-builder-agentic-authoring-panel"
|
|
8070
|
+
testIdPrefix="page-builder-agentic"
|
|
8071
|
+
submitTestId="page-builder-agentic-preview"
|
|
8072
|
+
applyTestId="page-builder-agentic-persist"
|
|
8073
|
+
[labels]="agenticAuthoringShellLabels()"
|
|
8074
|
+
mode="agentic-authoring"
|
|
8075
|
+
[state]="agenticAuthoringShellState()"
|
|
8076
|
+
[contextItems]="agenticAuthoringContextItems()"
|
|
8077
|
+
[attachments]="agenticAuthoringAttachments()"
|
|
8078
|
+
[messages]="agenticAuthoringConversation()"
|
|
8079
|
+
[quickReplies]="agenticAuthoringQuickReplies()"
|
|
8080
|
+
[prompt]="agenticAuthoringPrompt()"
|
|
8081
|
+
[statusText]="agenticAuthoringStatus()"
|
|
8082
|
+
[errorText]="agenticAuthoringError()"
|
|
8083
|
+
[busy]="agenticAuthoringBusy()"
|
|
8084
|
+
[canApply]="!!agenticAuthoringPreviewResult()?.valid"
|
|
8085
|
+
[enableFileAttachments]="true"
|
|
8086
|
+
attachmentAccept="image/*,application/json,text/plain,application/pdf"
|
|
8087
|
+
[layout]="agenticAuthoringPanelLayout()"
|
|
8088
|
+
[minWidth]="320"
|
|
8089
|
+
[minHeight]="280"
|
|
8090
|
+
[margin]="8"
|
|
8091
|
+
(promptChange)="agenticAuthoringPrompt.set($event)"
|
|
8092
|
+
(submitPrompt)="agenticAuthoringPrompt.set($event); previewAgenticAuthoring()"
|
|
8093
|
+
(apply)="persistAgenticAuthoring()"
|
|
8094
|
+
(quickReply)="submitAgenticQuickReply($event)"
|
|
8095
|
+
(attach)="attachAgenticContext()"
|
|
8096
|
+
(attachmentsPasted)="addAgenticAttachments($event)"
|
|
8097
|
+
(attachmentsSelected)="addAgenticAttachments($event)"
|
|
8098
|
+
(removeAttachment)="removeAgenticAttachment($event)"
|
|
8099
|
+
(editMessage)="editAgenticMessage($event)"
|
|
8100
|
+
(resendMessage)="resendAgenticMessage($event)"
|
|
8101
|
+
(layoutChange)="agenticAuthoringPanelLayout.set($event)"
|
|
8102
|
+
(close)="toggleAgenticAuthoring()"
|
|
8103
|
+
/>
|
|
8104
|
+
|
|
8105
|
+
<section
|
|
8106
|
+
*ngIf="agenticAuthoringIncludeLlmDiagnostics && agenticAuthoringLlmDiagnosticsText()"
|
|
8107
|
+
class="agentic-diagnostics-panel"
|
|
8108
|
+
data-testid="page-builder-agentic-llm-diagnostics"
|
|
8109
|
+
role="region"
|
|
8110
|
+
[attr.aria-label]="tx('agentic.diagnostics.title', 'LLM diagnostics')"
|
|
8111
|
+
[style.top.px]="agenticAuthoringDiagnosticsTop()"
|
|
8112
|
+
>
|
|
8113
|
+
<header class="agentic-diagnostics-panel__header">
|
|
8114
|
+
<span>{{ tx('agentic.diagnostics.title', 'LLM diagnostics') }}</span>
|
|
8115
|
+
<span class="agentic-diagnostics-panel__badge">
|
|
8116
|
+
{{ tx('agentic.diagnostics.badge', 'Debug') }}
|
|
8117
|
+
</span>
|
|
8118
|
+
</header>
|
|
8119
|
+
<p class="agentic-diagnostics-panel__description">
|
|
8120
|
+
{{ tx('agentic.diagnostics.description', 'Prompt, context bundle, and tool catalog returned by the backend for this turn.') }}
|
|
8121
|
+
</p>
|
|
8122
|
+
<pre>{{ agenticAuthoringLlmDiagnosticsText() }}</pre>
|
|
8123
|
+
</section>
|
|
8124
|
+
|
|
5538
8125
|
<praxis-floating-toolbar
|
|
5539
8126
|
[visible]="showSettings()"
|
|
5540
8127
|
[canUndo]="false"
|
|
@@ -5544,6 +8131,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
5544
8131
|
(save)="saveCurrentPage()"
|
|
5545
8132
|
(preview)="togglePreview()"
|
|
5546
8133
|
>
|
|
8134
|
+
<button
|
|
8135
|
+
*ngIf="enableAgenticAuthoring"
|
|
8136
|
+
pdx-toolbar-extra
|
|
8137
|
+
mat-mini-fab
|
|
8138
|
+
type="button"
|
|
8139
|
+
[attr.data-testid]="'page-builder-agentic-toggle'"
|
|
8140
|
+
[matTooltip]="tx('agentic.toggle', 'Create with AI')"
|
|
8141
|
+
[attr.aria-label]="tx('agentic.toggle', 'Create with AI')"
|
|
8142
|
+
(click)="toggleAgenticAuthoring()"
|
|
8143
|
+
>
|
|
8144
|
+
<mat-icon [praxisIcon]="'auto_awesome'"></mat-icon>
|
|
8145
|
+
</button>
|
|
5547
8146
|
<button
|
|
5548
8147
|
pdx-toolbar-extra
|
|
5549
8148
|
mat-mini-fab
|
|
@@ -5557,7 +8156,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
5557
8156
|
</button>
|
|
5558
8157
|
</praxis-floating-toolbar>
|
|
5559
8158
|
</div>
|
|
5560
|
-
`, styles: [":host
|
|
8159
|
+
`, 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%}.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__header{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:13px;font-weight:700}.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__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}\n"] }]
|
|
5561
8160
|
}], ctorParameters: () => [{ type: i1.MatDialog }, { type: undefined, decorators: [{
|
|
5562
8161
|
type: Optional
|
|
5563
8162
|
}, {
|
|
@@ -5572,6 +8171,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
5572
8171
|
type: Input
|
|
5573
8172
|
}], strictValidation: [{
|
|
5574
8173
|
type: Input
|
|
8174
|
+
}], autoPersist: [{
|
|
8175
|
+
type: Input
|
|
5575
8176
|
}], enableCustomization: [{
|
|
5576
8177
|
type: Input
|
|
5577
8178
|
}], showSettingsButton: [{
|
|
@@ -5582,8 +8183,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
5582
8183
|
type: Input
|
|
5583
8184
|
}], pageEditorComponent: [{
|
|
5584
8185
|
type: Input
|
|
8186
|
+
}], enableAgenticAuthoring: [{
|
|
8187
|
+
type: Input
|
|
8188
|
+
}], agenticAuthoringProvider: [{
|
|
8189
|
+
type: Input
|
|
8190
|
+
}], agenticAuthoringModel: [{
|
|
8191
|
+
type: Input
|
|
8192
|
+
}], agenticAuthoringApiKey: [{
|
|
8193
|
+
type: Input
|
|
8194
|
+
}], agenticAuthoringComponentId: [{
|
|
8195
|
+
type: Input
|
|
8196
|
+
}], agenticAuthoringScope: [{
|
|
8197
|
+
type: Input
|
|
8198
|
+
}], agenticAuthoringEtag: [{
|
|
8199
|
+
type: Input
|
|
8200
|
+
}], agenticAuthoringIncludeLlmDiagnostics: [{
|
|
8201
|
+
type: Input
|
|
8202
|
+
}], agenticAuthoringEnableStreaming: [{
|
|
8203
|
+
type: Input
|
|
5585
8204
|
}], pageChange: [{
|
|
5586
8205
|
type: Output
|
|
8206
|
+
}], agenticAuthoringApplied: [{
|
|
8207
|
+
type: Output
|
|
5587
8208
|
}] } });
|
|
5588
8209
|
|
|
5589
8210
|
/*
|
|
@@ -5595,4 +8216,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
5595
8216
|
* Generated bundle index. Do not edit.
|
|
5596
8217
|
*/
|
|
5597
8218
|
|
|
5598
|
-
export { ComponentPaletteDialogComponent, ConfirmDialogComponent, DynamicPageBuilderComponent, DynamicPageConfigEditorComponent, FloatingToolbarComponent, PAGE_BUILDER_AI_CAPABILITIES, PAGE_BUILDER_WIDGET_AI_CATALOGS, PLACEHOLDER, PageConfigEditorComponent, TileToolbarComponent, WidgetShellEditorComponent, clearWidgetAiCatalogs, getPageAiCatalog, getWidgetAiCapabilities, providePageBuilderWidgetAiCatalogs, registerWidgetAiCatalog, registerWidgetAiCatalogs };
|
|
8219
|
+
export { ComponentPaletteDialogComponent, ConfirmDialogComponent, DynamicPageBuilderComponent, DynamicPageConfigEditorComponent, FloatingToolbarComponent, PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS, PAGE_BUILDER_AI_CAPABILITIES, PAGE_BUILDER_WIDGET_AI_CATALOGS, PLACEHOLDER, PageBuilderAgenticAuthoringService, PageConfigEditorComponent, TileToolbarComponent, WidgetShellEditorComponent, clearWidgetAiCatalogs, getPageAiCatalog, getWidgetAiCapabilities, providePageBuilderWidgetAiCatalogs, registerWidgetAiCatalog, registerWidgetAiCatalogs };
|