@praxisui/page-builder 9.0.27 → 9.0.28

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.
@@ -180,6 +180,8 @@ class FloatingToolbarComponent {
180
180
  canRedo = false;
181
181
  showSave = true;
182
182
  showPreview = true;
183
+ showAdd = true;
184
+ showSettings = true;
183
185
  editingEnabled = true;
184
186
  previewActive = false;
185
187
  connectionMode = false;
@@ -198,7 +200,7 @@ class FloatingToolbarComponent {
198
200
  preview = new EventEmitter();
199
201
  save = new EventEmitter();
200
202
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FloatingToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
201
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: FloatingToolbarComponent, isStandalone: true, selector: "praxis-floating-toolbar", inputs: { visible: "visible", canUndo: "canUndo", canRedo: "canRedo", showSave: "showSave", showPreview: "showPreview", editingEnabled: "editingEnabled", previewActive: "previewActive", connectionMode: "connectionMode", modeLabel: "modeLabel", addLabel: "addLabel", saveLabel: "saveLabel", undoLabel: "undoLabel", redoLabel: "redoLabel", settingsLabel: "settingsLabel", previewLabel: "previewLabel", exitPreviewLabel: "exitPreviewLabel" }, outputs: { add: "add", undo: "undo", redo: "redo", settings: "settings", preview: "preview", save: "save" }, ngImport: i0, template: `
203
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: FloatingToolbarComponent, isStandalone: true, selector: "praxis-floating-toolbar", inputs: { visible: "visible", canUndo: "canUndo", canRedo: "canRedo", showSave: "showSave", showPreview: "showPreview", showAdd: "showAdd", showSettings: "showSettings", editingEnabled: "editingEnabled", previewActive: "previewActive", connectionMode: "connectionMode", modeLabel: "modeLabel", addLabel: "addLabel", saveLabel: "saveLabel", undoLabel: "undoLabel", redoLabel: "redoLabel", settingsLabel: "settingsLabel", previewLabel: "previewLabel", exitPreviewLabel: "exitPreviewLabel" }, outputs: { add: "add", undo: "undo", redo: "redo", settings: "settings", preview: "preview", save: "save" }, ngImport: i0, template: `
202
204
  @if (visible) {
203
205
  <div
204
206
  class="pdx-floating-toolbar"
@@ -209,9 +211,11 @@ class FloatingToolbarComponent {
209
211
  <span class="pdx-mode-chip" [attr.data-testid]="'page-builder-toolbar-mode'">{{ modeLabel }}</span>
210
212
  }
211
213
  <div class="pdx-actions">
212
- <button mat-mini-fab color="primary" (click)="add.emit()" [disabled]="!editingEnabled" [matTooltip]="addLabel" [attr.aria-label]="addLabel">
213
- <mat-icon [praxisIcon]="'add'"></mat-icon>
214
- </button>
214
+ @if (showAdd) {
215
+ <button mat-mini-fab color="primary" (click)="add.emit()" [disabled]="!editingEnabled" [matTooltip]="addLabel" [attr.aria-label]="addLabel">
216
+ <mat-icon [praxisIcon]="'add'"></mat-icon>
217
+ </button>
218
+ }
215
219
  @if (showSave) {
216
220
  <button mat-mini-fab color="accent" (click)="save.emit()" [disabled]="!editingEnabled" [matTooltip]="saveLabel" [attr.aria-label]="saveLabel">
217
221
  <mat-icon [praxisIcon]="'save'"></mat-icon>
@@ -227,9 +231,11 @@ class FloatingToolbarComponent {
227
231
  <mat-icon [praxisIcon]="'redo'"></mat-icon>
228
232
  </button>
229
233
  }
230
- <button mat-mini-fab (click)="settings.emit()" [disabled]="!editingEnabled" [matTooltip]="settingsLabel" [attr.aria-label]="settingsLabel">
231
- <mat-icon [praxisIcon]="'settings'"></mat-icon>
232
- </button>
234
+ @if (showSettings) {
235
+ <button mat-mini-fab (click)="settings.emit()" [disabled]="!editingEnabled" [matTooltip]="settingsLabel" [attr.aria-label]="settingsLabel">
236
+ <mat-icon [praxisIcon]="'settings'"></mat-icon>
237
+ </button>
238
+ }
233
239
  @if (showPreview) {
234
240
  <button
235
241
  mat-mini-fab
@@ -261,9 +267,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
261
267
  <span class="pdx-mode-chip" [attr.data-testid]="'page-builder-toolbar-mode'">{{ modeLabel }}</span>
262
268
  }
263
269
  <div class="pdx-actions">
264
- <button mat-mini-fab color="primary" (click)="add.emit()" [disabled]="!editingEnabled" [matTooltip]="addLabel" [attr.aria-label]="addLabel">
265
- <mat-icon [praxisIcon]="'add'"></mat-icon>
266
- </button>
270
+ @if (showAdd) {
271
+ <button mat-mini-fab color="primary" (click)="add.emit()" [disabled]="!editingEnabled" [matTooltip]="addLabel" [attr.aria-label]="addLabel">
272
+ <mat-icon [praxisIcon]="'add'"></mat-icon>
273
+ </button>
274
+ }
267
275
  @if (showSave) {
268
276
  <button mat-mini-fab color="accent" (click)="save.emit()" [disabled]="!editingEnabled" [matTooltip]="saveLabel" [attr.aria-label]="saveLabel">
269
277
  <mat-icon [praxisIcon]="'save'"></mat-icon>
@@ -279,9 +287,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
279
287
  <mat-icon [praxisIcon]="'redo'"></mat-icon>
280
288
  </button>
281
289
  }
282
- <button mat-mini-fab (click)="settings.emit()" [disabled]="!editingEnabled" [matTooltip]="settingsLabel" [attr.aria-label]="settingsLabel">
283
- <mat-icon [praxisIcon]="'settings'"></mat-icon>
284
- </button>
290
+ @if (showSettings) {
291
+ <button mat-mini-fab (click)="settings.emit()" [disabled]="!editingEnabled" [matTooltip]="settingsLabel" [attr.aria-label]="settingsLabel">
292
+ <mat-icon [praxisIcon]="'settings'"></mat-icon>
293
+ </button>
294
+ }
285
295
  @if (showPreview) {
286
296
  <button
287
297
  mat-mini-fab
@@ -309,6 +319,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
309
319
  type: Input
310
320
  }], showPreview: [{
311
321
  type: Input
322
+ }], showAdd: [{
323
+ type: Input
324
+ }], showSettings: [{
325
+ type: Input
312
326
  }], editingEnabled: [{
313
327
  type: Input
314
328
  }], previewActive: [{
@@ -2227,13 +2241,17 @@ const SET_INPUT_PRESETS = {
2227
2241
  class WidgetShellEditorComponent {
2228
2242
  registry;
2229
2243
  form = new FormGroup({
2230
- kind: new FormControl('dashboard-card', { nonNullable: true }),
2244
+ kind: new FormControl('dashboard-card', {
2245
+ nonNullable: true,
2246
+ }),
2231
2247
  preset: new FormControl('', { nonNullable: true }),
2232
2248
  applyToAll: new FormControl(false, { nonNullable: true }),
2233
2249
  title: new FormControl('', { nonNullable: true }),
2234
2250
  subtitle: new FormControl('', { nonNullable: true }),
2235
2251
  icon: new FormControl('', { nonNullable: true }),
2236
- showHeader: new FormControl('auto', { nonNullable: true }),
2252
+ showHeader: new FormControl('auto', {
2253
+ nonNullable: true,
2254
+ }),
2237
2255
  collapsible: new FormControl(true, { nonNullable: true }),
2238
2256
  cardBg: new FormControl('', { nonNullable: true }),
2239
2257
  cardBorder: new FormControl('', { nonNullable: true }),
@@ -2263,8 +2281,12 @@ class WidgetShellEditorComponent {
2263
2281
  initialTitle;
2264
2282
  initialSubtitle;
2265
2283
  actionCopySources = new WeakMap();
2266
- presetOptions = [...BUILTIN_PRESET_OPTIONS];
2267
- presets = { ...BUILTIN_PRESET_MAP };
2284
+ presetOptions = [
2285
+ ...BUILTIN_PRESET_OPTIONS,
2286
+ ];
2287
+ presets = {
2288
+ ...BUILTIN_PRESET_MAP,
2289
+ };
2268
2290
  availableActions = [];
2269
2291
  actionQuery = new FormControl('', { nonNullable: true });
2270
2292
  showScopeShell = true;
@@ -2277,10 +2299,15 @@ class WidgetShellEditorComponent {
2277
2299
  previewCollapsed = false;
2278
2300
  previewExpanded = false;
2279
2301
  pagePreset = null;
2302
+ authoringCapabilities;
2280
2303
  constructor(data, registry) {
2281
2304
  this.registry = registry;
2305
+ this.authoringCapabilities = data?.authoringCapabilities ?? null;
2282
2306
  const customPresets = data?.presets || {};
2283
- const customOptions = Object.keys(customPresets).map((id) => ({ id, label: id }));
2307
+ const customOptions = Object.keys(customPresets).map((id) => ({
2308
+ id,
2309
+ label: id,
2310
+ }));
2284
2311
  this.presetOptions = [...BUILTIN_PRESET_OPTIONS, ...customOptions];
2285
2312
  this.presets = { ...BUILTIN_PRESET_MAP, ...customPresets };
2286
2313
  this.pagePreset = data?.pagePreset || null;
@@ -2289,9 +2316,7 @@ class WidgetShellEditorComponent {
2289
2316
  this.applyShell(shell);
2290
2317
  this.loadAvailableActions(data?.widgetType || null);
2291
2318
  this.loadSetInputPresets(data?.widgetType || null);
2292
- this.form.valueChanges
2293
- .pipe(takeUntilDestroyed())
2294
- .subscribe(() => {
2319
+ this.form.valueChanges.pipe(takeUntilDestroyed()).subscribe(() => {
2295
2320
  this.validSubject.next(this.form.valid);
2296
2321
  const current = this.snapshotValue();
2297
2322
  this.dirtySubject.next(current !== this.snapshot);
@@ -2317,10 +2342,26 @@ class WidgetShellEditorComponent {
2317
2342
  get hasAvailableActions() {
2318
2343
  return !!this.availableActions.length;
2319
2344
  }
2345
+ canEditShellIdentity() {
2346
+ return this.isShellCapabilityEnabled('identity');
2347
+ }
2348
+ canEditShellAppearance() {
2349
+ return this.isShellCapabilityEnabled('appearance');
2350
+ }
2351
+ canEditShellActions() {
2352
+ return this.isShellCapabilityEnabled('actions');
2353
+ }
2354
+ canPromotePagePreset() {
2355
+ return this.isShellCapabilityEnabled('pagePreset');
2356
+ }
2320
2357
  addAction(seed) {
2358
+ if (!this.canEditShellActions())
2359
+ return;
2321
2360
  this.actions.push(this.createActionGroup(seed));
2322
2361
  }
2323
2362
  removeAction(index) {
2363
+ if (!this.canEditShellActions())
2364
+ return;
2324
2365
  this.actions.removeAt(index);
2325
2366
  }
2326
2367
  getSettingsValue() {
@@ -2405,58 +2446,106 @@ class WidgetShellEditorComponent {
2405
2446
  }
2406
2447
  createActionGroup(seed) {
2407
2448
  const group = new FormGroup({
2408
- id: new FormControl(seed?.id || '', { nonNullable: true, validators: [Validators.required] }),
2409
- label: new FormControl(this.editableText(seed?.label), { nonNullable: true }),
2449
+ id: new FormControl(seed?.id || '', {
2450
+ nonNullable: true,
2451
+ validators: [Validators.required],
2452
+ }),
2453
+ label: new FormControl(this.editableText(seed?.label), {
2454
+ nonNullable: true,
2455
+ }),
2410
2456
  icon: new FormControl(seed?.icon || '', { nonNullable: true }),
2411
2457
  variant: new FormControl(seed?.variant || 'text', { nonNullable: true }),
2412
2458
  placement: new FormControl(seed?.placement || 'header', { nonNullable: true }),
2413
2459
  emit: new FormControl(seed?.emit || '', { nonNullable: true }),
2414
- tooltip: new FormControl(this.editableText(seed?.tooltip), { nonNullable: true }),
2415
- command: new FormControl(seed?.command || '', { nonNullable: true }),
2460
+ tooltip: new FormControl(this.editableText(seed?.tooltip), {
2461
+ nonNullable: true,
2462
+ }),
2463
+ command: new FormControl(seed?.command || '', {
2464
+ nonNullable: true,
2465
+ }),
2416
2466
  payload: new FormControl(seed?.payload != null ? JSON.stringify(seed.payload) : '', { nonNullable: true }),
2417
- visible: new FormControl(seed?.visible !== false, { nonNullable: true }),
2418
- disabled: new FormControl(!!seed?.disabled, { nonNullable: true }),
2467
+ visible: new FormControl(seed?.visible !== false, {
2468
+ nonNullable: true,
2469
+ }),
2470
+ disabled: new FormControl(!!seed?.disabled, {
2471
+ nonNullable: true,
2472
+ }),
2473
+ });
2474
+ this.actionCopySources.set(group, {
2475
+ label: seed?.label,
2476
+ tooltip: seed?.tooltip,
2419
2477
  });
2420
- this.actionCopySources.set(group, { label: seed?.label, tooltip: seed?.tooltip });
2421
2478
  return group;
2422
2479
  }
2423
2480
  buildShell() {
2424
2481
  const raw = this.form.getRawValue();
2425
- if (raw.kind === 'none') {
2426
- return { kind: 'none' };
2427
- }
2428
- const shell = {};
2429
- if (raw.preset)
2430
- shell.preset = raw.preset;
2431
- const title = this.preserveTextDescriptor(this.initialTitle, raw.title);
2432
- const subtitle = this.preserveTextDescriptor(this.initialSubtitle, raw.subtitle);
2433
- if (title)
2434
- shell.title = title;
2435
- if (subtitle)
2436
- shell.subtitle = subtitle;
2437
- if (raw.icon.trim())
2438
- shell.icon = raw.icon.trim();
2439
- if (raw.showHeader !== 'auto')
2440
- shell.showHeader = raw.showHeader === 'true';
2441
- const windowActions = {};
2442
- if (!raw.collapsible)
2443
- windowActions.collapsible = false;
2444
- if (Object.keys(windowActions).length)
2445
- shell.windowActions = windowActions;
2446
- const actions = this.actions.controls
2447
- .map((group) => this.normalizeAction(group.getRawValue(), this.actionCopySources.get(group)))
2448
- .filter((a) => a.id);
2449
- if (actions.length)
2450
- shell.actions = actions;
2451
- const appearance = this.buildAppearance(raw);
2452
- if (appearance)
2453
- shell.appearance = appearance;
2482
+ if (this.canEditShellIdentity() && raw.kind === 'none') {
2483
+ return {
2484
+ ...(this.initialShell.value || {}),
2485
+ kind: 'none',
2486
+ };
2487
+ }
2488
+ const initial = this.initialShell.value;
2489
+ const shell = initial ? { ...initial } : {};
2490
+ if (this.canEditShellIdentity()) {
2491
+ delete shell.kind;
2492
+ delete shell.preset;
2493
+ delete shell.title;
2494
+ delete shell.subtitle;
2495
+ delete shell.icon;
2496
+ delete shell.showHeader;
2497
+ if (raw.preset)
2498
+ shell.preset = raw.preset;
2499
+ const title = this.preserveTextDescriptor(this.initialTitle, raw.title);
2500
+ const subtitle = this.preserveTextDescriptor(this.initialSubtitle, raw.subtitle);
2501
+ if (title)
2502
+ shell.title = title;
2503
+ if (subtitle)
2504
+ shell.subtitle = subtitle;
2505
+ if (raw.icon.trim())
2506
+ shell.icon = raw.icon.trim();
2507
+ if (raw.showHeader !== 'auto')
2508
+ shell.showHeader = raw.showHeader === 'true';
2509
+ const windowActions = {
2510
+ ...(initial?.windowActions || {}),
2511
+ };
2512
+ if (raw.collapsible)
2513
+ delete windowActions.collapsible;
2514
+ else
2515
+ windowActions.collapsible = false;
2516
+ if (Object.keys(windowActions).length)
2517
+ shell.windowActions = windowActions;
2518
+ else
2519
+ delete shell.windowActions;
2520
+ }
2521
+ if (this.canEditShellActions()) {
2522
+ const actions = this.actions.controls
2523
+ .map((group) => this.normalizeAction(group.getRawValue(), this.actionCopySources.get(group)))
2524
+ .filter((a) => a.id);
2525
+ if (actions.length)
2526
+ shell.actions = actions;
2527
+ else
2528
+ delete shell.actions;
2529
+ }
2530
+ else if (initial?.actions) {
2531
+ shell.actions = initial.actions.map((action) => ({ ...action }));
2532
+ }
2533
+ if (this.canEditShellAppearance()) {
2534
+ const appearance = this.buildAppearance(raw);
2535
+ if (appearance)
2536
+ shell.appearance = appearance;
2537
+ else
2538
+ delete shell.appearance;
2539
+ }
2540
+ else if (initial?.appearance) {
2541
+ shell.appearance = this.cloneAppearance(initial.appearance);
2542
+ }
2454
2543
  return shell;
2455
2544
  }
2456
2545
  buildResult() {
2457
2546
  const raw = this.form.getRawValue();
2458
2547
  const shell = this.buildShell();
2459
- const applyToAll = !!raw.applyToAll && !!raw.preset;
2548
+ const applyToAll = this.canPromotePagePreset() && !!raw.applyToAll && !!raw.preset;
2460
2549
  return {
2461
2550
  shell,
2462
2551
  applyToAll,
@@ -2509,6 +2598,24 @@ class WidgetShellEditorComponent {
2509
2598
  appearance.typography = typography;
2510
2599
  return Object.keys(appearance).length ? appearance : undefined;
2511
2600
  }
2601
+ cloneAppearance(appearance) {
2602
+ return {
2603
+ ...(appearance.card ? { card: { ...appearance.card } } : {}),
2604
+ ...(appearance.header ? { header: { ...appearance.header } } : {}),
2605
+ ...(appearance.body ? { body: { ...appearance.body } } : {}),
2606
+ ...(appearance.typography
2607
+ ? { typography: { ...appearance.typography } }
2608
+ : {}),
2609
+ };
2610
+ }
2611
+ isShellCapabilityEnabled(capability) {
2612
+ const shellCapabilities = this.authoringCapabilities?.widgetShell;
2613
+ if (shellCapabilities === false)
2614
+ return false;
2615
+ if (!shellCapabilities || shellCapabilities === true)
2616
+ return true;
2617
+ return shellCapabilities[capability] !== false;
2618
+ }
2512
2619
  previewVars() {
2513
2620
  const appearance = this.buildPreviewAppearance();
2514
2621
  return {
@@ -2688,6 +2795,8 @@ class WidgetShellEditorComponent {
2688
2795
  return this.findActionIndex(action) >= 0;
2689
2796
  }
2690
2797
  toggleAvailableAction(action) {
2798
+ if (!this.canEditShellActions())
2799
+ return;
2691
2800
  const idx = this.findActionIndex(action);
2692
2801
  if (idx >= 0) {
2693
2802
  this.removeAction(idx);
@@ -2748,6 +2857,8 @@ class WidgetShellEditorComponent {
2748
2857
  return preset?.values || [];
2749
2858
  }
2750
2859
  addSetInputAction() {
2860
+ if (!this.canEditShellActions())
2861
+ return;
2751
2862
  const preset = this.setInputPresets.find((p) => p.input === this.setInputTarget.value);
2752
2863
  if (!preset)
2753
2864
  return;
@@ -2800,136 +2911,217 @@ class WidgetShellEditorComponent {
2800
2911
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: WidgetShellEditorComponent, deps: [{ token: SETTINGS_PANEL_DATA, optional: true }, { token: i2$2.ComponentMetadataRegistry, optional: true }], target: i0.ɵɵFactoryTarget.Component });
2801
2912
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: WidgetShellEditorComponent, isStandalone: true, selector: "praxis-widget-shell-editor", ngImport: i0, template: `
2802
2913
  <div class="shell-editor">
2803
- <p class="shell-intro">
2804
- Defina a identidade, a aparência e as ações do card. Use a prévia para conferir o resultado antes de salvar.
2805
- </p>
2806
-
2807
- <div class="shell-section">Geral</div>
2808
- <div class="shell-grid">
2809
- <mat-form-field appearance="outline">
2810
- <mat-label>Tipo de card</mat-label>
2811
- <mat-select [formControl]="form.controls.kind">
2812
- <mat-option value="dashboard-card">Dashboard Card</mat-option>
2813
- <mat-option value="none">Sem shell</mat-option>
2814
- </mat-select>
2815
- </mat-form-field>
2816
- <mat-form-field appearance="outline">
2817
- <mat-label>Preset</mat-label>
2818
- <mat-select [formControl]="form.controls.preset">
2819
- <mat-option value="">Nenhum</mat-option>
2820
- @if (pagePreset) {
2821
- <mat-option [value]="pagePreset">Usar preset da página ({{ pagePreset }})</mat-option>
2822
- }
2823
- @for (p of presetOptions; track p) {
2824
- <mat-option [value]="p.id">{{ p.label }}</mat-option>
2825
- }
2826
- </mat-select>
2827
- </mat-form-field>
2828
- @if (!form.controls.preset.value && pagePreset) {
2829
- <div class="shell-hint">
2830
- Preset da página: {{ pagePreset }}
2831
- </div>
2832
- }
2833
- @if (form.controls.preset.value) {
2834
- <mat-checkbox [formControl]="form.controls.applyToAll">
2835
- Aplicar preset como padrão da página
2836
- </mat-checkbox>
2837
- }
2838
- <mat-form-field appearance="outline">
2839
- <mat-label>Ícone</mat-label>
2840
- <input matInput [formControl]="form.controls.icon" placeholder="ex: badge" />
2841
- </mat-form-field>
2842
- <mat-form-field appearance="outline">
2843
- <mat-label>Título</mat-label>
2844
- <input matInput [formControl]="form.controls.title" />
2845
- </mat-form-field>
2846
- <mat-form-field appearance="outline" class="shell-field--wide">
2847
- <mat-label>Subtítulo</mat-label>
2848
- <input matInput [formControl]="form.controls.subtitle" />
2849
- </mat-form-field>
2850
- <mat-form-field appearance="outline">
2851
- <mat-label>Mostrar cabeçalho</mat-label>
2852
- <mat-select [formControl]="form.controls.showHeader">
2853
- <mat-option value="auto">Automático</mat-option>
2854
- <mat-option value="true">Sempre</mat-option>
2855
- <mat-option value="false">Nunca</mat-option>
2856
- </mat-select>
2857
- </mat-form-field>
2858
- </div>
2859
-
2860
- <div class="shell-section">Controles de janela</div>
2861
- <div class="shell-flags">
2862
- <mat-checkbox [formControl]="form.controls.collapsible">Permitir recolher</mat-checkbox>
2863
- </div>
2864
-
2865
- <mat-divider></mat-divider>
2866
-
2867
- <div class="shell-section">Aparência</div>
2868
- <div class="shell-grid">
2869
- <mat-form-field appearance="outline">
2870
- <mat-label>Fundo do card</mat-label>
2871
- <input matInput [formControl]="form.controls.cardBg" placeholder="ex: #0b1220" />
2872
- </mat-form-field>
2873
- <mat-form-field appearance="outline">
2874
- <mat-label>Cor da borda</mat-label>
2875
- <input matInput [formControl]="form.controls.cardBorder" placeholder="ex: rgba(255,255,255,0.12)" />
2876
- </mat-form-field>
2877
- <mat-form-field appearance="outline">
2878
- <mat-label>Raio da borda</mat-label>
2879
- <input matInput [formControl]="form.controls.cardRadius" placeholder="ex: 14px" />
2880
- </mat-form-field>
2881
- <mat-form-field appearance="outline">
2882
- <mat-label>Sombra</mat-label>
2883
- <input matInput [formControl]="form.controls.cardShadow" placeholder="ex: 0 10px 30px rgba(0,0,0,0.2)" />
2884
- </mat-form-field>
2885
- <mat-form-field appearance="outline">
2886
- <mat-label>Fundo do cabeçalho</mat-label>
2887
- <input matInput [formControl]="form.controls.headerBg" placeholder="ex: linear-gradient(...)" />
2888
- </mat-form-field>
2889
- <mat-form-field appearance="outline">
2890
- <mat-label>Borda do cabeçalho</mat-label>
2891
- <input matInput [formControl]="form.controls.headerBorder" placeholder="ex: rgba(255,255,255,0.08)" />
2892
- </mat-form-field>
2893
- <mat-form-field appearance="outline">
2894
- <mat-label>Cor do título</mat-label>
2895
- <input matInput [formControl]="form.controls.titleColor" placeholder="ex: #e6edf3" />
2896
- </mat-form-field>
2897
- <mat-form-field appearance="outline">
2898
- <mat-label>Cor do subtítulo</mat-label>
2899
- <input matInput [formControl]="form.controls.subtitleColor" placeholder="ex: #9fb0c4" />
2900
- </mat-form-field>
2901
- <mat-form-field appearance="outline">
2902
- <mat-label>Cor do ícone</mat-label>
2903
- <input matInput [formControl]="form.controls.iconColor" placeholder="ex: #8ab4ff" />
2904
- </mat-form-field>
2905
- <mat-form-field appearance="outline">
2906
- <mat-label>Fundo do corpo</mat-label>
2907
- <input matInput [formControl]="form.controls.bodyBg" placeholder="ex: transparent" />
2908
- </mat-form-field>
2909
- <mat-form-field appearance="outline">
2910
- <mat-label>Cor do texto do corpo</mat-label>
2911
- <input matInput [formControl]="form.controls.bodyColor" placeholder="ex: #e6edf3" />
2912
- </mat-form-field>
2913
- <mat-form-field appearance="outline">
2914
- <mat-label>Padding do corpo</mat-label>
2915
- <input matInput [formControl]="form.controls.bodyPadding" placeholder="ex: 10px 12px 12px" />
2916
- </mat-form-field>
2917
- <mat-form-field appearance="outline">
2918
- <mat-label>Tamanho do título</mat-label>
2919
- <input matInput [formControl]="form.controls.titleSize" placeholder="ex: 14px" />
2920
- </mat-form-field>
2921
- <mat-form-field appearance="outline">
2922
- <mat-label>Peso do título</mat-label>
2923
- <input matInput [formControl]="form.controls.titleWeight" placeholder="ex: 600" />
2924
- </mat-form-field>
2925
- <mat-form-field appearance="outline">
2926
- <mat-label>Tamanho do subtítulo</mat-label>
2927
- <input matInput [formControl]="form.controls.subtitleSize" placeholder="ex: 12px" />
2928
- </mat-form-field>
2929
- </div>
2930
-
2914
+ @if (
2915
+ canEditShellIdentity() &&
2916
+ canEditShellAppearance() &&
2917
+ canEditShellActions()
2918
+ ) {
2919
+ <p class="shell-intro">
2920
+ Defina a identidade, a aparência e as ações do card. Use a prévia para
2921
+ conferir o resultado antes de salvar.
2922
+ </p>
2923
+ }
2924
+
2925
+ @if (canEditShellIdentity()) {
2926
+ <div class="shell-section">Geral</div>
2927
+ <div class="shell-grid">
2928
+ <mat-form-field appearance="outline">
2929
+ <mat-label>Tipo de card</mat-label>
2930
+ <mat-select [formControl]="form.controls.kind">
2931
+ <mat-option value="dashboard-card">Dashboard Card</mat-option>
2932
+ <mat-option value="none">Sem shell</mat-option>
2933
+ </mat-select>
2934
+ </mat-form-field>
2935
+ <mat-form-field appearance="outline">
2936
+ <mat-label>Preset</mat-label>
2937
+ <mat-select [formControl]="form.controls.preset">
2938
+ <mat-option value="">Nenhum</mat-option>
2939
+ @if (pagePreset) {
2940
+ <mat-option [value]="pagePreset"
2941
+ >Usar preset da página ({{ pagePreset }})</mat-option
2942
+ >
2943
+ }
2944
+ @for (p of presetOptions; track p) {
2945
+ <mat-option [value]="p.id">{{ p.label }}</mat-option>
2946
+ }
2947
+ </mat-select>
2948
+ </mat-form-field>
2949
+ @if (!form.controls.preset.value && pagePreset) {
2950
+ <div class="shell-hint">Preset da página: {{ pagePreset }}</div>
2951
+ }
2952
+ @if (canPromotePagePreset() && form.controls.preset.value) {
2953
+ <mat-checkbox [formControl]="form.controls.applyToAll">
2954
+ Aplicar preset como padrão da página
2955
+ </mat-checkbox>
2956
+ }
2957
+ <mat-form-field appearance="outline">
2958
+ <mat-label>Ícone</mat-label>
2959
+ <input
2960
+ matInput
2961
+ [formControl]="form.controls.icon"
2962
+ placeholder="ex: badge"
2963
+ />
2964
+ </mat-form-field>
2965
+ <mat-form-field appearance="outline">
2966
+ <mat-label>Título</mat-label>
2967
+ <input matInput [formControl]="form.controls.title" />
2968
+ </mat-form-field>
2969
+ <mat-form-field appearance="outline" class="shell-field--wide">
2970
+ <mat-label>Subtítulo</mat-label>
2971
+ <input matInput [formControl]="form.controls.subtitle" />
2972
+ </mat-form-field>
2973
+ <mat-form-field appearance="outline">
2974
+ <mat-label>Mostrar cabeçalho</mat-label>
2975
+ <mat-select [formControl]="form.controls.showHeader">
2976
+ <mat-option value="auto">Automático</mat-option>
2977
+ <mat-option value="true">Sempre</mat-option>
2978
+ <mat-option value="false">Nunca</mat-option>
2979
+ </mat-select>
2980
+ </mat-form-field>
2981
+ </div>
2982
+
2983
+ <div class="shell-section">Controles de janela</div>
2984
+ <div class="shell-flags">
2985
+ <mat-checkbox [formControl]="form.controls.collapsible"
2986
+ >Permitir recolher</mat-checkbox
2987
+ >
2988
+ </div>
2989
+ }
2990
+
2991
+ @if (canEditShellAppearance()) {
2992
+ <mat-divider></mat-divider>
2993
+
2994
+ <div class="shell-section">Aparência</div>
2995
+ <div class="shell-grid">
2996
+ <mat-form-field appearance="outline">
2997
+ <mat-label>Fundo do card</mat-label>
2998
+ <input
2999
+ matInput
3000
+ [formControl]="form.controls.cardBg"
3001
+ placeholder="ex: #0b1220"
3002
+ />
3003
+ </mat-form-field>
3004
+ <mat-form-field appearance="outline">
3005
+ <mat-label>Cor da borda</mat-label>
3006
+ <input
3007
+ matInput
3008
+ [formControl]="form.controls.cardBorder"
3009
+ placeholder="ex: rgba(255,255,255,0.12)"
3010
+ />
3011
+ </mat-form-field>
3012
+ <mat-form-field appearance="outline">
3013
+ <mat-label>Raio da borda</mat-label>
3014
+ <input
3015
+ matInput
3016
+ [formControl]="form.controls.cardRadius"
3017
+ placeholder="ex: 14px"
3018
+ />
3019
+ </mat-form-field>
3020
+ <mat-form-field appearance="outline">
3021
+ <mat-label>Sombra</mat-label>
3022
+ <input
3023
+ matInput
3024
+ [formControl]="form.controls.cardShadow"
3025
+ placeholder="ex: 0 10px 30px rgba(0,0,0,0.2)"
3026
+ />
3027
+ </mat-form-field>
3028
+ <mat-form-field appearance="outline">
3029
+ <mat-label>Fundo do cabeçalho</mat-label>
3030
+ <input
3031
+ matInput
3032
+ [formControl]="form.controls.headerBg"
3033
+ placeholder="ex: linear-gradient(...)"
3034
+ />
3035
+ </mat-form-field>
3036
+ <mat-form-field appearance="outline">
3037
+ <mat-label>Borda do cabeçalho</mat-label>
3038
+ <input
3039
+ matInput
3040
+ [formControl]="form.controls.headerBorder"
3041
+ placeholder="ex: rgba(255,255,255,0.08)"
3042
+ />
3043
+ </mat-form-field>
3044
+ <mat-form-field appearance="outline">
3045
+ <mat-label>Cor do título</mat-label>
3046
+ <input
3047
+ matInput
3048
+ [formControl]="form.controls.titleColor"
3049
+ placeholder="ex: #e6edf3"
3050
+ />
3051
+ </mat-form-field>
3052
+ <mat-form-field appearance="outline">
3053
+ <mat-label>Cor do subtítulo</mat-label>
3054
+ <input
3055
+ matInput
3056
+ [formControl]="form.controls.subtitleColor"
3057
+ placeholder="ex: #9fb0c4"
3058
+ />
3059
+ </mat-form-field>
3060
+ <mat-form-field appearance="outline">
3061
+ <mat-label>Cor do ícone</mat-label>
3062
+ <input
3063
+ matInput
3064
+ [formControl]="form.controls.iconColor"
3065
+ placeholder="ex: #8ab4ff"
3066
+ />
3067
+ </mat-form-field>
3068
+ <mat-form-field appearance="outline">
3069
+ <mat-label>Fundo do corpo</mat-label>
3070
+ <input
3071
+ matInput
3072
+ [formControl]="form.controls.bodyBg"
3073
+ placeholder="ex: transparent"
3074
+ />
3075
+ </mat-form-field>
3076
+ <mat-form-field appearance="outline">
3077
+ <mat-label>Cor do texto do corpo</mat-label>
3078
+ <input
3079
+ matInput
3080
+ [formControl]="form.controls.bodyColor"
3081
+ placeholder="ex: #e6edf3"
3082
+ />
3083
+ </mat-form-field>
3084
+ <mat-form-field appearance="outline">
3085
+ <mat-label>Padding do corpo</mat-label>
3086
+ <input
3087
+ matInput
3088
+ [formControl]="form.controls.bodyPadding"
3089
+ placeholder="ex: 10px 12px 12px"
3090
+ />
3091
+ </mat-form-field>
3092
+ <mat-form-field appearance="outline">
3093
+ <mat-label>Tamanho do título</mat-label>
3094
+ <input
3095
+ matInput
3096
+ [formControl]="form.controls.titleSize"
3097
+ placeholder="ex: 14px"
3098
+ />
3099
+ </mat-form-field>
3100
+ <mat-form-field appearance="outline">
3101
+ <mat-label>Peso do título</mat-label>
3102
+ <input
3103
+ matInput
3104
+ [formControl]="form.controls.titleWeight"
3105
+ placeholder="ex: 600"
3106
+ />
3107
+ </mat-form-field>
3108
+ <mat-form-field appearance="outline">
3109
+ <mat-label>Tamanho do subtítulo</mat-label>
3110
+ <input
3111
+ matInput
3112
+ [formControl]="form.controls.subtitleSize"
3113
+ placeholder="ex: 12px"
3114
+ />
3115
+ </mat-form-field>
3116
+ </div>
3117
+ }
3118
+
2931
3119
  <div class="shell-preview" [ngStyle]="previewVars()">
2932
- <div class="shell-preview-card" [class.no-shell]="form.controls.kind.value === 'none'" [class.expanded]="previewExpanded">
3120
+ <div
3121
+ class="shell-preview-card"
3122
+ [class.no-shell]="form.controls.kind.value === 'none'"
3123
+ [class.expanded]="previewExpanded"
3124
+ >
2933
3125
  @if (previewShowHeader()) {
2934
3126
  <div class="shell-preview-header">
2935
3127
  <div class="shell-preview-title">
@@ -2937,8 +3129,12 @@ class WidgetShellEditorComponent {
2937
3129
  <mat-icon [praxisIcon]="form.controls.icon.value"></mat-icon>
2938
3130
  }
2939
3131
  <div class="shell-preview-text">
2940
- <div class="shell-preview-title-text">{{ previewTitle() }}</div>
2941
- <div class="shell-preview-subtitle">{{ previewSubtitle() }}</div>
3132
+ <div class="shell-preview-title-text">
3133
+ {{ previewTitle() }}
3134
+ </div>
3135
+ <div class="shell-preview-subtitle">
3136
+ {{ previewSubtitle() }}
3137
+ </div>
2942
3138
  </div>
2943
3139
  </div>
2944
3140
  <div class="shell-preview-actions">
@@ -2946,13 +3142,19 @@ class WidgetShellEditorComponent {
2946
3142
  <button
2947
3143
  type="button"
2948
3144
  [disabled]="action.disabled"
2949
- [ngClass]="action.variant === 'outlined' ? 'pdx-preview-outlined' : 'pdx-preview-text'"
3145
+ [ngClass]="
3146
+ action.variant === 'outlined'
3147
+ ? 'pdx-preview-outlined'
3148
+ : 'pdx-preview-text'
3149
+ "
2950
3150
  mat-button
2951
- >
3151
+ >
2952
3152
  @if (action.icon) {
2953
3153
  <mat-icon [praxisIcon]="action.icon"></mat-icon>
2954
3154
  }
2955
- <span class="pdx-preview-label">{{ action.label || action.id }}</span>
3155
+ <span class="pdx-preview-label">{{
3156
+ action.label || action.id
3157
+ }}</span>
2956
3158
  </button>
2957
3159
  }
2958
3160
  @if (previewOverflowCount()) {
@@ -2975,14 +3177,18 @@ class WidgetShellEditorComponent {
2975
3177
  }
2976
3178
  }
2977
3179
  <button
2978
- [praxisIconButton]="previewCollapsed ? 'unfold_more' : 'unfold_less'"
3180
+ [praxisIconButton]="
3181
+ previewCollapsed ? 'unfold_more' : 'unfold_less'
3182
+ "
2979
3183
  size="compact"
2980
3184
  type="button"
2981
3185
  (click)="togglePreviewCollapse()"
2982
3186
  aria-label="Recolher"
2983
3187
  ></button>
2984
3188
  <button
2985
- [praxisIconButton]="previewExpanded ? 'close_fullscreen' : 'open_in_full'"
3189
+ [praxisIconButton]="
3190
+ previewExpanded ? 'close_fullscreen' : 'open_in_full'
3191
+ "
2986
3192
  size="compact"
2987
3193
  type="button"
2988
3194
  (click)="togglePreviewExpand()"
@@ -2991,27 +3197,34 @@ class WidgetShellEditorComponent {
2991
3197
  </div>
2992
3198
  </div>
2993
3199
  }
2994
- <div class="shell-preview-body" [class.hidden]="previewCollapsed">Conteudo do widget</div>
3200
+ <div class="shell-preview-body" [class.hidden]="previewCollapsed">
3201
+ Conteudo do widget
3202
+ </div>
2995
3203
  </div>
2996
3204
  </div>
2997
-
2998
- <mat-divider></mat-divider>
2999
-
3000
- @if (hasAvailableActions) {
3205
+
3206
+ @if (canEditShellActions() && hasAvailableActions) {
3207
+ <mat-divider></mat-divider>
3001
3208
  <div class="shell-section">Ações disponíveis</div>
3002
- }
3003
- @if (hasAvailableActions) {
3004
3209
  <div class="shell-available">
3005
3210
  <div class="shell-available-toolbar">
3006
3211
  <mat-form-field appearance="outline">
3007
3212
  <mat-label>Buscar ação</mat-label>
3008
- <input matInput [formControl]="actionQuery" placeholder="ex: export, editar, submit" />
3213
+ <input
3214
+ matInput
3215
+ [formControl]="actionQuery"
3216
+ placeholder="ex: export, editar, submit"
3217
+ />
3009
3218
  </mat-form-field>
3010
3219
  <div class="shell-available-filters">
3011
3220
  <mat-checkbox [(ngModel)]="showScopeShell">Shell</mat-checkbox>
3012
3221
  <mat-checkbox [(ngModel)]="showScopeAny">Any</mat-checkbox>
3013
- <mat-checkbox [(ngModel)]="showScopeToolbar">Toolbar</mat-checkbox>
3014
- <mat-checkbox [(ngModel)]="showScopeContext">Context</mat-checkbox>
3222
+ <mat-checkbox [(ngModel)]="showScopeToolbar"
3223
+ >Toolbar</mat-checkbox
3224
+ >
3225
+ <mat-checkbox [(ngModel)]="showScopeContext"
3226
+ >Context</mat-checkbox
3227
+ >
3015
3228
  </div>
3016
3229
  </div>
3017
3230
  <div class="shell-available-list">
@@ -3023,31 +3236,47 @@ class WidgetShellEditorComponent {
3023
3236
  <mat-icon [praxisIcon]="action.icon"></mat-icon>
3024
3237
  }
3025
3238
  <div class="shell-available-text">
3026
- <div class="shell-available-label">{{ action.label }}</div>
3239
+ <div class="shell-available-label">
3240
+ {{ action.label }}
3241
+ </div>
3027
3242
  <div class="shell-available-meta">
3028
- <span class="shell-badge">{{ action.kind === 'command' ? 'Comando' : 'Ação' }}</span>
3029
- <span class="shell-badge">{{ scopeLabel(action.scope) }}</span>
3243
+ <span class="shell-badge">{{
3244
+ action.kind === 'command' ? 'Comando' : 'Ação'
3245
+ }}</span>
3246
+ <span class="shell-badge">{{
3247
+ scopeLabel(action.scope)
3248
+ }}</span>
3030
3249
  <span class="shell-code">id: {{ action.id }}</span>
3031
3250
  @if (action.emit) {
3032
- <span class="shell-code">emit: {{ action.emit }}</span>
3251
+ <span class="shell-code"
3252
+ >emit: {{ action.emit }}</span
3253
+ >
3033
3254
  }
3034
3255
  @if (action.command) {
3035
- <span class="shell-code">command: {{ action.command }}</span>
3256
+ <span class="shell-code"
3257
+ >command: {{ action.command }}</span
3258
+ >
3036
3259
  }
3037
3260
  </div>
3038
3261
  </div>
3039
3262
  </div>
3040
3263
  @if (action.description) {
3041
- <div class="shell-available-desc">{{ action.description }}</div>
3264
+ <div class="shell-available-desc">
3265
+ {{ action.description }}
3266
+ </div>
3042
3267
  }
3043
3268
  @if (action.payloadExample !== undefined) {
3044
3269
  <div class="shell-available-payload">
3045
- <span class="shell-code">payload: {{ stringifyPayload(action.payloadExample) }}</span>
3270
+ <span class="shell-code"
3271
+ >payload:
3272
+ {{ stringifyPayload(action.payloadExample) }}</span
3273
+ >
3046
3274
  </div>
3047
3275
  }
3048
3276
  @if (action.scope === 'context') {
3049
3277
  <div class="shell-available-warning">
3050
- Essa ação depende de item/linha selecionado; payload fixo pode não funcionar.
3278
+ Essa ação depende de item/linha selecionado; payload fixo
3279
+ pode não funcionar.
3051
3280
  </div>
3052
3281
  }
3053
3282
  </div>
@@ -3057,7 +3286,7 @@ class WidgetShellEditorComponent {
3057
3286
  type="button"
3058
3287
  [color]="isActionSelected(action) ? 'warn' : 'primary'"
3059
3288
  (click)="toggleAvailableAction(action)"
3060
- >
3289
+ >
3061
3290
  {{ isActionSelected(action) ? 'Remover' : 'Adicionar' }}
3062
3291
  </button>
3063
3292
  </div>
@@ -3065,18 +3294,19 @@ class WidgetShellEditorComponent {
3065
3294
  }
3066
3295
  </div>
3067
3296
  </div>
3068
- } @else {
3069
- <div class="shell-empty">Nenhuma ação registrada para este componente.</div>
3297
+ } @else if (canEditShellActions()) {
3298
+ <mat-divider></mat-divider>
3299
+ <div class="shell-empty">
3300
+ Nenhuma ação registrada para este componente.
3301
+ </div>
3070
3302
  }
3071
-
3072
- @if (hasAvailableActions) {
3303
+
3304
+ @if (canEditShellActions() && hasAvailableActions) {
3073
3305
  <mat-divider></mat-divider>
3074
3306
  }
3075
-
3076
- @if (setInputPresets.length) {
3307
+
3308
+ @if (canEditShellActions() && setInputPresets.length) {
3077
3309
  <div class="shell-section">Ações rápidas (inputs)</div>
3078
- }
3079
- @if (setInputPresets.length) {
3080
3310
  <div class="shell-quick-inputs">
3081
3311
  <mat-form-field appearance="outline">
3082
3312
  <mat-label>Input</mat-label>
@@ -3109,18 +3339,32 @@ class WidgetShellEditorComponent {
3109
3339
  }
3110
3340
  </mat-select>
3111
3341
  </mat-form-field>
3112
- <button mat-flat-button color="primary" type="button" (click)="addSetInputAction()">
3342
+ <button
3343
+ mat-flat-button
3344
+ color="primary"
3345
+ type="button"
3346
+ (click)="addSetInputAction()"
3347
+ >
3113
3348
  Adicionar ação
3114
3349
  </button>
3115
3350
  </div>
3116
3351
  }
3117
-
3118
- <div class="shell-section shell-actions-head">
3119
- <div>Ações do cabeçalho</div>
3120
- <button mat-flat-button color="primary" type="button" (click)="addAction()">Adicionar ação</button>
3121
- </div>
3122
-
3123
- @if (actions.controls.length) {
3352
+
3353
+ @if (canEditShellActions()) {
3354
+ <div class="shell-section shell-actions-head">
3355
+ <div>Ações do cabeçalho</div>
3356
+ <button
3357
+ mat-flat-button
3358
+ color="primary"
3359
+ type="button"
3360
+ (click)="addAction()"
3361
+ >
3362
+ Adicionar ação
3363
+ </button>
3364
+ </div>
3365
+ }
3366
+
3367
+ @if (canEditShellActions() && actions.controls.length) {
3124
3368
  <div class="shell-actions">
3125
3369
  @for (action of actions.controls; track action; let i = $index) {
3126
3370
  <div class="shell-action" [formGroup]="action">
@@ -3156,7 +3400,11 @@ class WidgetShellEditorComponent {
3156
3400
  </mat-form-field>
3157
3401
  <mat-form-field appearance="outline">
3158
3402
  <mat-label>Emit</mat-label>
3159
- <input matInput formControlName="emit" placeholder="ex: editar" />
3403
+ <input
3404
+ matInput
3405
+ formControlName="emit"
3406
+ placeholder="ex: editar"
3407
+ />
3160
3408
  </mat-form-field>
3161
3409
  <mat-form-field appearance="outline">
3162
3410
  <mat-label>Tooltip</mat-label>
@@ -3166,32 +3414,50 @@ class WidgetShellEditorComponent {
3166
3414
  <div class="shell-action-row">
3167
3415
  <mat-form-field appearance="outline">
3168
3416
  <mat-label>Command</mat-label>
3169
- <input matInput formControlName="command" placeholder="ex: add-item" />
3417
+ <input
3418
+ matInput
3419
+ formControlName="command"
3420
+ placeholder="ex: add-item"
3421
+ />
3170
3422
  </mat-form-field>
3171
3423
  <mat-form-field appearance="outline">
3172
3424
  <mat-label>Payload (JSON)</mat-label>
3173
- <textarea matInput rows="2" formControlName="payload" placeholder='ex: {"foo":"bar"}'></textarea>
3425
+ <textarea
3426
+ matInput
3427
+ rows="2"
3428
+ formControlName="payload"
3429
+ placeholder='ex: {"foo":"bar"}'
3430
+ ></textarea>
3174
3431
  </mat-form-field>
3175
3432
  <mat-checkbox formControlName="visible">Visível</mat-checkbox>
3176
- <mat-checkbox formControlName="disabled">Desabilitado</mat-checkbox>
3433
+ <mat-checkbox formControlName="disabled"
3434
+ >Desabilitado</mat-checkbox
3435
+ >
3177
3436
  </div>
3178
3437
  @if (showActionInputPath(action.value)) {
3179
3438
  <div class="shell-action-hint">
3180
- Input: {{ displayInputPath(extractActionInput(action.value)) }}
3439
+ Input:
3440
+ {{ displayInputPath(extractActionInput(action.value)) }}
3181
3441
  </div>
3182
3442
  }
3183
3443
  <div class="shell-action-actions">
3184
- <button mat-stroked-button color="warn" type="button" (click)="removeAction(i)">Remover</button>
3444
+ <button
3445
+ mat-stroked-button
3446
+ color="warn"
3447
+ type="button"
3448
+ (click)="removeAction(i)"
3449
+ >
3450
+ Remover
3451
+ </button>
3185
3452
  </div>
3186
3453
  </div>
3187
3454
  }
3188
3455
  </div>
3189
- } @else {
3456
+ } @else if (canEditShellActions()) {
3190
3457
  <div class="shell-empty">Nenhuma ação configurada.</div>
3191
3458
  }
3192
-
3193
3459
  </div>
3194
- `, isInline: true, styles: [".shell-editor{display:grid;gap:20px;padding:12px 4px 20px}.shell-intro{margin:0;max-width:68ch;color:var(--md-sys-color-on-surface-variant);font-size:14px;line-height:1.5}.shell-section{margin:4px 0 -8px;color:var(--md-sys-color-on-surface);font-size:14px;font-weight:650;line-height:1.4}.shell-grid{display:grid;gap:12px 16px;grid-template-columns:repeat(2,minmax(0,1fr));align-items:start}.shell-field--wide{grid-column:1 / -1}.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}@media(max-width:640px){.shell-editor{padding-inline:0}.shell-grid{grid-template-columns:minmax(0,1fr)}.shell-field--wide{grid-column:auto}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$3.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],[formArray],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: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i5$1.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: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3460
+ `, isInline: true, styles: [".shell-editor{display:grid;gap:20px;padding:12px 4px 20px}.shell-intro{margin:0;max-width:68ch;color:var(--md-sys-color-on-surface-variant);font-size:14px;line-height:1.5}.shell-section{margin:4px 0 -8px;color:var(--md-sys-color-on-surface);font-size:14px;font-weight:650;line-height:1.4}.shell-grid{display:grid;gap:12px 16px;grid-template-columns:repeat(2,minmax(0,1fr));align-items:start}.shell-field--wide{grid-column:1 / -1}.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}@media(max-width:640px){.shell-editor{padding-inline:0}.shell-grid{grid-template-columns:minmax(0,1fr)}.shell-field--wide{grid-column:auto}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$3.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],[formArray],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: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i5$1.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: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3195
3461
  }
3196
3462
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: WidgetShellEditorComponent, decorators: [{
3197
3463
  type: Component,
@@ -3210,136 +3476,217 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3210
3476
  PraxisIconDirective,
3211
3477
  ], template: `
3212
3478
  <div class="shell-editor">
3213
- <p class="shell-intro">
3214
- Defina a identidade, a aparência e as ações do card. Use a prévia para conferir o resultado antes de salvar.
3215
- </p>
3216
-
3217
- <div class="shell-section">Geral</div>
3218
- <div class="shell-grid">
3219
- <mat-form-field appearance="outline">
3220
- <mat-label>Tipo de card</mat-label>
3221
- <mat-select [formControl]="form.controls.kind">
3222
- <mat-option value="dashboard-card">Dashboard Card</mat-option>
3223
- <mat-option value="none">Sem shell</mat-option>
3224
- </mat-select>
3225
- </mat-form-field>
3226
- <mat-form-field appearance="outline">
3227
- <mat-label>Preset</mat-label>
3228
- <mat-select [formControl]="form.controls.preset">
3229
- <mat-option value="">Nenhum</mat-option>
3230
- @if (pagePreset) {
3231
- <mat-option [value]="pagePreset">Usar preset da página ({{ pagePreset }})</mat-option>
3232
- }
3233
- @for (p of presetOptions; track p) {
3234
- <mat-option [value]="p.id">{{ p.label }}</mat-option>
3235
- }
3236
- </mat-select>
3237
- </mat-form-field>
3238
- @if (!form.controls.preset.value && pagePreset) {
3239
- <div class="shell-hint">
3240
- Preset da página: {{ pagePreset }}
3241
- </div>
3242
- }
3243
- @if (form.controls.preset.value) {
3244
- <mat-checkbox [formControl]="form.controls.applyToAll">
3245
- Aplicar preset como padrão da página
3246
- </mat-checkbox>
3247
- }
3248
- <mat-form-field appearance="outline">
3249
- <mat-label>Ícone</mat-label>
3250
- <input matInput [formControl]="form.controls.icon" placeholder="ex: badge" />
3251
- </mat-form-field>
3252
- <mat-form-field appearance="outline">
3253
- <mat-label>Título</mat-label>
3254
- <input matInput [formControl]="form.controls.title" />
3255
- </mat-form-field>
3256
- <mat-form-field appearance="outline" class="shell-field--wide">
3257
- <mat-label>Subtítulo</mat-label>
3258
- <input matInput [formControl]="form.controls.subtitle" />
3259
- </mat-form-field>
3260
- <mat-form-field appearance="outline">
3261
- <mat-label>Mostrar cabeçalho</mat-label>
3262
- <mat-select [formControl]="form.controls.showHeader">
3263
- <mat-option value="auto">Automático</mat-option>
3264
- <mat-option value="true">Sempre</mat-option>
3265
- <mat-option value="false">Nunca</mat-option>
3266
- </mat-select>
3267
- </mat-form-field>
3268
- </div>
3269
-
3270
- <div class="shell-section">Controles de janela</div>
3271
- <div class="shell-flags">
3272
- <mat-checkbox [formControl]="form.controls.collapsible">Permitir recolher</mat-checkbox>
3273
- </div>
3274
-
3275
- <mat-divider></mat-divider>
3276
-
3277
- <div class="shell-section">Aparência</div>
3278
- <div class="shell-grid">
3279
- <mat-form-field appearance="outline">
3280
- <mat-label>Fundo do card</mat-label>
3281
- <input matInput [formControl]="form.controls.cardBg" placeholder="ex: #0b1220" />
3282
- </mat-form-field>
3283
- <mat-form-field appearance="outline">
3284
- <mat-label>Cor da borda</mat-label>
3285
- <input matInput [formControl]="form.controls.cardBorder" placeholder="ex: rgba(255,255,255,0.12)" />
3286
- </mat-form-field>
3287
- <mat-form-field appearance="outline">
3288
- <mat-label>Raio da borda</mat-label>
3289
- <input matInput [formControl]="form.controls.cardRadius" placeholder="ex: 14px" />
3290
- </mat-form-field>
3291
- <mat-form-field appearance="outline">
3292
- <mat-label>Sombra</mat-label>
3293
- <input matInput [formControl]="form.controls.cardShadow" placeholder="ex: 0 10px 30px rgba(0,0,0,0.2)" />
3294
- </mat-form-field>
3295
- <mat-form-field appearance="outline">
3296
- <mat-label>Fundo do cabeçalho</mat-label>
3297
- <input matInput [formControl]="form.controls.headerBg" placeholder="ex: linear-gradient(...)" />
3298
- </mat-form-field>
3299
- <mat-form-field appearance="outline">
3300
- <mat-label>Borda do cabeçalho</mat-label>
3301
- <input matInput [formControl]="form.controls.headerBorder" placeholder="ex: rgba(255,255,255,0.08)" />
3302
- </mat-form-field>
3303
- <mat-form-field appearance="outline">
3304
- <mat-label>Cor do título</mat-label>
3305
- <input matInput [formControl]="form.controls.titleColor" placeholder="ex: #e6edf3" />
3306
- </mat-form-field>
3307
- <mat-form-field appearance="outline">
3308
- <mat-label>Cor do subtítulo</mat-label>
3309
- <input matInput [formControl]="form.controls.subtitleColor" placeholder="ex: #9fb0c4" />
3310
- </mat-form-field>
3311
- <mat-form-field appearance="outline">
3312
- <mat-label>Cor do ícone</mat-label>
3313
- <input matInput [formControl]="form.controls.iconColor" placeholder="ex: #8ab4ff" />
3314
- </mat-form-field>
3315
- <mat-form-field appearance="outline">
3316
- <mat-label>Fundo do corpo</mat-label>
3317
- <input matInput [formControl]="form.controls.bodyBg" placeholder="ex: transparent" />
3318
- </mat-form-field>
3319
- <mat-form-field appearance="outline">
3320
- <mat-label>Cor do texto do corpo</mat-label>
3321
- <input matInput [formControl]="form.controls.bodyColor" placeholder="ex: #e6edf3" />
3322
- </mat-form-field>
3323
- <mat-form-field appearance="outline">
3324
- <mat-label>Padding do corpo</mat-label>
3325
- <input matInput [formControl]="form.controls.bodyPadding" placeholder="ex: 10px 12px 12px" />
3326
- </mat-form-field>
3327
- <mat-form-field appearance="outline">
3328
- <mat-label>Tamanho do título</mat-label>
3329
- <input matInput [formControl]="form.controls.titleSize" placeholder="ex: 14px" />
3330
- </mat-form-field>
3331
- <mat-form-field appearance="outline">
3332
- <mat-label>Peso do título</mat-label>
3333
- <input matInput [formControl]="form.controls.titleWeight" placeholder="ex: 600" />
3334
- </mat-form-field>
3335
- <mat-form-field appearance="outline">
3336
- <mat-label>Tamanho do subtítulo</mat-label>
3337
- <input matInput [formControl]="form.controls.subtitleSize" placeholder="ex: 12px" />
3338
- </mat-form-field>
3339
- </div>
3340
-
3479
+ @if (
3480
+ canEditShellIdentity() &&
3481
+ canEditShellAppearance() &&
3482
+ canEditShellActions()
3483
+ ) {
3484
+ <p class="shell-intro">
3485
+ Defina a identidade, a aparência e as ações do card. Use a prévia para
3486
+ conferir o resultado antes de salvar.
3487
+ </p>
3488
+ }
3489
+
3490
+ @if (canEditShellIdentity()) {
3491
+ <div class="shell-section">Geral</div>
3492
+ <div class="shell-grid">
3493
+ <mat-form-field appearance="outline">
3494
+ <mat-label>Tipo de card</mat-label>
3495
+ <mat-select [formControl]="form.controls.kind">
3496
+ <mat-option value="dashboard-card">Dashboard Card</mat-option>
3497
+ <mat-option value="none">Sem shell</mat-option>
3498
+ </mat-select>
3499
+ </mat-form-field>
3500
+ <mat-form-field appearance="outline">
3501
+ <mat-label>Preset</mat-label>
3502
+ <mat-select [formControl]="form.controls.preset">
3503
+ <mat-option value="">Nenhum</mat-option>
3504
+ @if (pagePreset) {
3505
+ <mat-option [value]="pagePreset"
3506
+ >Usar preset da página ({{ pagePreset }})</mat-option
3507
+ >
3508
+ }
3509
+ @for (p of presetOptions; track p) {
3510
+ <mat-option [value]="p.id">{{ p.label }}</mat-option>
3511
+ }
3512
+ </mat-select>
3513
+ </mat-form-field>
3514
+ @if (!form.controls.preset.value && pagePreset) {
3515
+ <div class="shell-hint">Preset da página: {{ pagePreset }}</div>
3516
+ }
3517
+ @if (canPromotePagePreset() && form.controls.preset.value) {
3518
+ <mat-checkbox [formControl]="form.controls.applyToAll">
3519
+ Aplicar preset como padrão da página
3520
+ </mat-checkbox>
3521
+ }
3522
+ <mat-form-field appearance="outline">
3523
+ <mat-label>Ícone</mat-label>
3524
+ <input
3525
+ matInput
3526
+ [formControl]="form.controls.icon"
3527
+ placeholder="ex: badge"
3528
+ />
3529
+ </mat-form-field>
3530
+ <mat-form-field appearance="outline">
3531
+ <mat-label>Título</mat-label>
3532
+ <input matInput [formControl]="form.controls.title" />
3533
+ </mat-form-field>
3534
+ <mat-form-field appearance="outline" class="shell-field--wide">
3535
+ <mat-label>Subtítulo</mat-label>
3536
+ <input matInput [formControl]="form.controls.subtitle" />
3537
+ </mat-form-field>
3538
+ <mat-form-field appearance="outline">
3539
+ <mat-label>Mostrar cabeçalho</mat-label>
3540
+ <mat-select [formControl]="form.controls.showHeader">
3541
+ <mat-option value="auto">Automático</mat-option>
3542
+ <mat-option value="true">Sempre</mat-option>
3543
+ <mat-option value="false">Nunca</mat-option>
3544
+ </mat-select>
3545
+ </mat-form-field>
3546
+ </div>
3547
+
3548
+ <div class="shell-section">Controles de janela</div>
3549
+ <div class="shell-flags">
3550
+ <mat-checkbox [formControl]="form.controls.collapsible"
3551
+ >Permitir recolher</mat-checkbox
3552
+ >
3553
+ </div>
3554
+ }
3555
+
3556
+ @if (canEditShellAppearance()) {
3557
+ <mat-divider></mat-divider>
3558
+
3559
+ <div class="shell-section">Aparência</div>
3560
+ <div class="shell-grid">
3561
+ <mat-form-field appearance="outline">
3562
+ <mat-label>Fundo do card</mat-label>
3563
+ <input
3564
+ matInput
3565
+ [formControl]="form.controls.cardBg"
3566
+ placeholder="ex: #0b1220"
3567
+ />
3568
+ </mat-form-field>
3569
+ <mat-form-field appearance="outline">
3570
+ <mat-label>Cor da borda</mat-label>
3571
+ <input
3572
+ matInput
3573
+ [formControl]="form.controls.cardBorder"
3574
+ placeholder="ex: rgba(255,255,255,0.12)"
3575
+ />
3576
+ </mat-form-field>
3577
+ <mat-form-field appearance="outline">
3578
+ <mat-label>Raio da borda</mat-label>
3579
+ <input
3580
+ matInput
3581
+ [formControl]="form.controls.cardRadius"
3582
+ placeholder="ex: 14px"
3583
+ />
3584
+ </mat-form-field>
3585
+ <mat-form-field appearance="outline">
3586
+ <mat-label>Sombra</mat-label>
3587
+ <input
3588
+ matInput
3589
+ [formControl]="form.controls.cardShadow"
3590
+ placeholder="ex: 0 10px 30px rgba(0,0,0,0.2)"
3591
+ />
3592
+ </mat-form-field>
3593
+ <mat-form-field appearance="outline">
3594
+ <mat-label>Fundo do cabeçalho</mat-label>
3595
+ <input
3596
+ matInput
3597
+ [formControl]="form.controls.headerBg"
3598
+ placeholder="ex: linear-gradient(...)"
3599
+ />
3600
+ </mat-form-field>
3601
+ <mat-form-field appearance="outline">
3602
+ <mat-label>Borda do cabeçalho</mat-label>
3603
+ <input
3604
+ matInput
3605
+ [formControl]="form.controls.headerBorder"
3606
+ placeholder="ex: rgba(255,255,255,0.08)"
3607
+ />
3608
+ </mat-form-field>
3609
+ <mat-form-field appearance="outline">
3610
+ <mat-label>Cor do título</mat-label>
3611
+ <input
3612
+ matInput
3613
+ [formControl]="form.controls.titleColor"
3614
+ placeholder="ex: #e6edf3"
3615
+ />
3616
+ </mat-form-field>
3617
+ <mat-form-field appearance="outline">
3618
+ <mat-label>Cor do subtítulo</mat-label>
3619
+ <input
3620
+ matInput
3621
+ [formControl]="form.controls.subtitleColor"
3622
+ placeholder="ex: #9fb0c4"
3623
+ />
3624
+ </mat-form-field>
3625
+ <mat-form-field appearance="outline">
3626
+ <mat-label>Cor do ícone</mat-label>
3627
+ <input
3628
+ matInput
3629
+ [formControl]="form.controls.iconColor"
3630
+ placeholder="ex: #8ab4ff"
3631
+ />
3632
+ </mat-form-field>
3633
+ <mat-form-field appearance="outline">
3634
+ <mat-label>Fundo do corpo</mat-label>
3635
+ <input
3636
+ matInput
3637
+ [formControl]="form.controls.bodyBg"
3638
+ placeholder="ex: transparent"
3639
+ />
3640
+ </mat-form-field>
3641
+ <mat-form-field appearance="outline">
3642
+ <mat-label>Cor do texto do corpo</mat-label>
3643
+ <input
3644
+ matInput
3645
+ [formControl]="form.controls.bodyColor"
3646
+ placeholder="ex: #e6edf3"
3647
+ />
3648
+ </mat-form-field>
3649
+ <mat-form-field appearance="outline">
3650
+ <mat-label>Padding do corpo</mat-label>
3651
+ <input
3652
+ matInput
3653
+ [formControl]="form.controls.bodyPadding"
3654
+ placeholder="ex: 10px 12px 12px"
3655
+ />
3656
+ </mat-form-field>
3657
+ <mat-form-field appearance="outline">
3658
+ <mat-label>Tamanho do título</mat-label>
3659
+ <input
3660
+ matInput
3661
+ [formControl]="form.controls.titleSize"
3662
+ placeholder="ex: 14px"
3663
+ />
3664
+ </mat-form-field>
3665
+ <mat-form-field appearance="outline">
3666
+ <mat-label>Peso do título</mat-label>
3667
+ <input
3668
+ matInput
3669
+ [formControl]="form.controls.titleWeight"
3670
+ placeholder="ex: 600"
3671
+ />
3672
+ </mat-form-field>
3673
+ <mat-form-field appearance="outline">
3674
+ <mat-label>Tamanho do subtítulo</mat-label>
3675
+ <input
3676
+ matInput
3677
+ [formControl]="form.controls.subtitleSize"
3678
+ placeholder="ex: 12px"
3679
+ />
3680
+ </mat-form-field>
3681
+ </div>
3682
+ }
3683
+
3341
3684
  <div class="shell-preview" [ngStyle]="previewVars()">
3342
- <div class="shell-preview-card" [class.no-shell]="form.controls.kind.value === 'none'" [class.expanded]="previewExpanded">
3685
+ <div
3686
+ class="shell-preview-card"
3687
+ [class.no-shell]="form.controls.kind.value === 'none'"
3688
+ [class.expanded]="previewExpanded"
3689
+ >
3343
3690
  @if (previewShowHeader()) {
3344
3691
  <div class="shell-preview-header">
3345
3692
  <div class="shell-preview-title">
@@ -3347,8 +3694,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3347
3694
  <mat-icon [praxisIcon]="form.controls.icon.value"></mat-icon>
3348
3695
  }
3349
3696
  <div class="shell-preview-text">
3350
- <div class="shell-preview-title-text">{{ previewTitle() }}</div>
3351
- <div class="shell-preview-subtitle">{{ previewSubtitle() }}</div>
3697
+ <div class="shell-preview-title-text">
3698
+ {{ previewTitle() }}
3699
+ </div>
3700
+ <div class="shell-preview-subtitle">
3701
+ {{ previewSubtitle() }}
3702
+ </div>
3352
3703
  </div>
3353
3704
  </div>
3354
3705
  <div class="shell-preview-actions">
@@ -3356,13 +3707,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3356
3707
  <button
3357
3708
  type="button"
3358
3709
  [disabled]="action.disabled"
3359
- [ngClass]="action.variant === 'outlined' ? 'pdx-preview-outlined' : 'pdx-preview-text'"
3710
+ [ngClass]="
3711
+ action.variant === 'outlined'
3712
+ ? 'pdx-preview-outlined'
3713
+ : 'pdx-preview-text'
3714
+ "
3360
3715
  mat-button
3361
- >
3716
+ >
3362
3717
  @if (action.icon) {
3363
3718
  <mat-icon [praxisIcon]="action.icon"></mat-icon>
3364
3719
  }
3365
- <span class="pdx-preview-label">{{ action.label || action.id }}</span>
3720
+ <span class="pdx-preview-label">{{
3721
+ action.label || action.id
3722
+ }}</span>
3366
3723
  </button>
3367
3724
  }
3368
3725
  @if (previewOverflowCount()) {
@@ -3385,14 +3742,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3385
3742
  }
3386
3743
  }
3387
3744
  <button
3388
- [praxisIconButton]="previewCollapsed ? 'unfold_more' : 'unfold_less'"
3745
+ [praxisIconButton]="
3746
+ previewCollapsed ? 'unfold_more' : 'unfold_less'
3747
+ "
3389
3748
  size="compact"
3390
3749
  type="button"
3391
3750
  (click)="togglePreviewCollapse()"
3392
3751
  aria-label="Recolher"
3393
3752
  ></button>
3394
3753
  <button
3395
- [praxisIconButton]="previewExpanded ? 'close_fullscreen' : 'open_in_full'"
3754
+ [praxisIconButton]="
3755
+ previewExpanded ? 'close_fullscreen' : 'open_in_full'
3756
+ "
3396
3757
  size="compact"
3397
3758
  type="button"
3398
3759
  (click)="togglePreviewExpand()"
@@ -3401,27 +3762,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3401
3762
  </div>
3402
3763
  </div>
3403
3764
  }
3404
- <div class="shell-preview-body" [class.hidden]="previewCollapsed">Conteudo do widget</div>
3765
+ <div class="shell-preview-body" [class.hidden]="previewCollapsed">
3766
+ Conteudo do widget
3767
+ </div>
3405
3768
  </div>
3406
3769
  </div>
3407
-
3408
- <mat-divider></mat-divider>
3409
-
3410
- @if (hasAvailableActions) {
3770
+
3771
+ @if (canEditShellActions() && hasAvailableActions) {
3772
+ <mat-divider></mat-divider>
3411
3773
  <div class="shell-section">Ações disponíveis</div>
3412
- }
3413
- @if (hasAvailableActions) {
3414
3774
  <div class="shell-available">
3415
3775
  <div class="shell-available-toolbar">
3416
3776
  <mat-form-field appearance="outline">
3417
3777
  <mat-label>Buscar ação</mat-label>
3418
- <input matInput [formControl]="actionQuery" placeholder="ex: export, editar, submit" />
3778
+ <input
3779
+ matInput
3780
+ [formControl]="actionQuery"
3781
+ placeholder="ex: export, editar, submit"
3782
+ />
3419
3783
  </mat-form-field>
3420
3784
  <div class="shell-available-filters">
3421
3785
  <mat-checkbox [(ngModel)]="showScopeShell">Shell</mat-checkbox>
3422
3786
  <mat-checkbox [(ngModel)]="showScopeAny">Any</mat-checkbox>
3423
- <mat-checkbox [(ngModel)]="showScopeToolbar">Toolbar</mat-checkbox>
3424
- <mat-checkbox [(ngModel)]="showScopeContext">Context</mat-checkbox>
3787
+ <mat-checkbox [(ngModel)]="showScopeToolbar"
3788
+ >Toolbar</mat-checkbox
3789
+ >
3790
+ <mat-checkbox [(ngModel)]="showScopeContext"
3791
+ >Context</mat-checkbox
3792
+ >
3425
3793
  </div>
3426
3794
  </div>
3427
3795
  <div class="shell-available-list">
@@ -3433,31 +3801,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3433
3801
  <mat-icon [praxisIcon]="action.icon"></mat-icon>
3434
3802
  }
3435
3803
  <div class="shell-available-text">
3436
- <div class="shell-available-label">{{ action.label }}</div>
3804
+ <div class="shell-available-label">
3805
+ {{ action.label }}
3806
+ </div>
3437
3807
  <div class="shell-available-meta">
3438
- <span class="shell-badge">{{ action.kind === 'command' ? 'Comando' : 'Ação' }}</span>
3439
- <span class="shell-badge">{{ scopeLabel(action.scope) }}</span>
3808
+ <span class="shell-badge">{{
3809
+ action.kind === 'command' ? 'Comando' : 'Ação'
3810
+ }}</span>
3811
+ <span class="shell-badge">{{
3812
+ scopeLabel(action.scope)
3813
+ }}</span>
3440
3814
  <span class="shell-code">id: {{ action.id }}</span>
3441
3815
  @if (action.emit) {
3442
- <span class="shell-code">emit: {{ action.emit }}</span>
3816
+ <span class="shell-code"
3817
+ >emit: {{ action.emit }}</span
3818
+ >
3443
3819
  }
3444
3820
  @if (action.command) {
3445
- <span class="shell-code">command: {{ action.command }}</span>
3821
+ <span class="shell-code"
3822
+ >command: {{ action.command }}</span
3823
+ >
3446
3824
  }
3447
3825
  </div>
3448
3826
  </div>
3449
3827
  </div>
3450
3828
  @if (action.description) {
3451
- <div class="shell-available-desc">{{ action.description }}</div>
3829
+ <div class="shell-available-desc">
3830
+ {{ action.description }}
3831
+ </div>
3452
3832
  }
3453
3833
  @if (action.payloadExample !== undefined) {
3454
3834
  <div class="shell-available-payload">
3455
- <span class="shell-code">payload: {{ stringifyPayload(action.payloadExample) }}</span>
3835
+ <span class="shell-code"
3836
+ >payload:
3837
+ {{ stringifyPayload(action.payloadExample) }}</span
3838
+ >
3456
3839
  </div>
3457
3840
  }
3458
3841
  @if (action.scope === 'context') {
3459
3842
  <div class="shell-available-warning">
3460
- Essa ação depende de item/linha selecionado; payload fixo pode não funcionar.
3843
+ Essa ação depende de item/linha selecionado; payload fixo
3844
+ pode não funcionar.
3461
3845
  </div>
3462
3846
  }
3463
3847
  </div>
@@ -3467,7 +3851,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3467
3851
  type="button"
3468
3852
  [color]="isActionSelected(action) ? 'warn' : 'primary'"
3469
3853
  (click)="toggleAvailableAction(action)"
3470
- >
3854
+ >
3471
3855
  {{ isActionSelected(action) ? 'Remover' : 'Adicionar' }}
3472
3856
  </button>
3473
3857
  </div>
@@ -3475,18 +3859,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3475
3859
  }
3476
3860
  </div>
3477
3861
  </div>
3478
- } @else {
3479
- <div class="shell-empty">Nenhuma ação registrada para este componente.</div>
3862
+ } @else if (canEditShellActions()) {
3863
+ <mat-divider></mat-divider>
3864
+ <div class="shell-empty">
3865
+ Nenhuma ação registrada para este componente.
3866
+ </div>
3480
3867
  }
3481
-
3482
- @if (hasAvailableActions) {
3868
+
3869
+ @if (canEditShellActions() && hasAvailableActions) {
3483
3870
  <mat-divider></mat-divider>
3484
3871
  }
3485
-
3486
- @if (setInputPresets.length) {
3872
+
3873
+ @if (canEditShellActions() && setInputPresets.length) {
3487
3874
  <div class="shell-section">Ações rápidas (inputs)</div>
3488
- }
3489
- @if (setInputPresets.length) {
3490
3875
  <div class="shell-quick-inputs">
3491
3876
  <mat-form-field appearance="outline">
3492
3877
  <mat-label>Input</mat-label>
@@ -3519,18 +3904,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3519
3904
  }
3520
3905
  </mat-select>
3521
3906
  </mat-form-field>
3522
- <button mat-flat-button color="primary" type="button" (click)="addSetInputAction()">
3907
+ <button
3908
+ mat-flat-button
3909
+ color="primary"
3910
+ type="button"
3911
+ (click)="addSetInputAction()"
3912
+ >
3523
3913
  Adicionar ação
3524
3914
  </button>
3525
3915
  </div>
3526
3916
  }
3527
-
3528
- <div class="shell-section shell-actions-head">
3529
- <div>Ações do cabeçalho</div>
3530
- <button mat-flat-button color="primary" type="button" (click)="addAction()">Adicionar ação</button>
3531
- </div>
3532
-
3533
- @if (actions.controls.length) {
3917
+
3918
+ @if (canEditShellActions()) {
3919
+ <div class="shell-section shell-actions-head">
3920
+ <div>Ações do cabeçalho</div>
3921
+ <button
3922
+ mat-flat-button
3923
+ color="primary"
3924
+ type="button"
3925
+ (click)="addAction()"
3926
+ >
3927
+ Adicionar ação
3928
+ </button>
3929
+ </div>
3930
+ }
3931
+
3932
+ @if (canEditShellActions() && actions.controls.length) {
3534
3933
  <div class="shell-actions">
3535
3934
  @for (action of actions.controls; track action; let i = $index) {
3536
3935
  <div class="shell-action" [formGroup]="action">
@@ -3566,7 +3965,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3566
3965
  </mat-form-field>
3567
3966
  <mat-form-field appearance="outline">
3568
3967
  <mat-label>Emit</mat-label>
3569
- <input matInput formControlName="emit" placeholder="ex: editar" />
3968
+ <input
3969
+ matInput
3970
+ formControlName="emit"
3971
+ placeholder="ex: editar"
3972
+ />
3570
3973
  </mat-form-field>
3571
3974
  <mat-form-field appearance="outline">
3572
3975
  <mat-label>Tooltip</mat-label>
@@ -3576,32 +3979,50 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3576
3979
  <div class="shell-action-row">
3577
3980
  <mat-form-field appearance="outline">
3578
3981
  <mat-label>Command</mat-label>
3579
- <input matInput formControlName="command" placeholder="ex: add-item" />
3982
+ <input
3983
+ matInput
3984
+ formControlName="command"
3985
+ placeholder="ex: add-item"
3986
+ />
3580
3987
  </mat-form-field>
3581
3988
  <mat-form-field appearance="outline">
3582
3989
  <mat-label>Payload (JSON)</mat-label>
3583
- <textarea matInput rows="2" formControlName="payload" placeholder='ex: {"foo":"bar"}'></textarea>
3990
+ <textarea
3991
+ matInput
3992
+ rows="2"
3993
+ formControlName="payload"
3994
+ placeholder='ex: {"foo":"bar"}'
3995
+ ></textarea>
3584
3996
  </mat-form-field>
3585
3997
  <mat-checkbox formControlName="visible">Visível</mat-checkbox>
3586
- <mat-checkbox formControlName="disabled">Desabilitado</mat-checkbox>
3998
+ <mat-checkbox formControlName="disabled"
3999
+ >Desabilitado</mat-checkbox
4000
+ >
3587
4001
  </div>
3588
4002
  @if (showActionInputPath(action.value)) {
3589
4003
  <div class="shell-action-hint">
3590
- Input: {{ displayInputPath(extractActionInput(action.value)) }}
4004
+ Input:
4005
+ {{ displayInputPath(extractActionInput(action.value)) }}
3591
4006
  </div>
3592
4007
  }
3593
4008
  <div class="shell-action-actions">
3594
- <button mat-stroked-button color="warn" type="button" (click)="removeAction(i)">Remover</button>
4009
+ <button
4010
+ mat-stroked-button
4011
+ color="warn"
4012
+ type="button"
4013
+ (click)="removeAction(i)"
4014
+ >
4015
+ Remover
4016
+ </button>
3595
4017
  </div>
3596
4018
  </div>
3597
4019
  }
3598
4020
  </div>
3599
- } @else {
4021
+ } @else if (canEditShellActions()) {
3600
4022
  <div class="shell-empty">Nenhuma ação configurada.</div>
3601
4023
  }
3602
-
3603
4024
  </div>
3604
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".shell-editor{display:grid;gap:20px;padding:12px 4px 20px}.shell-intro{margin:0;max-width:68ch;color:var(--md-sys-color-on-surface-variant);font-size:14px;line-height:1.5}.shell-section{margin:4px 0 -8px;color:var(--md-sys-color-on-surface);font-size:14px;font-weight:650;line-height:1.4}.shell-grid{display:grid;gap:12px 16px;grid-template-columns:repeat(2,minmax(0,1fr));align-items:start}.shell-field--wide{grid-column:1 / -1}.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}@media(max-width:640px){.shell-editor{padding-inline:0}.shell-grid{grid-template-columns:minmax(0,1fr)}.shell-field--wide{grid-column:auto}}\n"] }]
4025
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".shell-editor{display:grid;gap:20px;padding:12px 4px 20px}.shell-intro{margin:0;max-width:68ch;color:var(--md-sys-color-on-surface-variant);font-size:14px;line-height:1.5}.shell-section{margin:4px 0 -8px;color:var(--md-sys-color-on-surface);font-size:14px;font-weight:650;line-height:1.4}.shell-grid{display:grid;gap:12px 16px;grid-template-columns:repeat(2,minmax(0,1fr));align-items:start}.shell-field--wide{grid-column:1 / -1}.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}@media(max-width:640px){.shell-editor{padding-inline:0}.shell-grid{grid-template-columns:minmax(0,1fr)}.shell-field--wide{grid-column:auto}}\n"] }]
3605
4026
  }], ctorParameters: () => [{ type: undefined, decorators: [{
3606
4027
  type: Optional
3607
4028
  }, {
@@ -12615,7 +13036,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12615
13036
  * Capabilities catalog for the canonical dynamic page builder/runtime.
12616
13037
  */
12617
13038
  const PAGE_BUILDER_AI_CAPABILITIES = {
12618
- version: 'v1.3',
13039
+ version: 'v1.4',
12619
13040
  enums: {},
12620
13041
  targets: [
12621
13042
  'page-builder',
@@ -12637,6 +13058,7 @@ const PAGE_BUILDER_AI_CAPABILITIES = {
12637
13058
  '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.',
12638
13059
  'Payloads legados de layout ainda podem ser ingeridos, mas sao normalizados para canvas e nao devem ser reemitidos.',
12639
13060
  'pageIdentity identifica o escopo de persistencia e nao pertence ao objeto page.',
13061
+ 'authoringCapabilities é um grant transitório do host para limitar affordances visíveis; não integra WidgetPageDefinition, não é persistido e não concede autoridade de edição à IA.',
12640
13062
  ],
12641
13063
  capabilities: [
12642
13064
  { path: 'uiCompositionPlan', category: 'page', valueKind: 'object', description: 'Plano declarativo intermediario aceito em preview agentic antes do WidgetPageDefinition.' },
@@ -13658,11 +14080,12 @@ const PRAXIS_PAGE_BUILDER_AUTHORING_MANIFEST = {
13658
14080
  componentId: 'praxis-page-builder',
13659
14081
  ownerPackage: '@praxisui/page-builder',
13660
14082
  configSchemaId: 'WidgetPageDefinition',
13661
- manifestVersion: '1.1.0',
14083
+ manifestVersion: '1.2.0',
13662
14084
  runtimeInputs: [
13663
14085
  { name: 'page', type: 'WidgetPageDefinition', description: 'Canonical renderable page document consumed by praxis-dynamic-page.' },
13664
14086
  { name: 'pageIdentity', type: 'PageIdentity | null', description: 'Persistence identity for ui_user_config save/apply flows; not persisted inside page.' },
13665
14087
  { name: 'enableCustomization', type: 'boolean', description: 'Enables page-builder authoring chrome around the runtime page.' },
14088
+ { name: 'authoringCapabilities', type: 'PageBuilderAuthoringCapabilities | null', description: 'Host-only grant that limits visible authoring operations without changing WidgetPageDefinition and without granting AI edit authority; omitted capabilities preserve full authoring.' },
13666
14089
  { name: 'context', type: 'Record<string, unknown>', description: 'Opaque host context passed to catalog resolution and agentic authoring.' },
13667
14090
  { name: 'pageChange', type: 'WidgetPageDefinition', description: 'Emitted after local apply/preview produces a renderable page.' },
13668
14091
  { name: 'agenticAuthoringEnableStreaming', type: 'boolean', description: 'Opt-in flag for the canonical streaming turn endpoints.' },
@@ -20878,6 +21301,7 @@ class DynamicPageBuilderComponent {
20878
21301
  strictValidation = true;
20879
21302
  autoPersist = true;
20880
21303
  enableCustomization = false;
21304
+ authoringCapabilities;
20881
21305
  showSettingsButton = true;
20882
21306
  pageIdentity;
20883
21307
  componentInstanceId;
@@ -20980,7 +21404,9 @@ class DynamicPageBuilderComponent {
20980
21404
  });
20981
21405
  effect(() => {
20982
21406
  const activeSession = this.assistantSessions.activeSession();
20983
- if (activeSession?.id === this.resolveAgenticAuthoringSessionId() && !this.agenticAuthoringOpen()) {
21407
+ if (this.isAuthoringCapabilityEnabled('agentic')
21408
+ && activeSession?.id === this.resolveAgenticAuthoringSessionId()
21409
+ && !this.agenticAuthoringOpen()) {
20984
21410
  this.agenticAuthoringOpen.set(true);
20985
21411
  this.agenticAuthoringError.set('');
20986
21412
  }
@@ -20990,6 +21416,19 @@ class DynamicPageBuilderComponent {
20990
21416
  if (changes['page']) {
20991
21417
  this.currentPage.set(this.parsePage(this.page) || { widgets: [] });
20992
21418
  }
21419
+ if (changes['authoringCapabilities']) {
21420
+ this.runtimeAuthoringPageCache = undefined;
21421
+ if (!this.isAuthoringCapabilityEnabled('connections')) {
21422
+ this.connectionsViewerOpen.set(false);
21423
+ }
21424
+ if (!this.isAuthoringCapabilityEnabled('agentic')) {
21425
+ this.cancelActiveAgenticTurn();
21426
+ this.agenticAuthoringBusy.set(false);
21427
+ this.agenticAuthoringOpen.set(false);
21428
+ this.agenticAuthoringPreviewResult.set(null);
21429
+ this.invalidateAgenticTerminalAuthorization();
21430
+ }
21431
+ }
20993
21432
  const pageIdentityChange = changes['pageIdentity'];
20994
21433
  const componentInstanceChange = changes['componentInstanceId'];
20995
21434
  const agenticComponentIdChange = changes['agenticAuthoringComponentId'];
@@ -21030,6 +21469,45 @@ class DynamicPageBuilderComponent {
21030
21469
  showSettings() {
21031
21470
  return !!this.enableCustomization && !this.previewMode;
21032
21471
  }
21472
+ canInsertWidgets() {
21473
+ return this.showSettings() && this.isAuthoringCapabilityEnabled('insertWidgets');
21474
+ }
21475
+ canOpenPageSettings() {
21476
+ return this.showSettings()
21477
+ && this.isAuthoringCapabilityEnabled('pageSettings')
21478
+ && !!this.pageEditorComponent;
21479
+ }
21480
+ canEditConnections() {
21481
+ return this.showSettings() && this.isAuthoringCapabilityEnabled('connections');
21482
+ }
21483
+ canPreviewPage() {
21484
+ return this.hasPageWidgets() && this.isAuthoringCapabilityEnabled('preview');
21485
+ }
21486
+ canUseAgenticAuthoring() {
21487
+ return !!this.enableCustomization
21488
+ && this.enableAgenticAuthoring
21489
+ && this.isAuthoringCapabilityEnabled('agentic');
21490
+ }
21491
+ canRunPremiumReadinessAction(action) {
21492
+ switch (action.kind) {
21493
+ case 'open-page-settings':
21494
+ return this.canOpenPageSettings();
21495
+ case 'open-connections':
21496
+ return this.canEditConnections();
21497
+ case 'open-widget-config':
21498
+ return this.showSettings() && this.isAuthoringCapabilityEnabled('widgetInputs');
21499
+ case 'focus-widget':
21500
+ return this.showSettings() && this.isAuthoringCapabilityEnabled('canvas');
21501
+ }
21502
+ }
21503
+ canUsePageLifecycle() {
21504
+ return this.showSettings()
21505
+ && this.showPageLifecycleActions
21506
+ && this.isAuthoringCapabilityEnabled('pageLifecycle');
21507
+ }
21508
+ isAuthoringCapabilityEnabled(capability) {
21509
+ return this.authoringCapabilities?.[capability] !== false;
21510
+ }
21033
21511
  isPreviewMode() {
21034
21512
  return this.previewMode;
21035
21513
  }
@@ -21079,6 +21557,8 @@ class DynamicPageBuilderComponent {
21079
21557
  if (event.output !== AGENTIC_PAGE_COMPOSITION_REQUEST_OUTPUT) {
21080
21558
  return;
21081
21559
  }
21560
+ if (!this.isAuthoringCapabilityEnabled('agentic'))
21561
+ return;
21082
21562
  const payload = this.toRecord(event.payload);
21083
21563
  const prompt = typeof payload?.['prompt'] === 'string' ? payload['prompt'].trim() : '';
21084
21564
  if (!prompt) {
@@ -21094,6 +21574,8 @@ class DynamicPageBuilderComponent {
21094
21574
  void this.previewAgenticAuthoring();
21095
21575
  }
21096
21576
  onConnectionEditorPageChange(next) {
21577
+ if (!this.canEditConnections())
21578
+ return;
21097
21579
  const cloned = this.clonePage(next);
21098
21580
  this.currentPage.set(cloned);
21099
21581
  this.clearSelectedWidgetIfMissing(cloned);
@@ -21106,6 +21588,8 @@ class DynamicPageBuilderComponent {
21106
21588
  }
21107
21589
  }
21108
21590
  togglePreview() {
21591
+ if (!this.canPreviewPage())
21592
+ return;
21109
21593
  this.previewMode = !this.previewMode;
21110
21594
  if (this.previewMode) {
21111
21595
  this.enterPreviewMode();
@@ -21155,6 +21639,8 @@ class DynamicPageBuilderComponent {
21155
21639
  this.projectKnowledgeCockpitCollapsed.update((current) => !current);
21156
21640
  }
21157
21641
  toggleConnectionsViewer() {
21642
+ if (!this.canEditConnections())
21643
+ return;
21158
21644
  this.connectionsViewerOpen.update((current) => !current);
21159
21645
  }
21160
21646
  connectionsToggleLabel() {
@@ -21167,6 +21653,8 @@ class DynamicPageBuilderComponent {
21167
21653
  return this.tx('connections.toggle', 'Edit connections');
21168
21654
  }
21169
21655
  onAddComponent() {
21656
+ if (!this.isAuthoringCapabilityEnabled('insertWidgets'))
21657
+ return;
21170
21658
  const ref = this.dialog.open(ComponentPaletteDialogComponent, {
21171
21659
  width: '720px',
21172
21660
  data: {
@@ -21182,6 +21670,8 @@ class DynamicPageBuilderComponent {
21182
21670
  });
21183
21671
  }
21184
21672
  addWidget(selection) {
21673
+ if (!this.isAuthoringCapabilityEnabled('insertWidgets'))
21674
+ return;
21185
21675
  const resolved = typeof selection === 'string'
21186
21676
  ? { componentId: selection }
21187
21677
  : selection;
@@ -21233,24 +21723,28 @@ class DynamicPageBuilderComponent {
21233
21723
  }
21234
21724
  }
21235
21725
  openPageSettings() {
21236
- if (!this.pageEditorComponent)
21726
+ if (!this.canOpenPageSettings())
21237
21727
  return;
21238
21728
  this.connectionsViewerOpen.set(false);
21239
21729
  this.runtime?.openPageSettings();
21240
21730
  }
21241
21731
  saveCurrentPage() {
21732
+ if (!this.isAuthoringCapabilityEnabled('save'))
21733
+ return;
21242
21734
  if (!this.canSaveCurrentPage()) {
21243
21735
  this.agenticAuthoringStatus.set(this.tx('agentic.status.reviewNeedsAttention', 'Complete this review in the assistant before saving.'));
21244
21736
  return;
21245
21737
  }
21246
21738
  const runtimeSnapshot = this.runtime?.getPageSnapshot();
21247
- const cloned = this.clonePage(runtimeSnapshot || this.currentPage());
21739
+ const cloned = this.toCanonicalPageFromAuthoringRuntime(runtimeSnapshot || this.currentPage());
21248
21740
  this.currentPage.set(cloned);
21249
21741
  this.pageChange.emit(cloned);
21250
21742
  this.pageSaveRequested.emit(this.clonePage(cloned));
21251
21743
  }
21252
21744
  canSaveCurrentPage() {
21253
- return this.hasPageWidgets() && !this.hasPendingAgenticPreview();
21745
+ return this.isAuthoringCapabilityEnabled('save')
21746
+ && this.hasPageWidgets()
21747
+ && !this.hasPendingAgenticPreview();
21254
21748
  }
21255
21749
  evaluatePremiumReadiness(page) {
21256
21750
  const widgets = page.widgets || [];
@@ -21344,7 +21838,7 @@ class DynamicPageBuilderComponent {
21344
21838
  }
21345
21839
  runPremiumReadinessAction(issue) {
21346
21840
  const action = issue.action;
21347
- if (!action)
21841
+ if (!action || !this.canRunPremiumReadinessAction(action))
21348
21842
  return;
21349
21843
  if (this.previewMode) {
21350
21844
  this.previewMode = false;
@@ -21446,6 +21940,8 @@ class DynamicPageBuilderComponent {
21446
21940
  };
21447
21941
  }
21448
21942
  toggleAgenticAuthoring() {
21943
+ if (!this.isAuthoringCapabilityEnabled('agentic'))
21944
+ return;
21449
21945
  if (this.agenticAuthoringOpen()) {
21450
21946
  this.minimizeAgenticAuthoring();
21451
21947
  return;
@@ -21456,16 +21952,22 @@ class DynamicPageBuilderComponent {
21456
21952
  this.openAgenticAuthoring();
21457
21953
  }
21458
21954
  openAgenticAuthoring() {
21955
+ if (!this.isAuthoringCapabilityEnabled('agentic'))
21956
+ return;
21459
21957
  this.agenticAuthoringOpen.set(true);
21460
21958
  this.agenticAuthoringError.set('');
21461
21959
  this.syncAgenticAuthoringSession('active');
21462
21960
  }
21463
21961
  openAgenticAuthoringForWidget(widgetKey) {
21962
+ if (!this.isAuthoringCapabilityEnabled('agentic'))
21963
+ return;
21464
21964
  this.selectedWidgetKey.set(widgetKey);
21465
21965
  this.agenticAuthoringWidgetContextKey.set(widgetKey);
21466
21966
  this.openAgenticAuthoring();
21467
21967
  }
21468
21968
  openAgenticAuthoringFromSession(session) {
21969
+ if (!this.isAuthoringCapabilityEnabled('agentic'))
21970
+ return;
21469
21971
  if (session.id !== this.resolveAgenticAuthoringSessionId())
21470
21972
  return;
21471
21973
  this.agenticAuthoringOpen.set(true);
@@ -21487,7 +21989,9 @@ class DynamicPageBuilderComponent {
21487
21989
  && !this.agenticAuthoringPanelLayoutTouched;
21488
21990
  }
21489
21991
  showAgenticAuthoringPanel() {
21490
- if (!this.enableAgenticAuthoring || !this.agenticAuthoringOpen()) {
21992
+ if (!this.isAuthoringCapabilityEnabled('agentic')
21993
+ || !this.enableAgenticAuthoring
21994
+ || !this.agenticAuthoringOpen()) {
21491
21995
  return false;
21492
21996
  }
21493
21997
  if (this.showSettings()) {
@@ -21498,6 +22002,7 @@ class DynamicPageBuilderComponent {
21498
22002
  showAgenticAuthoringDock() {
21499
22003
  return this.showSettings()
21500
22004
  && this.enableAgenticAuthoring
22005
+ && this.isAuthoringCapabilityEnabled('agentic')
21501
22006
  && !this.agenticAuthoringOpen()
21502
22007
  && this.hasAgenticAuthoringSession();
21503
22008
  }
@@ -21789,7 +22294,9 @@ class DynamicPageBuilderComponent {
21789
22294
  }
21790
22295
  }
21791
22296
  syncAgenticAuthoringSession(visibility = null) {
21792
- if (!this.enableAgenticAuthoring || !this.enableCustomization)
22297
+ if (!this.enableAgenticAuthoring
22298
+ || !this.enableCustomization
22299
+ || !this.isAuthoringCapabilityEnabled('agentic'))
21793
22300
  return;
21794
22301
  if (!this.agenticAuthoringOpen() && !this.hasAgenticAuthoringSession())
21795
22302
  return;
@@ -22265,6 +22772,8 @@ class DynamicPageBuilderComponent {
22265
22772
  .replace(/\b\w/g, (char) => char.toUpperCase());
22266
22773
  }
22267
22774
  async previewAgenticAuthoring() {
22775
+ if (!this.canUseAgenticAuthoring())
22776
+ return;
22268
22777
  const prompt = this.agenticAuthoringPrompt().trim();
22269
22778
  if (!prompt || this.agenticAuthoringBusy())
22270
22779
  return;
@@ -22656,6 +23165,8 @@ class DynamicPageBuilderComponent {
22656
23165
  }
22657
23166
  }
22658
23167
  async retryAgenticAuthoring() {
23168
+ if (!this.canUseAgenticAuthoring())
23169
+ return;
22659
23170
  if (this.agenticAuthoringBusy())
22660
23171
  return;
22661
23172
  this.invalidateAgenticTerminalAuthorization();
@@ -22703,6 +23214,8 @@ class DynamicPageBuilderComponent {
22703
23214
  await this.applyAgenticTurnState(await firstValueFrom(this.ensureAgenticTurnController().cancel()));
22704
23215
  }
22705
23216
  async persistAgenticAuthoring() {
23217
+ if (!this.canUseAgenticAuthoring())
23218
+ return;
22706
23219
  const preview = this.agenticAuthoringPreviewResult();
22707
23220
  if (!preview || !this.agenticAuthoringCanApply() || this.agenticAuthoringBusy())
22708
23221
  return;
@@ -22717,6 +23230,7 @@ class DynamicPageBuilderComponent {
22717
23230
  this.agenticAuthoringError.set(this.tx('agentic.errors.applyTargetExpired', 'O destino ou a versão revisada mudou. Gere uma nova prévia antes de salvar.'));
22718
23231
  return;
22719
23232
  }
23233
+ const authorizationRunId = this.agenticTurnRunId;
22720
23234
  this.agenticAuthoringBusy.set(true);
22721
23235
  this.agenticAuthoringError.set('');
22722
23236
  this.agenticAuthoringStatus.set(this.tx('agentic.status.saving', 'Salvando tela...'));
@@ -22737,7 +23251,10 @@ class DynamicPageBuilderComponent {
22737
23251
  source: 'page-builder-agentic-authoring',
22738
23252
  },
22739
23253
  semanticDecision: this.agenticAuthoringSemanticDecision(),
22740
- }));
23254
+ }).pipe(takeUntil(this.agenticTurnCancel$)));
23255
+ if (!this.isCurrentAgenticTurn(authorizationRunId)
23256
+ || !this.canUseAgenticAuthoring())
23257
+ return;
22741
23258
  this.agenticAuthoringLastEtag.set(result.etag ?? null);
22742
23259
  this.agenticAuthoringApplied.emit(result);
22743
23260
  this.agenticAuthoringPreviewResult.set(null);
@@ -22753,11 +23270,15 @@ class DynamicPageBuilderComponent {
22753
23270
  this.syncAgenticAuthoringSession();
22754
23271
  }
22755
23272
  catch (error) {
23273
+ if (!this.isCurrentAgenticTurn(authorizationRunId))
23274
+ return;
22756
23275
  this.agenticAuthoringStatus.set('');
22757
23276
  this.agenticAuthoringError.set(this.describeAgenticError(error));
22758
23277
  }
22759
23278
  finally {
22760
- this.agenticAuthoringBusy.set(false);
23279
+ if (this.isCurrentAgenticTurn(authorizationRunId)) {
23280
+ this.agenticAuthoringBusy.set(false);
23281
+ }
22761
23282
  }
22762
23283
  }
22763
23284
  async ensureSharedRuleDefinition() {
@@ -23772,6 +24293,9 @@ class DynamicPageBuilderComponent {
23772
24293
  }
23773
24294
  toAuthoringRuntimePage(page) {
23774
24295
  const cloned = this.clonePage(page);
24296
+ if (!this.isAuthoringCapabilityEnabled('childCustomization')) {
24297
+ return cloned;
24298
+ }
23775
24299
  cloned.widgets = (cloned.widgets || []).map((widget) => {
23776
24300
  const metadata = this.componentMetadata.get(widget.definition?.id);
23777
24301
  if (!metadata?.inputs?.some((input) => input.name === 'enableCustomization')) {
@@ -24607,7 +25131,7 @@ class DynamicPageBuilderComponent {
24607
25131
  return resolvePraxisPageBuilderText(this.i18n, key, fallback);
24608
25132
  }
24609
25133
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicPageBuilderComponent, deps: [{ token: i1.MatDialog }, { token: SETTINGS_PANEL_BRIDGE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
24610
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicPageBuilderComponent, isStandalone: true, selector: "praxis-dynamic-page-builder", inputs: { page: "page", context: "context", strictValidation: "strictValidation", autoPersist: "autoPersist", enableCustomization: "enableCustomization", showSettingsButton: "showSettingsButton", pageIdentity: "pageIdentity", componentInstanceId: "componentInstanceId", pageEditorComponent: "pageEditorComponent", componentPaletteAllowedWidgetIds: "componentPaletteAllowedWidgetIds", componentPaletteAllowedWidgetTags: "componentPaletteAllowedWidgetTags", componentPaletteAllowedPresetIds: "componentPaletteAllowedPresetIds", enableAgenticAuthoring: "enableAgenticAuthoring", agenticAuthoringProvider: "agenticAuthoringProvider", agenticAuthoringModel: "agenticAuthoringModel", agenticAuthoringApiKey: "agenticAuthoringApiKey", agenticAuthoringComponentId: "agenticAuthoringComponentId", agenticAuthoringScope: "agenticAuthoringScope", agenticAuthoringEtag: "agenticAuthoringEtag", agenticAuthoringIncludeLlmDiagnostics: "agenticAuthoringIncludeLlmDiagnostics", agenticAuthoringEnableStreaming: "agenticAuthoringEnableStreaming", agenticAuthoringVoiceInputMode: "agenticAuthoringVoiceInputMode", agenticAuthoringContextHints: "agenticAuthoringContextHints", showPageLifecycleActions: "showPageLifecycleActions", canDeleteSavedPage: "canDeleteSavedPage", pageLifecycleBusy: "pageLifecycleBusy", pageLifecycleResetRevision: "pageLifecycleResetRevision" }, outputs: { pageChange: "pageChange", widgetEvent: "widgetEvent", pageSaveRequested: "pageSaveRequested", agenticAuthoringApplied: "agenticAuthoringApplied", agenticAuthoringSharedRuleHandoff: "agenticAuthoringSharedRuleHandoff", pageRestart: "pageRestart", savedPageDeleteRequested: "savedPageDeleteRequested" }, providers: [
25134
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicPageBuilderComponent, isStandalone: true, selector: "praxis-dynamic-page-builder", inputs: { page: "page", context: "context", strictValidation: "strictValidation", autoPersist: "autoPersist", enableCustomization: "enableCustomization", authoringCapabilities: "authoringCapabilities", showSettingsButton: "showSettingsButton", pageIdentity: "pageIdentity", componentInstanceId: "componentInstanceId", pageEditorComponent: "pageEditorComponent", componentPaletteAllowedWidgetIds: "componentPaletteAllowedWidgetIds", componentPaletteAllowedWidgetTags: "componentPaletteAllowedWidgetTags", componentPaletteAllowedPresetIds: "componentPaletteAllowedPresetIds", enableAgenticAuthoring: "enableAgenticAuthoring", agenticAuthoringProvider: "agenticAuthoringProvider", agenticAuthoringModel: "agenticAuthoringModel", agenticAuthoringApiKey: "agenticAuthoringApiKey", agenticAuthoringComponentId: "agenticAuthoringComponentId", agenticAuthoringScope: "agenticAuthoringScope", agenticAuthoringEtag: "agenticAuthoringEtag", agenticAuthoringIncludeLlmDiagnostics: "agenticAuthoringIncludeLlmDiagnostics", agenticAuthoringEnableStreaming: "agenticAuthoringEnableStreaming", agenticAuthoringVoiceInputMode: "agenticAuthoringVoiceInputMode", agenticAuthoringContextHints: "agenticAuthoringContextHints", showPageLifecycleActions: "showPageLifecycleActions", canDeleteSavedPage: "canDeleteSavedPage", pageLifecycleBusy: "pageLifecycleBusy", pageLifecycleResetRevision: "pageLifecycleResetRevision" }, outputs: { pageChange: "pageChange", widgetEvent: "widgetEvent", pageSaveRequested: "pageSaveRequested", agenticAuthoringApplied: "agenticAuthoringApplied", agenticAuthoringSharedRuleHandoff: "agenticAuthoringSharedRuleHandoff", pageRestart: "pageRestart", savedPageDeleteRequested: "savedPageDeleteRequested" }, providers: [
24611
25135
  providePraxisPageBuilderI18n(),
24612
25136
  { provide: DYNAMIC_PAGE_SHELL_EDITOR, useValue: WidgetShellEditorComponent },
24613
25137
  ], viewQueries: [{ propertyName: "runtime", first: true, predicate: ["runtime"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
@@ -24640,7 +25164,7 @@ class DynamicPageBuilderComponent {
24640
25164
  <div>
24641
25165
  <strong>{{ issue.title }}</strong>
24642
25166
  <p>{{ issue.description }}</p>
24643
- @if (issue.action) {
25167
+ @if (issue.action && canRunPremiumReadinessAction(issue.action)) {
24644
25168
  <button
24645
25169
  type="button"
24646
25170
  class="builder-premium-readiness__action"
@@ -24664,11 +25188,12 @@ class DynamicPageBuilderComponent {
24664
25188
  [strictValidation]="strictValidation"
24665
25189
  [autoPersist]="false"
24666
25190
  [enableCustomization]="showSettings()"
25191
+ [authoringCapabilities]="authoringCapabilities"
24667
25192
  [showPageSettingsButton]="false"
24668
25193
  [pageIdentity]="pageIdentity"
24669
25194
  [componentInstanceId]="componentInstanceId"
24670
25195
  [pageEditorComponent]="pageEditorComponent"
24671
- [showWidgetAssistantButton]="showSettings() && enableAgenticAuthoring"
25196
+ [showWidgetAssistantButton]="canUseAgenticAuthoring()"
24672
25197
  (pageChange)="onRuntimePageChange($event)"
24673
25198
  (widgetEvent)="onRuntimeWidgetEvent($event)"
24674
25199
  (widgetSelectionChange)="onRuntimeWidgetSelectionChange($event)"
@@ -24676,7 +25201,7 @@ class DynamicPageBuilderComponent {
24676
25201
  />
24677
25202
 
24678
25203
  <praxis-connection-editor
24679
- [open]="showSettings() && connectionsViewerOpen()"
25204
+ [open]="canEditConnections() && connectionsViewerOpen()"
24680
25205
  [page]="currentPage()"
24681
25206
  (pageChange)="onConnectionEditorPageChange($event)"
24682
25207
  (focusWidget)="focusCanvasWidget($event)"
@@ -25068,7 +25593,9 @@ class DynamicPageBuilderComponent {
25068
25593
  [canUndo]="false"
25069
25594
  [canRedo]="false"
25070
25595
  [showSave]="canSaveCurrentPage()"
25071
- [showPreview]="hasPageWidgets()"
25596
+ [showPreview]="canPreviewPage()"
25597
+ [showAdd]="canInsertWidgets()"
25598
+ [showSettings]="canOpenPageSettings()"
25072
25599
  [editingEnabled]="showSettings()"
25073
25600
  [previewActive]="isPreviewMode()"
25074
25601
  [connectionMode]="showSettings() && connectionsViewerOpen()"
@@ -25085,7 +25612,7 @@ class DynamicPageBuilderComponent {
25085
25612
  (save)="saveCurrentPage()"
25086
25613
  (preview)="togglePreview()"
25087
25614
  >
25088
- @if (showSettings() && showPageLifecycleActions && hasPageWidgets()) {
25615
+ @if (canUsePageLifecycle() && hasPageWidgets()) {
25089
25616
  <button
25090
25617
  pdx-toolbar-extra
25091
25618
  mat-mini-fab
@@ -25099,7 +25626,7 @@ class DynamicPageBuilderComponent {
25099
25626
  <mat-icon [praxisIcon]="'restart_alt'"></mat-icon>
25100
25627
  </button>
25101
25628
  }
25102
- @if (showSettings() && showPageLifecycleActions && canDeleteSavedPage) {
25629
+ @if (canUsePageLifecycle() && canDeleteSavedPage) {
25103
25630
  <button
25104
25631
  pdx-toolbar-extra
25105
25632
  mat-mini-fab
@@ -25114,7 +25641,7 @@ class DynamicPageBuilderComponent {
25114
25641
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
25115
25642
  </button>
25116
25643
  }
25117
- @if (showSettings() && enableAgenticAuthoring) {
25644
+ @if (showSettings() && canUseAgenticAuthoring()) {
25118
25645
  <button
25119
25646
  pdx-toolbar-extra
25120
25647
  mat-mini-fab
@@ -25130,7 +25657,7 @@ class DynamicPageBuilderComponent {
25130
25657
  <mat-icon [praxisIcon]="'auto_awesome'"></mat-icon>
25131
25658
  </button>
25132
25659
  }
25133
- @if (showSettings() && hasPageWidgets()) {
25660
+ @if (canEditConnections() && hasPageWidgets()) {
25134
25661
  <button
25135
25662
  pdx-toolbar-extra
25136
25663
  mat-mini-fab
@@ -25155,7 +25682,7 @@ class DynamicPageBuilderComponent {
25155
25682
  }
25156
25683
  </praxis-floating-toolbar>
25157
25684
  </div>
25158
- `, 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%;box-sizing:border-box}.builder-shell--bottom-toolbar{padding-block-end:calc(80px + env(safe-area-inset-bottom,0px))}.builder-shell:has(.pdx-shell.fullscreen) praxis-floating-toolbar{display:none}.builder-premium-readiness{display:grid;grid-template-columns:minmax(220px,.72fr) minmax(0,1.28fr);gap:12px;width:100%;margin:0 0 14px;padding:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #cac4d0) 72%,transparent);border-radius:12px;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 10%,transparent),transparent 36%),color-mix(in srgb,var(--md-sys-color-surface-container-lowest, #fff) 96%,transparent);color:var(--md-sys-color-on-surface, #1d1b20);box-shadow:inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface, #1d1b20) 5%,transparent)}.builder-premium-readiness__header{display:flex;align-items:flex-start;gap:10px;min-width:0}.builder-premium-readiness__header strong{display:block;font-size:13px;line-height:1.25}.builder-premium-readiness__header p,.builder-premium-readiness__item p{margin:2px 0 0;color:var(--md-sys-color-on-surface-variant, #49454f);font-size:11px;line-height:1.35}.builder-premium-readiness__icon{color:var(--md-sys-color-primary, #6750a4);font-size:20px;line-height:1}.builder-premium-readiness__list{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:8px;margin:0;padding:0;list-style:none}.builder-premium-readiness__item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px;min-width:0;padding:9px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #cac4d0) 64%,transparent);border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low, #f7f2fa) 84%,transparent)}.builder-premium-readiness__item strong{display:block;font-size:12px;line-height:1.25}.builder-premium-readiness__action{appearance:none;display:inline-flex;align-items:center;justify-content:center;min-height:26px;margin-top:7px;padding:4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 34%,transparent);border-radius:7px;background:color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 9%,var(--md-sys-color-surface, #fff));color:var(--md-sys-color-primary, #6750a4);cursor:pointer;font:inherit;font-size:11px;font-weight:700;line-height:1.2;text-align:left}.builder-premium-readiness__severity{width:8px;height:8px;margin-top:4px;border-radius:999px;background:var(--md-sys-color-primary, #6750a4)}.builder-premium-readiness__item[data-severity=warning] .builder-premium-readiness__severity{background:var(--praxis-warning, #b26a00)}.builder-premium-readiness__item[data-severity=error] .builder-premium-readiness__severity{background:var(--md-sys-color-error, #b3261e)}@media(max-width:760px){.builder-premium-readiness{grid-template-columns:1fr}}.agentic-diagnostics-panel{position:absolute;z-index:21;right:16px;width:min(520px,calc(100% - 32px));max-height:min(440px,calc(100% - 32px));overflow:auto;padding:12px;border:1px solid rgba(107,114,128,.28);border-radius:8px;background:#fffffff5;color:#111827;box-shadow:0 14px 36px #0000003d}.agentic-diagnostics-panel--collapsed{width:min(280px,calc(100% - 32px));max-height:58px;overflow:hidden;padding:10px 12px;pointer-events:auto}.agentic-diagnostics-panel__header{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:13px;font-weight:700}.agentic-diagnostics-panel__header-actions{display:flex;align-items:center;gap:8px}.agentic-diagnostics-panel__badge{padding:2px 6px;border:1px solid rgba(107,114,128,.28);border-radius:8px;font-size:11px;font-weight:600;color:#4b5563}.agentic-diagnostics-panel__toggle,.shared-rule-cockpit__toggle{appearance:none;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent);border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 84%,transparent);color:var(--md-sys-color-primary);cursor:pointer;font-size:11px;font-weight:700;line-height:1;padding:6px 9px;white-space:nowrap}.agentic-diagnostics-panel__description{margin:8px 0 10px;color:#4b5563;font-size:12px;line-height:1.4}.agentic-diagnostics-panel pre{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px;line-height:1.45;color:#1f2937}.agentic-diagnostics-panel__health{display:grid;gap:8px;margin-bottom:12px}.agentic-diagnostics-panel__health h3,.agentic-diagnostics-panel__health p{margin:0}.agentic-diagnostics-panel__health h3{font-size:13px}.agentic-diagnostics-panel__health p{color:#4b5563;font-size:11px}.agentic-diagnostics-panel__metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:0}.agentic-diagnostics-panel__metrics div{padding:8px;border-radius:8px;background:#f3f4f6}.agentic-diagnostics-panel__metrics dt{color:#4b5563;font-size:10px}.agentic-diagnostics-panel__metrics dd{margin:3px 0 0;font-size:14px;font-weight:700}.agentic-diagnostics-panel__health-table{width:100%;border-collapse:collapse;font-size:10px}.agentic-diagnostics-panel__health-table caption{margin-bottom:4px;text-align:left;font-weight:700}.agentic-diagnostics-panel__health-table th,.agentic-diagnostics-panel__health-table td{padding:5px 4px;border-bottom:1px solid #e5e7eb;text-align:left}.agentic-diagnostics-panel__raw summary{margin-bottom:8px;cursor:pointer;font-size:11px;font-weight:700}@media(max-width:520px){.agentic-diagnostics-panel__metrics{grid-template-columns:repeat(2,minmax(0,1fr))}}praxis-ai-assistant-shell{position:fixed;inset:0;z-index:140;pointer-events:none}@media(min-width:1100px){.builder-shell--agentic-review-rail{box-sizing:border-box;padding-right:464px}}.builder-shell__agentic-toggle{position:relative}.builder-shell__agentic-toggle--open,.builder-shell__agentic-toggle--minimized{outline:2px solid rgba(96,165,250,.52);outline-offset:2px}.builder-shell__agentic-toggle--minimized:after{content:\"\";position:absolute;top:6px;right:6px;width:8px;height:8px;border:2px solid var(--md-sys-color-surface, #111827);border-radius:999px;background:#34d399}.builder-shell__connections-toggle--open{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 52%,transparent);outline-offset:2px}.builder-shell__connections-toggle{position:relative}.builder-shell__connections-toggle--recommended:not(.builder-shell__connections-toggle--open){outline:2px solid rgba(34,211,238,.48);outline-offset:2px}.builder-shell__connections-toggle-badge{position:absolute;top:5px;right:5px;width:9px;height:9px;border:2px solid var(--md-sys-color-surface, #111827);border-radius:999px;background:#22d3ee;box-shadow:0 0 0 3px #22d3ee2e}.shared-rule-cockpit{position:absolute;z-index:120;left:16px;bottom:88px;width:min(720px,calc(100% - 32px));max-height:min(560px,calc(100vh - 140px));padding:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,transparent);border-radius:12px;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary-container) 24%,var(--md-sys-color-surface-container-high) 76%),color-mix(in srgb,var(--md-sys-color-tertiary-container) 18%,var(--md-sys-color-surface-container) 82%));color:var(--md-sys-color-on-surface);box-shadow:0 18px 46px color-mix(in srgb,var(--md-sys-color-shadow, #000) 24%,transparent);overflow:auto;overscroll-behavior:contain}.shared-rule-cockpit--collapsed{width:min(360px,calc(100% - 32px));max-height:72px;overflow:hidden;padding:10px 12px}.shared-rule-cockpit__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.shared-rule-cockpit__header-actions{display:flex;align-items:center;gap:8px}.shared-rule-cockpit__header div{display:grid;gap:2px}.shared-rule-cockpit__header strong{font-size:14px;line-height:1.2}.shared-rule-cockpit__header span{color:var(--md-sys-color-on-surface-variant);font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__badge{flex:0 0 auto;max-width:220px;padding:3px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent);border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 74%,transparent);color:var(--md-sys-color-primary);font-size:11px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shared-rule-cockpit__description,.shared-rule-cockpit__status,.shared-rule-cockpit__error{margin:10px 0 0;color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.shared-rule-cockpit__error{color:var(--md-sys-color-error);font-weight:600}.shared-rule-cockpit__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.shared-rule-cockpit__facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:12px 0 0}.shared-rule-cockpit__facts div{min-width:0;padding:8px;border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 72%,transparent)}.shared-rule-cockpit__facts dt{color:var(--md-sys-color-on-surface-variant);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.shared-rule-cockpit__facts dd{margin:4px 0 0;color:var(--md-sys-color-on-surface);font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__enforcement-matrix{display:grid;gap:10px;margin-top:12px;padding:10px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 14%,transparent);border-radius:12px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 58%,transparent)}.shared-rule-cockpit__matrix-header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.shared-rule-cockpit__matrix-header div{display:grid;gap:2px}.shared-rule-cockpit__matrix-header strong{color:var(--md-sys-color-on-surface);font-size:12px}.shared-rule-cockpit__matrix-header span,.shared-rule-cockpit__matrix-source{color:var(--md-sys-color-on-surface-variant);font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-badge{flex:0 0 auto;padding:3px 8px;border-radius:999px;background:#16a34a1f;color:#166534;font-weight:800;white-space:nowrap}.shared-rule-cockpit__projection-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.shared-rule-cockpit__projection{display:grid;gap:3px;min-width:0;padding:9px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 52%,transparent);border-radius:11px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 82%,transparent)}.shared-rule-cockpit__projection[data-status=ready]{border-color:color-mix(in srgb,var(--md-sys-color-tertiary) 24%,transparent);background:color-mix(in srgb,var(--md-sys-color-tertiary-container) 32%,var(--md-sys-color-surface-container-low) 68%)}.shared-rule-cockpit__projection span{color:var(--md-sys-color-primary);font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;overflow-wrap:anywhere}.shared-rule-cockpit__projection strong{color:var(--md-sys-color-on-surface);font-size:12px}.shared-rule-cockpit__projection small,.shared-rule-cockpit__projection em{color:var(--md-sys-color-on-surface-variant);font-size:11px;font-style:normal;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-source{margin:0}.shared-rule-cockpit__timeline{display:grid;gap:8px;max-height:190px;margin:12px 0 0;padding:0;overflow:auto;list-style:none}.shared-rule-cockpit__timeline-item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent);border-radius:12px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 76%,transparent)}.shared-rule-cockpit__timeline-icon{display:grid;width:24px;height:24px;place-items:center;border-radius:999px;background:#1e40af1a;color:var(--md-sys-color-primary);font-family:Material Icons;font-size:16px;line-height:1}.shared-rule-cockpit__timeline-item strong{color:var(--md-sys-color-on-surface);font-size:12px;line-height:1.35}.shared-rule-cockpit__timeline-item p,.shared-rule-cockpit__timeline-item small,.shared-rule-cockpit__timeline-item time,.shared-rule-cockpit__timeline-empty{display:block;margin:3px 0 0;color:var(--md-sys-color-on-surface-variant);font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__timeline-badge{display:inline-flex;margin-left:6px;padding:2px 6px;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-secondary-container) 42%,transparent);color:var(--md-sys-color-on-secondary-container);font-size:10px;font-weight:700}.shared-rule-cockpit__timeline-empty{padding:10px;border-radius:12px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 64%,transparent)}@media(max-width:720px){.shared-rule-cockpit{bottom:72px;max-height:calc(100vh - 112px)}.shared-rule-cockpit__facts,.shared-rule-cockpit__projection-grid{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: DynamicWidgetPageComponent, selector: "praxis-dynamic-page", inputs: ["page", "context", "strictValidation", "enableCustomization", "showPageSettingsButton", "shellEditorComponent", "pageEditorComponent", "autoPersist", "pageIdentity", "componentInstanceId", "showWidgetAssistantButton"], outputs: ["pageChange", "widgetEvent", "widgetSelectionChange", "widgetAssistantRequested", "widgetDiagnosticsChange"] }, { kind: "component", type: FloatingToolbarComponent, selector: "praxis-floating-toolbar", inputs: ["visible", "canUndo", "canRedo", "showSave", "showPreview", "editingEnabled", "previewActive", "connectionMode", "modeLabel", "addLabel", "saveLabel", "undoLabel", "redoLabel", "settingsLabel", "previewLabel", "exitPreviewLabel"], outputs: ["add", "undo", "redo", "settings", "preview", "save"] }, { kind: "component", type: ConnectionEditorComponent, selector: "praxis-connection-editor", inputs: ["open", "page"], outputs: ["pageChange", "focusWidget", "openPageSettings", "close"] }, { kind: "component", type: PraxisAiAssistantShellComponent, selector: "praxis-ai-assistant-shell", inputs: ["labels", "mode", "state", "contextItems", "attachments", "messages", "quickReplies", "recommendedIntents", "prompt", "statusText", "errorText", "testIdPrefix", "panelTestId", "submitTestId", "applyTestId", "primaryAction", "secondaryActions", "governanceActions", "busy", "canSubmit", "canApply", "submitOnEnter", "showAttachAction", "enablePastedAttachments", "enableFileAttachments", "attachmentAccept", "attachmentMultiple", "voiceInputMode", "voiceLanguage", "draggable", "resizable", "minWidth", "minHeight", "margin", "layout"], outputs: ["promptChange", "submitPrompt", "apply", "retryTurn", "cancelTurn", "shellAction", "close", "attach", "attachmentsPasted", "attachmentsSelected", "removeAttachment", "messageAction", "editMessage", "resendMessage", "quickReply", "recommendedIntent", "layoutChange"] }] });
25685
+ `, 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%;box-sizing:border-box}.builder-shell--bottom-toolbar{padding-block-end:calc(80px + env(safe-area-inset-bottom,0px))}.builder-shell:has(.pdx-shell.fullscreen) praxis-floating-toolbar{display:none}.builder-premium-readiness{display:grid;grid-template-columns:minmax(220px,.72fr) minmax(0,1.28fr);gap:12px;width:100%;margin:0 0 14px;padding:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #cac4d0) 72%,transparent);border-radius:12px;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 10%,transparent),transparent 36%),color-mix(in srgb,var(--md-sys-color-surface-container-lowest, #fff) 96%,transparent);color:var(--md-sys-color-on-surface, #1d1b20);box-shadow:inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface, #1d1b20) 5%,transparent)}.builder-premium-readiness__header{display:flex;align-items:flex-start;gap:10px;min-width:0}.builder-premium-readiness__header strong{display:block;font-size:13px;line-height:1.25}.builder-premium-readiness__header p,.builder-premium-readiness__item p{margin:2px 0 0;color:var(--md-sys-color-on-surface-variant, #49454f);font-size:11px;line-height:1.35}.builder-premium-readiness__icon{color:var(--md-sys-color-primary, #6750a4);font-size:20px;line-height:1}.builder-premium-readiness__list{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:8px;margin:0;padding:0;list-style:none}.builder-premium-readiness__item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px;min-width:0;padding:9px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #cac4d0) 64%,transparent);border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low, #f7f2fa) 84%,transparent)}.builder-premium-readiness__item strong{display:block;font-size:12px;line-height:1.25}.builder-premium-readiness__action{appearance:none;display:inline-flex;align-items:center;justify-content:center;min-height:26px;margin-top:7px;padding:4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 34%,transparent);border-radius:7px;background:color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 9%,var(--md-sys-color-surface, #fff));color:var(--md-sys-color-primary, #6750a4);cursor:pointer;font:inherit;font-size:11px;font-weight:700;line-height:1.2;text-align:left}.builder-premium-readiness__severity{width:8px;height:8px;margin-top:4px;border-radius:999px;background:var(--md-sys-color-primary, #6750a4)}.builder-premium-readiness__item[data-severity=warning] .builder-premium-readiness__severity{background:var(--praxis-warning, #b26a00)}.builder-premium-readiness__item[data-severity=error] .builder-premium-readiness__severity{background:var(--md-sys-color-error, #b3261e)}@media(max-width:760px){.builder-premium-readiness{grid-template-columns:1fr}}.agentic-diagnostics-panel{position:absolute;z-index:21;right:16px;width:min(520px,calc(100% - 32px));max-height:min(440px,calc(100% - 32px));overflow:auto;padding:12px;border:1px solid rgba(107,114,128,.28);border-radius:8px;background:#fffffff5;color:#111827;box-shadow:0 14px 36px #0000003d}.agentic-diagnostics-panel--collapsed{width:min(280px,calc(100% - 32px));max-height:58px;overflow:hidden;padding:10px 12px;pointer-events:auto}.agentic-diagnostics-panel__header{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:13px;font-weight:700}.agentic-diagnostics-panel__header-actions{display:flex;align-items:center;gap:8px}.agentic-diagnostics-panel__badge{padding:2px 6px;border:1px solid rgba(107,114,128,.28);border-radius:8px;font-size:11px;font-weight:600;color:#4b5563}.agentic-diagnostics-panel__toggle,.shared-rule-cockpit__toggle{appearance:none;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent);border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 84%,transparent);color:var(--md-sys-color-primary);cursor:pointer;font-size:11px;font-weight:700;line-height:1;padding:6px 9px;white-space:nowrap}.agentic-diagnostics-panel__description{margin:8px 0 10px;color:#4b5563;font-size:12px;line-height:1.4}.agentic-diagnostics-panel pre{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px;line-height:1.45;color:#1f2937}.agentic-diagnostics-panel__health{display:grid;gap:8px;margin-bottom:12px}.agentic-diagnostics-panel__health h3,.agentic-diagnostics-panel__health p{margin:0}.agentic-diagnostics-panel__health h3{font-size:13px}.agentic-diagnostics-panel__health p{color:#4b5563;font-size:11px}.agentic-diagnostics-panel__metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:0}.agentic-diagnostics-panel__metrics div{padding:8px;border-radius:8px;background:#f3f4f6}.agentic-diagnostics-panel__metrics dt{color:#4b5563;font-size:10px}.agentic-diagnostics-panel__metrics dd{margin:3px 0 0;font-size:14px;font-weight:700}.agentic-diagnostics-panel__health-table{width:100%;border-collapse:collapse;font-size:10px}.agentic-diagnostics-panel__health-table caption{margin-bottom:4px;text-align:left;font-weight:700}.agentic-diagnostics-panel__health-table th,.agentic-diagnostics-panel__health-table td{padding:5px 4px;border-bottom:1px solid #e5e7eb;text-align:left}.agentic-diagnostics-panel__raw summary{margin-bottom:8px;cursor:pointer;font-size:11px;font-weight:700}@media(max-width:520px){.agentic-diagnostics-panel__metrics{grid-template-columns:repeat(2,minmax(0,1fr))}}praxis-ai-assistant-shell{position:fixed;inset:0;z-index:140;pointer-events:none}@media(min-width:1100px){.builder-shell--agentic-review-rail{box-sizing:border-box;padding-right:464px}}.builder-shell__agentic-toggle{position:relative}.builder-shell__agentic-toggle--open,.builder-shell__agentic-toggle--minimized{outline:2px solid rgba(96,165,250,.52);outline-offset:2px}.builder-shell__agentic-toggle--minimized:after{content:\"\";position:absolute;top:6px;right:6px;width:8px;height:8px;border:2px solid var(--md-sys-color-surface, #111827);border-radius:999px;background:#34d399}.builder-shell__connections-toggle--open{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary, #6750a4) 52%,transparent);outline-offset:2px}.builder-shell__connections-toggle{position:relative}.builder-shell__connections-toggle--recommended:not(.builder-shell__connections-toggle--open){outline:2px solid rgba(34,211,238,.48);outline-offset:2px}.builder-shell__connections-toggle-badge{position:absolute;top:5px;right:5px;width:9px;height:9px;border:2px solid var(--md-sys-color-surface, #111827);border-radius:999px;background:#22d3ee;box-shadow:0 0 0 3px #22d3ee2e}.shared-rule-cockpit{position:absolute;z-index:120;left:16px;bottom:88px;width:min(720px,calc(100% - 32px));max-height:min(560px,calc(100vh - 140px));padding:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,transparent);border-radius:12px;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary-container) 24%,var(--md-sys-color-surface-container-high) 76%),color-mix(in srgb,var(--md-sys-color-tertiary-container) 18%,var(--md-sys-color-surface-container) 82%));color:var(--md-sys-color-on-surface);box-shadow:0 18px 46px color-mix(in srgb,var(--md-sys-color-shadow, #000) 24%,transparent);overflow:auto;overscroll-behavior:contain}.shared-rule-cockpit--collapsed{width:min(360px,calc(100% - 32px));max-height:72px;overflow:hidden;padding:10px 12px}.shared-rule-cockpit__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.shared-rule-cockpit__header-actions{display:flex;align-items:center;gap:8px}.shared-rule-cockpit__header div{display:grid;gap:2px}.shared-rule-cockpit__header strong{font-size:14px;line-height:1.2}.shared-rule-cockpit__header span{color:var(--md-sys-color-on-surface-variant);font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__badge{flex:0 0 auto;max-width:220px;padding:3px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent);border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 74%,transparent);color:var(--md-sys-color-primary);font-size:11px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shared-rule-cockpit__description,.shared-rule-cockpit__status,.shared-rule-cockpit__error{margin:10px 0 0;color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.shared-rule-cockpit__error{color:var(--md-sys-color-error);font-weight:600}.shared-rule-cockpit__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.shared-rule-cockpit__facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:12px 0 0}.shared-rule-cockpit__facts div{min-width:0;padding:8px;border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 72%,transparent)}.shared-rule-cockpit__facts dt{color:var(--md-sys-color-on-surface-variant);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.shared-rule-cockpit__facts dd{margin:4px 0 0;color:var(--md-sys-color-on-surface);font-size:12px;overflow-wrap:anywhere}.shared-rule-cockpit__enforcement-matrix{display:grid;gap:10px;margin-top:12px;padding:10px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 14%,transparent);border-radius:12px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 58%,transparent)}.shared-rule-cockpit__matrix-header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.shared-rule-cockpit__matrix-header div{display:grid;gap:2px}.shared-rule-cockpit__matrix-header strong{color:var(--md-sys-color-on-surface);font-size:12px}.shared-rule-cockpit__matrix-header span,.shared-rule-cockpit__matrix-source{color:var(--md-sys-color-on-surface-variant);font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-badge{flex:0 0 auto;padding:3px 8px;border-radius:999px;background:#16a34a1f;color:#166534;font-weight:800;white-space:nowrap}.shared-rule-cockpit__projection-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.shared-rule-cockpit__projection{display:grid;gap:3px;min-width:0;padding:9px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 52%,transparent);border-radius:11px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 82%,transparent)}.shared-rule-cockpit__projection[data-status=ready]{border-color:color-mix(in srgb,var(--md-sys-color-tertiary) 24%,transparent);background:color-mix(in srgb,var(--md-sys-color-tertiary-container) 32%,var(--md-sys-color-surface-container-low) 68%)}.shared-rule-cockpit__projection span{color:var(--md-sys-color-primary);font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;overflow-wrap:anywhere}.shared-rule-cockpit__projection strong{color:var(--md-sys-color-on-surface);font-size:12px}.shared-rule-cockpit__projection small,.shared-rule-cockpit__projection em{color:var(--md-sys-color-on-surface-variant);font-size:11px;font-style:normal;overflow-wrap:anywhere}.shared-rule-cockpit__matrix-source{margin:0}.shared-rule-cockpit__timeline{display:grid;gap:8px;max-height:190px;margin:12px 0 0;padding:0;overflow:auto;list-style:none}.shared-rule-cockpit__timeline-item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent);border-radius:12px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 76%,transparent)}.shared-rule-cockpit__timeline-icon{display:grid;width:24px;height:24px;place-items:center;border-radius:999px;background:#1e40af1a;color:var(--md-sys-color-primary);font-family:Material Icons;font-size:16px;line-height:1}.shared-rule-cockpit__timeline-item strong{color:var(--md-sys-color-on-surface);font-size:12px;line-height:1.35}.shared-rule-cockpit__timeline-item p,.shared-rule-cockpit__timeline-item small,.shared-rule-cockpit__timeline-item time,.shared-rule-cockpit__timeline-empty{display:block;margin:3px 0 0;color:var(--md-sys-color-on-surface-variant);font-size:11px;line-height:1.35;overflow-wrap:anywhere}.shared-rule-cockpit__timeline-badge{display:inline-flex;margin-left:6px;padding:2px 6px;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-secondary-container) 42%,transparent);color:var(--md-sys-color-on-secondary-container);font-size:10px;font-weight:700}.shared-rule-cockpit__timeline-empty{padding:10px;border-radius:12px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 64%,transparent)}@media(max-width:720px){.shared-rule-cockpit{bottom:72px;max-height:calc(100vh - 112px)}.shared-rule-cockpit__facts,.shared-rule-cockpit__projection-grid{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: DynamicWidgetPageComponent, selector: "praxis-dynamic-page", inputs: ["page", "context", "strictValidation", "enableCustomization", "authoringCapabilities", "showPageSettingsButton", "shellEditorComponent", "pageEditorComponent", "autoPersist", "pageIdentity", "componentInstanceId", "showWidgetAssistantButton"], outputs: ["pageChange", "widgetEvent", "widgetSelectionChange", "widgetAssistantRequested", "widgetDiagnosticsChange"] }, { kind: "component", type: FloatingToolbarComponent, selector: "praxis-floating-toolbar", inputs: ["visible", "canUndo", "canRedo", "showSave", "showPreview", "showAdd", "showSettings", "editingEnabled", "previewActive", "connectionMode", "modeLabel", "addLabel", "saveLabel", "undoLabel", "redoLabel", "settingsLabel", "previewLabel", "exitPreviewLabel"], outputs: ["add", "undo", "redo", "settings", "preview", "save"] }, { kind: "component", type: ConnectionEditorComponent, selector: "praxis-connection-editor", inputs: ["open", "page"], outputs: ["pageChange", "focusWidget", "openPageSettings", "close"] }, { kind: "component", type: PraxisAiAssistantShellComponent, selector: "praxis-ai-assistant-shell", inputs: ["labels", "mode", "state", "contextItems", "attachments", "messages", "quickReplies", "recommendedIntents", "prompt", "statusText", "errorText", "testIdPrefix", "panelTestId", "submitTestId", "applyTestId", "primaryAction", "secondaryActions", "governanceActions", "busy", "canSubmit", "canApply", "submitOnEnter", "showAttachAction", "enablePastedAttachments", "enableFileAttachments", "attachmentAccept", "attachmentMultiple", "voiceInputMode", "voiceLanguage", "draggable", "resizable", "minWidth", "minHeight", "margin", "layout"], outputs: ["promptChange", "submitPrompt", "apply", "retryTurn", "cancelTurn", "shellAction", "close", "attach", "attachmentsPasted", "attachmentsSelected", "removeAttachment", "messageAction", "editMessage", "resendMessage", "quickReply", "recommendedIntent", "layoutChange"] }] });
25159
25686
  }
25160
25687
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicPageBuilderComponent, decorators: [{
25161
25688
  type: Component,
@@ -25201,7 +25728,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25201
25728
  <div>
25202
25729
  <strong>{{ issue.title }}</strong>
25203
25730
  <p>{{ issue.description }}</p>
25204
- @if (issue.action) {
25731
+ @if (issue.action && canRunPremiumReadinessAction(issue.action)) {
25205
25732
  <button
25206
25733
  type="button"
25207
25734
  class="builder-premium-readiness__action"
@@ -25225,11 +25752,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25225
25752
  [strictValidation]="strictValidation"
25226
25753
  [autoPersist]="false"
25227
25754
  [enableCustomization]="showSettings()"
25755
+ [authoringCapabilities]="authoringCapabilities"
25228
25756
  [showPageSettingsButton]="false"
25229
25757
  [pageIdentity]="pageIdentity"
25230
25758
  [componentInstanceId]="componentInstanceId"
25231
25759
  [pageEditorComponent]="pageEditorComponent"
25232
- [showWidgetAssistantButton]="showSettings() && enableAgenticAuthoring"
25760
+ [showWidgetAssistantButton]="canUseAgenticAuthoring()"
25233
25761
  (pageChange)="onRuntimePageChange($event)"
25234
25762
  (widgetEvent)="onRuntimeWidgetEvent($event)"
25235
25763
  (widgetSelectionChange)="onRuntimeWidgetSelectionChange($event)"
@@ -25237,7 +25765,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25237
25765
  />
25238
25766
 
25239
25767
  <praxis-connection-editor
25240
- [open]="showSettings() && connectionsViewerOpen()"
25768
+ [open]="canEditConnections() && connectionsViewerOpen()"
25241
25769
  [page]="currentPage()"
25242
25770
  (pageChange)="onConnectionEditorPageChange($event)"
25243
25771
  (focusWidget)="focusCanvasWidget($event)"
@@ -25629,7 +26157,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25629
26157
  [canUndo]="false"
25630
26158
  [canRedo]="false"
25631
26159
  [showSave]="canSaveCurrentPage()"
25632
- [showPreview]="hasPageWidgets()"
26160
+ [showPreview]="canPreviewPage()"
26161
+ [showAdd]="canInsertWidgets()"
26162
+ [showSettings]="canOpenPageSettings()"
25633
26163
  [editingEnabled]="showSettings()"
25634
26164
  [previewActive]="isPreviewMode()"
25635
26165
  [connectionMode]="showSettings() && connectionsViewerOpen()"
@@ -25646,7 +26176,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25646
26176
  (save)="saveCurrentPage()"
25647
26177
  (preview)="togglePreview()"
25648
26178
  >
25649
- @if (showSettings() && showPageLifecycleActions && hasPageWidgets()) {
26179
+ @if (canUsePageLifecycle() && hasPageWidgets()) {
25650
26180
  <button
25651
26181
  pdx-toolbar-extra
25652
26182
  mat-mini-fab
@@ -25660,7 +26190,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25660
26190
  <mat-icon [praxisIcon]="'restart_alt'"></mat-icon>
25661
26191
  </button>
25662
26192
  }
25663
- @if (showSettings() && showPageLifecycleActions && canDeleteSavedPage) {
26193
+ @if (canUsePageLifecycle() && canDeleteSavedPage) {
25664
26194
  <button
25665
26195
  pdx-toolbar-extra
25666
26196
  mat-mini-fab
@@ -25675,7 +26205,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25675
26205
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
25676
26206
  </button>
25677
26207
  }
25678
- @if (showSettings() && enableAgenticAuthoring) {
26208
+ @if (showSettings() && canUseAgenticAuthoring()) {
25679
26209
  <button
25680
26210
  pdx-toolbar-extra
25681
26211
  mat-mini-fab
@@ -25691,7 +26221,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25691
26221
  <mat-icon [praxisIcon]="'auto_awesome'"></mat-icon>
25692
26222
  </button>
25693
26223
  }
25694
- @if (showSettings() && hasPageWidgets()) {
26224
+ @if (canEditConnections() && hasPageWidgets()) {
25695
26225
  <button
25696
26226
  pdx-toolbar-extra
25697
26227
  mat-mini-fab
@@ -25735,6 +26265,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25735
26265
  type: Input
25736
26266
  }], enableCustomization: [{
25737
26267
  type: Input
26268
+ }], authoringCapabilities: [{
26269
+ type: Input
25738
26270
  }], showSettingsButton: [{
25739
26271
  type: Input
25740
26272
  }], pageIdentity: [{