@acorex/platform 21.0.0-beta.2 → 21.0.0-beta.4

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.
Files changed (31) hide show
  1. package/fesm2022/{acorex-platform-common-common-settings.provider-G9XcXXOG.mjs → acorex-platform-common-common-settings.provider-lWz_f-Ia.mjs} +22 -24
  2. package/fesm2022/acorex-platform-common-common-settings.provider-lWz_f-Ia.mjs.map +1 -0
  3. package/fesm2022/acorex-platform-common.mjs +115 -23
  4. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-core.mjs +89 -1
  6. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-layout-builder.mjs +104 -13
  8. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-layout-components.mjs +220 -2
  10. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-layout-designer.mjs +37 -2
  12. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  13. package/fesm2022/acorex-platform-layout-entity.mjs +149 -2
  14. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  15. package/fesm2022/acorex-platform-layout-widgets.mjs +62 -17
  16. package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
  17. package/fesm2022/acorex-platform-runtime.mjs +65 -2
  18. package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
  19. package/fesm2022/{acorex-platform-themes-shared-settings.provider-D13QB3Hr.mjs → acorex-platform-themes-shared-settings.provider-DK6R87Lf.mjs} +23 -24
  20. package/fesm2022/acorex-platform-themes-shared-settings.provider-DK6R87Lf.mjs.map +1 -0
  21. package/fesm2022/acorex-platform-themes-shared.mjs +2 -2
  22. package/package.json +2 -4
  23. package/types/acorex-platform-common.d.ts +38 -4
  24. package/types/acorex-platform-core.d.ts +20 -2
  25. package/types/acorex-platform-layout-builder.d.ts +26 -3
  26. package/types/acorex-platform-layout-components.d.ts +52 -1
  27. package/types/acorex-platform-layout-entity.d.ts +19 -2
  28. package/types/acorex-platform-layout-widgets.d.ts +19 -5
  29. package/types/acorex-platform-runtime.d.ts +6 -0
  30. package/fesm2022/acorex-platform-common-common-settings.provider-G9XcXXOG.mjs.map +0 -1
  31. package/fesm2022/acorex-platform-themes-shared-settings.provider-D13QB3Hr.mjs.map +0 -1
@@ -2,7 +2,7 @@ import * as i5 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
4
  import { Injectable, inject, input, model, signal, computed, effect, output, viewChild, ChangeDetectionStrategy, Component, NgModule, EventEmitter, Output } from '@angular/core';
5
- import { provideCommandSetups } from '@acorex/platform/runtime';
5
+ import { provideCommandSetups, AXPCommandService } from '@acorex/platform/runtime';
6
6
  import { AXPopupService } from '@acorex/components/popup';
7
7
  import * as i4 from '@acorex/platform/core';
8
8
  import { AXPHookService, AXPExpressionEvaluatorService, AXPComponentSlotModule, AXPContextStore } from '@acorex/platform/core';
@@ -40,6 +40,15 @@ const AXP_LAYOUT_BUILDER_DIALOG_BEFORE_OPEN_HOOK_KEY = 'layout-builder.dialog.be
40
40
  */
41
41
  const AXP_LAYOUT_BUILDER_DIALOG_CONFIG_HOOK_KEY = 'layout-builder.dialog.config';
42
42
  //#endregion
43
+ //#region ---- Context updates (after open) ----
44
+ /**
45
+ * Runs whenever the dialog layout builder context changes (debounced upstream), **after** the popup is visible.
46
+ * Use for side effects that depend on live context (for example values updated by widgets after render).
47
+ * Payload mirrors `AXPDialogRendererComponent` semantics: {@link AXPLayoutBuilderDialogContextChangedPayload.getContext},
48
+ * {@link AXPLayoutBuilderDialogContextChangedPayload.patchContext}, and optional loading state.
49
+ */
50
+ const AXP_LAYOUT_BUILDER_DIALOG_CONTEXT_CHANGED_HOOK_KEY = 'layout-builder.dialog.context-changed';
51
+ //#endregion
43
52
 
44
53
  class AXPLayoutConversionService {
45
54
  constructor() {
@@ -1670,7 +1679,8 @@ class DialogContainerBuilder {
1670
1679
  // Create dialog configuration
1671
1680
  const dialogConfig = {
1672
1681
  title: this.dialogState.dialogOptions?.title || '',
1673
- message: this.dialogState.dialogOptions?.message,
1682
+ //TODO: why we need message?
1683
+ //message: this.dialogState.dialogOptions?.message,
1674
1684
  context: initialContext,
1675
1685
  definition: dialogNode,
1676
1686
  metadata: this.dialogState.dialogOptions.metadata,
@@ -1684,7 +1694,7 @@ class DialogContainerBuilder {
1684
1694
  // The Promise resolves when user clicks an action button
1685
1695
  return new Promise(async (resolve) => {
1686
1696
  let flag = false;
1687
- this.popupService.open(AXPDialogRendererComponent, {
1697
+ await this.popupService.open(AXPDialogRendererComponent, {
1688
1698
  title: dialogConfig.title,
1689
1699
  size: this.dialogState.dialogOptions?.size || 'md',
1690
1700
  closeButton: this.dialogState.dialogOptions?.closeButton || false,
@@ -2360,6 +2370,8 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2360
2370
  super(...arguments);
2361
2371
  this.result = new EventEmitter();
2362
2372
  this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
2373
+ this.commandService = inject(AXPCommandService);
2374
+ this.hookService = inject(AXPHookService, { optional: true });
2363
2375
  this.context = signal({}, ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
2364
2376
  // This will be set by the popup service automatically - same as dynamic-dialog
2365
2377
  this.callBack = () => { };
@@ -2367,6 +2379,12 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2367
2379
  // Aggregated actions for footer rendering
2368
2380
  this.footerPrefix = signal([], ...(ngDevMode ? [{ debugName: "footerPrefix" }] : /* istanbul ignore next */ []));
2369
2381
  this.footerSuffix = signal([], ...(ngDevMode ? [{ debugName: "footerSuffix" }] : /* istanbul ignore next */ []));
2382
+ /**
2383
+ * Correlate layout context snapshots for distributed hooks (`layout-builder.dialog.context-changed`).
2384
+ */
2385
+ this.contextChangedHooksSessionKey = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'
2386
+ ? crypto.randomUUID()
2387
+ : `layout-dialog-ctx-${Date.now()}-${Math.random().toString(36).slice(2)}`;
2370
2388
  //#endregion
2371
2389
  //#region ---- View Accessors ----
2372
2390
  // Access the internal layout renderer to reach the widgets container injector
@@ -2397,16 +2415,42 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2397
2415
  //#region ---- Lifecycle ----
2398
2416
  ngOnInit() {
2399
2417
  this.context.set(this.config?.context || {});
2418
+ void this.invokeLayoutContextChangedHooks();
2400
2419
  }
2401
2420
  #eff;
2402
2421
  //#endregion
2403
2422
  handleContextChanged(event) {
2404
2423
  this.context.set(event);
2405
2424
  this.aggregateAndEvaluateActions();
2425
+ void this.invokeLayoutContextChangedHooks();
2406
2426
  }
2407
2427
  handleContextInitiated(event) {
2408
2428
  this.context.set(event);
2409
2429
  this.aggregateAndEvaluateActions();
2430
+ void this.invokeLayoutContextChangedHooks();
2431
+ }
2432
+ async invokeLayoutContextChangedHooks() {
2433
+ const meta = this.config?.metadata;
2434
+ if (!this.hookService) {
2435
+ return;
2436
+ }
2437
+ const payload = {
2438
+ sessionKey: this.contextChangedHooksSessionKey,
2439
+ getContext: () => (this.context() ?? {}),
2440
+ metadata: meta,
2441
+ patchContext: (partial) => {
2442
+ const merged = merge({}, this.context(), partial);
2443
+ this.context.set(merged);
2444
+ this.layoutRenderer()?.updateContext(merged);
2445
+ },
2446
+ setLoading: (loading) => this.isDialogLoading.set(loading),
2447
+ };
2448
+ try {
2449
+ await this.hookService.runAsync(AXP_LAYOUT_BUILDER_DIALOG_CONTEXT_CHANGED_HOOK_KEY, payload);
2450
+ }
2451
+ catch {
2452
+ // Hook providers are best-effort; avoid breaking the dialog lifecycle.
2453
+ }
2410
2454
  }
2411
2455
  footerPrefixActions() {
2412
2456
  return this.footerPrefix();
@@ -2428,6 +2472,7 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2428
2472
  return;
2429
2473
  }
2430
2474
  }
2475
+ //TODO: matin, why we need this? maybe we can remove it?
2431
2476
  if (cmd?.startsWith('widget:')) {
2432
2477
  const parsed = this.parseWidgetCommand(cmd);
2433
2478
  if (parsed.widgetName && parsed.action) {
@@ -2436,6 +2481,25 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2436
2481
  return;
2437
2482
  }
2438
2483
  }
2484
+ if (cmd && this.commandService.exists(cmd)) {
2485
+ const dialogRef = this.createDialogRef(cmd);
2486
+ const integration = (this.config.metadata ?? {});
2487
+ try {
2488
+ const cmdResult = await this.commandService.execute(cmd, { dialogRef, integration });
2489
+ if (!cmdResult?.success) {
2490
+ return;
2491
+ }
2492
+ if (this.shouldKeepDialogOpenAfterCommandResult(cmdResult)) {
2493
+ return;
2494
+ }
2495
+ this.callBack(cmdResult);
2496
+ await this.closeWithOptionalSkipValidate(cmdResult);
2497
+ }
2498
+ catch (error) {
2499
+ console.error('Error executing action', cmd, error);
2500
+ }
2501
+ return;
2502
+ }
2439
2503
  const context = this.context();
2440
2504
  const onAction = this.config?.onAction;
2441
2505
  if (onAction) {
@@ -2443,7 +2507,7 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2443
2507
  try {
2444
2508
  this.isDialogLoading.set(true);
2445
2509
  const result = await Promise.resolve(onAction(dialogRef));
2446
- if (result && typeof result === 'object' && result.keepDialogOpen) {
2510
+ if (this.shouldKeepDialogOpenAfterCommandResult(result)) {
2447
2511
  return;
2448
2512
  }
2449
2513
  this.callBack(result);
@@ -2481,8 +2545,25 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2481
2545
  if (cmd.startsWith('widget:')) {
2482
2546
  return false;
2483
2547
  }
2548
+ if (this.commandService.exists(cmd)) {
2549
+ return false;
2550
+ }
2484
2551
  return true;
2485
2552
  }
2553
+ /** True when a footer handler or command result asks to leave the dialog open (`keepDialogOpen` on the result or `result.data`). */
2554
+ shouldKeepDialogOpenAfterCommandResult(result) {
2555
+ if (!result || typeof result !== 'object') {
2556
+ return false;
2557
+ }
2558
+ const top = result;
2559
+ if (top.keepDialogOpen === true) {
2560
+ return true;
2561
+ }
2562
+ if (top.data != null && typeof top.data === 'object' && 'keepDialogOpen' in top.data) {
2563
+ return top.data.keepDialogOpen === true;
2564
+ }
2565
+ return false;
2566
+ }
2486
2567
  createDialogRef(actionCmd) {
2487
2568
  return {
2488
2569
  close: (res) => {
@@ -2672,9 +2753,9 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2672
2753
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPDialogRendererComponent, isStandalone: true, selector: "axp-dialog-renderer", outputs: { result: "result" }, providers: [AXPContextStore], viewQueries: [{ propertyName: "layoutRenderer", first: true, predicate: AXPLayoutRendererComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
2673
2754
  <axp-component-slot name="dialog-header" [context]="context()"></axp-component-slot>
2674
2755
  <div class="p-4">
2675
- @if (config.message) {
2756
+ <!-- @if (config.message) {
2676
2757
  <p class="mb-4 leading-relaxed">{{ config.message | translate | async }}</p>
2677
- }
2758
+ } -->
2678
2759
  <axp-layout-renderer
2679
2760
  [layout]="config.definition"
2680
2761
  [context]="context()"
@@ -2698,8 +2779,13 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2698
2779
  [color]="action.color"
2699
2780
  (onClick)="executeAction(action)"
2700
2781
  >
2782
+ @if (isFormLoading()) {
2783
+ <ax-loading></ax-loading>
2784
+ }
2701
2785
  <ax-prefix>
2702
- <i class="{{ action.icon }}"></i>
2786
+ @if (action.icon) {
2787
+ <ax-icon [icon]="action.icon"></ax-icon>
2788
+ }
2703
2789
  </ax-prefix>
2704
2790
  </ax-button>
2705
2791
  }
@@ -2718,7 +2804,7 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2718
2804
  }
2719
2805
  @if (action.icon) {
2720
2806
  <ax-prefix>
2721
- <ax-icon icon="{{ action.icon }}"></ax-icon>
2807
+ <ax-icon [icon]="action.icon"></ax-icon>
2722
2808
  </ax-prefix>
2723
2809
  }
2724
2810
  </ax-button>
@@ -2748,9 +2834,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
2748
2834
  template: `
2749
2835
  <axp-component-slot name="dialog-header" [context]="context()"></axp-component-slot>
2750
2836
  <div class="p-4">
2751
- @if (config.message) {
2837
+ <!-- @if (config.message) {
2752
2838
  <p class="mb-4 leading-relaxed">{{ config.message | translate | async }}</p>
2753
- }
2839
+ } -->
2754
2840
  <axp-layout-renderer
2755
2841
  [layout]="config.definition"
2756
2842
  [context]="context()"
@@ -2774,8 +2860,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
2774
2860
  [color]="action.color"
2775
2861
  (onClick)="executeAction(action)"
2776
2862
  >
2863
+ @if (isFormLoading()) {
2864
+ <ax-loading></ax-loading>
2865
+ }
2777
2866
  <ax-prefix>
2778
- <i class="{{ action.icon }}"></i>
2867
+ @if (action.icon) {
2868
+ <ax-icon [icon]="action.icon"></ax-icon>
2869
+ }
2779
2870
  </ax-prefix>
2780
2871
  </ax-button>
2781
2872
  }
@@ -2794,7 +2885,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
2794
2885
  }
2795
2886
  @if (action.icon) {
2796
2887
  <ax-prefix>
2797
- <ax-icon icon="{{ action.icon }}"></ax-icon>
2888
+ <ax-icon [icon]="action.icon"></ax-icon>
2798
2889
  </ax-prefix>
2799
2890
  }
2800
2891
  </ax-button>
@@ -2999,5 +3090,5 @@ var previewWidgetField_command = /*#__PURE__*/Object.freeze({
2999
3090
  * Generated bundle index. Do not edit.
3000
3091
  */
3001
3092
 
3002
- export { AXPDialogRendererComponent, AXPLayoutBuilderService, AXPLayoutConversionService, AXPLayoutRendererComponent, AXPPreviewWidgetFieldCommand, AXP_LAYOUT_BUILDER_DIALOG_BEFORE_OPEN_HOOK_KEY, AXP_LAYOUT_BUILDER_DIALOG_CONFIG_HOOK_KEY, AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY, LayoutBuilderModule };
3093
+ export { AXPDialogRendererComponent, AXPLayoutBuilderService, AXPLayoutConversionService, AXPLayoutRendererComponent, AXPPreviewWidgetFieldCommand, AXP_LAYOUT_BUILDER_DIALOG_BEFORE_OPEN_HOOK_KEY, AXP_LAYOUT_BUILDER_DIALOG_CONFIG_HOOK_KEY, AXP_LAYOUT_BUILDER_DIALOG_CONTEXT_CHANGED_HOOK_KEY, AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY, LayoutBuilderModule };
3003
3094
  //# sourceMappingURL=acorex-platform-layout-builder.mjs.map