@acorex/platform 20.2.3 → 20.2.4-next.1

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 (75) hide show
  1. package/common/index.d.ts +91 -3
  2. package/core/index.d.ts +65 -58
  3. package/fesm2022/acorex-platform-common.mjs +16 -8
  4. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-core.mjs +110 -158
  6. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-layout-builder.mjs +109 -55
  8. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-layout-components.mjs +1086 -35
  10. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-layout-designer.mjs +15 -122
  12. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  13. package/fesm2022/acorex-platform-layout-entity.mjs +2518 -1006
  14. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  15. package/fesm2022/acorex-platform-layout-views.mjs +243 -65
  16. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  17. package/fesm2022/{acorex-platform-themes-default-entity-master-create-view.component-hHXxHlFG.mjs → acorex-platform-themes-default-entity-master-create-view.component-I7Eq8Nti.mjs} +3 -3
  18. package/fesm2022/{acorex-platform-themes-default-entity-master-create-view.component-hHXxHlFG.mjs.map → acorex-platform-themes-default-entity-master-create-view.component-I7Eq8Nti.mjs.map} +1 -1
  19. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DXGLsVis.mjs +706 -0
  20. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DXGLsVis.mjs.map +1 -0
  21. package/fesm2022/{acorex-platform-themes-default-entity-master-modify-view.component-DC3MrDtI.mjs → acorex-platform-themes-default-entity-master-modify-view.component-16sdMBvH.mjs} +3 -10
  22. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-16sdMBvH.mjs.map +1 -0
  23. package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-Bb90PeHq.mjs → acorex-platform-themes-default-entity-master-single-view.component-CVaJzWb2.mjs} +25 -17
  24. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-CVaJzWb2.mjs.map +1 -0
  25. package/fesm2022/acorex-platform-themes-default.mjs +65 -495
  26. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  27. package/fesm2022/{acorex-platform-themes-shared-color-chooser-column.component-DjKLg513.mjs → acorex-platform-themes-shared-theme-color-chooser-column.component-DjKLg513.mjs} +1 -1
  28. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-DjKLg513.mjs.map +1 -0
  29. package/fesm2022/{acorex-platform-themes-shared-color-chooser-view.component-DE0wO98F.mjs → acorex-platform-themes-shared-theme-color-chooser-view.component-DE0wO98F.mjs} +1 -1
  30. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-DE0wO98F.mjs.map +1 -0
  31. package/fesm2022/acorex-platform-themes-shared.mjs +10 -12
  32. package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
  33. package/fesm2022/{acorex-platform-widgets-checkbox-widget-designer.component-BI18uzNZ.mjs → acorex-platform-widgets-checkbox-widget-designer.component-Cv7dEMCm.mjs} +2 -2
  34. package/fesm2022/acorex-platform-widgets-checkbox-widget-designer.component-Cv7dEMCm.mjs.map +1 -0
  35. package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-edit.component-B3SJUnGQ.mjs +50 -0
  36. package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-edit.component-B3SJUnGQ.mjs.map +1 -0
  37. package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-view.component-BLR0JkRt.mjs +42 -0
  38. package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-view.component-BLR0JkRt.mjs.map +1 -0
  39. package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-edit.component-hzR2FgOm.mjs +55 -0
  40. package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-edit.component-hzR2FgOm.mjs.map +1 -0
  41. package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-view.component-IDm6Clua.mjs +50 -0
  42. package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-view.component-IDm6Clua.mjs.map +1 -0
  43. package/fesm2022/acorex-platform-widgets-extra-properties-widget-edit.component-BRO9tYDa.mjs +48 -0
  44. package/fesm2022/acorex-platform-widgets-extra-properties-widget-edit.component-BRO9tYDa.mjs.map +1 -0
  45. package/fesm2022/acorex-platform-widgets-extra-properties-widget-view.component-CkpLimyW.mjs +42 -0
  46. package/fesm2022/acorex-platform-widgets-extra-properties-widget-view.component-CkpLimyW.mjs.map +1 -0
  47. package/fesm2022/{acorex-platform-widgets-file-list-popup.component-DFbPO0ud.mjs → acorex-platform-widgets-file-list-popup.component-B601gPsW.mjs} +66 -3
  48. package/fesm2022/acorex-platform-widgets-file-list-popup.component-B601gPsW.mjs.map +1 -0
  49. package/fesm2022/{acorex-platform-widgets-tabular-data-edit-popup.component-nLZYiPnF.mjs → acorex-platform-widgets-tabular-data-edit-popup.component-BDQIfr0g.mjs} +5 -5
  50. package/fesm2022/{acorex-platform-widgets-tabular-data-edit-popup.component-nLZYiPnF.mjs.map → acorex-platform-widgets-tabular-data-edit-popup.component-BDQIfr0g.mjs.map} +1 -1
  51. package/fesm2022/{acorex-platform-widgets-tabular-data-view-popup.component-D6kiasYM.mjs → acorex-platform-widgets-tabular-data-view-popup.component-CmPqtt0G.mjs} +3 -3
  52. package/fesm2022/{acorex-platform-widgets-tabular-data-view-popup.component-D6kiasYM.mjs.map → acorex-platform-widgets-tabular-data-view-popup.component-CmPqtt0G.mjs.map} +1 -1
  53. package/fesm2022/acorex-platform-widgets.mjs +1352 -218
  54. package/fesm2022/acorex-platform-widgets.mjs.map +1 -1
  55. package/fesm2022/acorex-platform-workflow.mjs +3 -0
  56. package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
  57. package/layout/builder/index.d.ts +19 -5
  58. package/layout/components/index.d.ts +214 -9
  59. package/layout/designer/index.d.ts +3 -46
  60. package/layout/entity/index.d.ts +203 -332
  61. package/layout/views/index.d.ts +83 -21
  62. package/package.json +5 -5
  63. package/themes/default/index.d.ts +5 -2
  64. package/widgets/index.d.ts +107 -11
  65. package/workflow/index.d.ts +3 -1
  66. package/fesm2022/acorex-platform-themes-default-create-entity-view.component-SY0oMDoH.mjs +0 -22
  67. package/fesm2022/acorex-platform-themes-default-create-entity-view.component-SY0oMDoH.mjs.map +0 -1
  68. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-hf4QOz_4.mjs +0 -665
  69. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-hf4QOz_4.mjs.map +0 -1
  70. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-DC3MrDtI.mjs.map +0 -1
  71. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Bb90PeHq.mjs.map +0 -1
  72. package/fesm2022/acorex-platform-themes-shared-color-chooser-column.component-DjKLg513.mjs.map +0 -1
  73. package/fesm2022/acorex-platform-themes-shared-color-chooser-view.component-DE0wO98F.mjs.map +0 -1
  74. package/fesm2022/acorex-platform-widgets-checkbox-widget-designer.component-BI18uzNZ.mjs.map +0 -1
  75. package/fesm2022/acorex-platform-widgets-file-list-popup.component-DFbPO0ud.mjs.map +0 -1
@@ -1,19 +1,20 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, Injectable, computed, signal, Injector, EnvironmentInjector, runInInjectionContext, makeEnvironmentProviders, effect, HostBinding, ChangeDetectionStrategy, Component, viewChild, ViewChild, NgModule } from '@angular/core';
2
+ import { InjectionToken, inject, Injectable, computed, signal, Injector, runInInjectionContext, EnvironmentInjector, viewChild, viewChildren, linkedSignal, effect, untracked, ChangeDetectionStrategy, Component, HostBinding, ViewChild, NgModule } from '@angular/core';
3
3
  import { castArray, get, cloneDeep, set, merge, isNil, isEmpty, sortBy } from 'lodash-es';
4
4
  import * as i1$2 from '@acorex/cdk/common';
5
5
  import { AXDataSource, AXCommonModule } from '@acorex/cdk/common';
6
6
  import { AXFormatService } from '@acorex/core/format';
7
- import { resolveActionLook, AXPFilterOperatorMiddlewareService, AXPEntityCommandScope, getEntityInfo, AXPSettingService, AXPRefreshEvent, AXPLockService, AXPCleanNestedFilters, AXPWorkflowNavigateAction, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER } from '@acorex/platform/common';
7
+ import { resolveActionLook, AXPFilterOperatorMiddlewareService, AXPEntityCommandScope, getEntityInfo, AXPSettingService, AXPRefreshEvent, AXPReloadEvent, AXPCleanNestedFilters, AXPWorkflowNavigateAction, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER } from '@acorex/platform/common';
8
8
  import * as i1$4 from '@acorex/platform/core';
9
- import { AXPExpressionEvaluatorService, AXPPlatformScope, extractValue, setSmart } from '@acorex/platform/core';
9
+ import { AXPExpressionEvaluatorService, AXPPlatformScope, AXPDistributedEventListenerService, getSmart, getChangedPaths, extractValue, setSmart } from '@acorex/platform/core';
10
10
  import * as i2$2 from '@acorex/platform/workflow';
11
11
  import { AXPWorkflowService, ofType, createWorkFlowEvent, AXPWorkflowAction, AXPWorkflowModule } from '@acorex/platform/workflow';
12
- import * as i6 from '@acorex/platform/layout/builder';
13
- import { AXPPageStatus, AXPWidgetRegistryService, AXPValueWidgetComponent, AXPLayoutBuilderModule, AXPColumnWidgetComponent, AXPWidgetsCatalog, AXPWidgetGroupEnum, AXP_WIDGETS_EDITOR_CATEGORY, AXPLayoutWidgetComponent } from '@acorex/platform/layout/builder';
12
+ import * as i2 from '@acorex/platform/layout/builder';
13
+ import { AXPPageStatus, AXPWidgetRegistryService, AXPWidgetsCatalog, AXPValueWidgetComponent, AXPWidgetContainerComponent, AXPWidgetRendererDirective, AXPLayoutBuilderModule, AXPWidgetGroupEnum, AXPLayoutWidgetComponent, AXPColumnWidgetComponent, AXP_WIDGETS_EDITOR_CATEGORY } from '@acorex/platform/layout/builder';
14
14
  import { AXPLayoutThemeService } from '@acorex/platform/themes/shared';
15
- import { AXPSessionService, AXPAuthGuard } from '@acorex/platform/auth';
16
15
  import { Subject, takeUntil } from 'rxjs';
16
+ import { AXPSessionService, AXPAuthGuard } from '@acorex/platform/auth';
17
+ import { AXPCommandService } from '@acorex/platform/runtime';
17
18
  import * as i8 from '@acorex/core/translation';
18
19
  import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
19
20
  import { AXDialogService } from '@acorex/components/dialog';
@@ -21,35 +22,38 @@ import { AXLoadingDialogService } from '@acorex/components/loading-dialog';
21
22
  import { AXPopupService } from '@acorex/components/popup';
22
23
  import { AXPlatform } from '@acorex/core/platform';
23
24
  import { RouterModule, ROUTES } from '@angular/router';
24
- import * as i1 from '@acorex/components/loading';
25
- import { AXLoadingModule } from '@acorex/components/loading';
26
- import * as i1$1 from '@acorex/components/badge';
27
- import { AXBadgeModule } from '@acorex/components/badge';
28
- import * as i2 from '@acorex/components/button';
25
+ import * as i3$1 from '@acorex/components/button';
29
26
  import { AXButtonModule } from '@acorex/components/button';
30
27
  import * as i3 from '@acorex/components/decorators';
31
28
  import { AXDecoratorModule } from '@acorex/components/decorators';
32
- import * as i5$1 from '@acorex/components/form';
33
- import { AXFormModule } from '@acorex/components/form';
34
- import * as i6$1 from '@acorex/components/tag-box';
35
- import { AXTagBoxComponent, AXTagBoxModule } from '@acorex/components/tag-box';
36
- import { AXValidationModule } from '@acorex/core/validation';
29
+ import * as i4 from '@acorex/components/dropdown';
30
+ import { AXDropdownModule } from '@acorex/components/dropdown';
37
31
  import * as i7 from '@angular/common';
38
32
  import { CommonModule } from '@angular/common';
33
+ import { AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_DISABLED_PROPERTY, AXP_ALLOW_CLEAR_PROPERTY, AXP_DATA_PROPERTY_GROUP, AXP_ALLOW_MULTIPLE_PROPERTY, AXPFileUploaderWidgetService } from '@acorex/platform/widgets';
39
34
  import * as i1$3 from '@angular/forms';
40
35
  import { FormsModule } from '@angular/forms';
41
- import * as i4 from '@acorex/components/data-table';
42
- import { AXDataTableModule } from '@acorex/components/data-table';
43
- import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
44
- import { AXBasePageComponent } from '@acorex/components/page';
36
+ import * as i1 from '@acorex/components/loading';
37
+ import { AXLoadingModule } from '@acorex/components/loading';
38
+ import * as i1$1 from '@acorex/components/badge';
39
+ import { AXBadgeModule } from '@acorex/components/badge';
40
+ import * as i5$1 from '@acorex/components/form';
41
+ import { AXFormModule } from '@acorex/components/form';
45
42
  import * as i5 from '@acorex/components/search-box';
46
43
  import { AXSearchBoxModule, AXSearchBoxComponent } from '@acorex/components/search-box';
47
44
  import * as i7$1 from '@acorex/components/select-box';
48
45
  import { AXSelectBoxModule } from '@acorex/components/select-box';
49
- import { AXP_DISABLED_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_DATA_PROPERTY_GROUP, AXP_ALLOW_MULTIPLE_PROPERTY, AXP_NAME_PROPERTY, AXPFileUploaderWidgetService } from '@acorex/platform/widgets';
46
+ import * as i6 from '@acorex/components/tag-box';
47
+ import { AXTagBoxComponent, AXTagBoxModule } from '@acorex/components/tag-box';
48
+ import { AXValidationModule } from '@acorex/core/validation';
49
+ import * as i4$1 from '@acorex/components/data-table';
50
+ import { AXDataTableModule } from '@acorex/components/data-table';
51
+ import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
52
+ import { AXBasePageComponent } from '@acorex/components/page';
50
53
  import * as i2$1 from '@acorex/components/text-box';
51
54
  import { AXTextBoxModule, AXTextBoxComponent } from '@acorex/components/text-box';
52
- import { AXPWidgetPropertyViewerComponent } from '@acorex/platform/layout/designer';
55
+ import { AXPWidgetPropertyViewerComponent } from '@acorex/platform/layout/components';
56
+ import { transform, isEqual } from 'lodash';
53
57
 
54
58
  const AXP_DATA_SEEDER_TOKEN = new InjectionToken('AXP_DATA_SEEDER_TOKEN');
55
59
  class AXPDataSeederService {
@@ -221,7 +225,8 @@ class AXPEntityDetailListViewModel {
221
225
  return !usedOverrideActions.has(actionKey);
222
226
  })
223
227
  .map((action) => new AXPEntityCommandTriggerViewModel(this.detailEntity(), action));
224
- return [...additionalActions, ...mergedActions].filter((a) => !a.hidden);
228
+ // Do not filter by hidden here; hidden/disabled may be expressions that must be evaluated dynamically
229
+ return [...additionalActions, ...mergedActions];
225
230
  }, ...(ngDevMode ? [{ debugName: "allActions" }] : []));
226
231
  this.selectedScopeActionsCount = computed(() => {
227
232
  return this.allActions().filter((a) => a.scope == AXPEntityCommandScope.Selected).length;
@@ -367,6 +372,43 @@ class AXPEntityDetailListViewModel {
367
372
  options,
368
373
  });
369
374
  }
375
+ //#region ---- Evaluated Actions (Primary/Secondary) ----
376
+ /**
377
+ * Evaluate hidden/disabled expressions for primary actions and return the visible list.
378
+ */
379
+ async getPrimaryActions() {
380
+ const scope = {};
381
+ const actions = await Promise.all(this.allActions()
382
+ .filter((a) => a.priority == 'primary' &&
383
+ ((a.scope == AXPEntityCommandScope.Selected && this.hasSelectedItems()) ||
384
+ (a.scope == AXPEntityCommandScope.TypeLevel && !this.hasSelectedItems())))
385
+ .map(async (a) => {
386
+ const isHidden = await this.evaluateExpressions(a.hidden);
387
+ if (isHidden)
388
+ return null;
389
+ const disabled = await this.evaluateExpressions(a.disabled);
390
+ return { ...a, disabled };
391
+ }));
392
+ return actions.filter(Boolean);
393
+ }
394
+ /**
395
+ * Evaluate hidden/disabled expressions for secondary actions and return the visible list.
396
+ */
397
+ async getSecondaryActions() {
398
+ const scope = {};
399
+ const actions = await Promise.all(this.allActions()
400
+ .filter((a) => a.priority == 'secondary' &&
401
+ ((a.scope == AXPEntityCommandScope.Selected && this.hasSelectedItems()) ||
402
+ (a.scope == AXPEntityCommandScope.TypeLevel && !this.hasSelectedItems())))
403
+ .map(async (a) => {
404
+ const isHidden = await this.evaluateExpressions(a.hidden);
405
+ if (isHidden)
406
+ return null;
407
+ const disabled = await this.evaluateExpressions(a.disabled);
408
+ return { ...a, disabled };
409
+ }));
410
+ return actions.filter(Boolean);
411
+ }
370
412
  }
371
413
 
372
414
  function createModifierContext(entity) {
@@ -523,6 +565,15 @@ function createModifierContext(entity) {
523
565
  entity.interfaces.master = updater(entity.interfaces.master);
524
566
  return ctx;
525
567
  },
568
+ list: {
569
+ get: () => entity.interfaces?.master?.list,
570
+ update: (updater) => {
571
+ entity.interfaces ??= {};
572
+ entity.interfaces.master ??= {};
573
+ entity.interfaces.master.list = updater(entity.interfaces.master.list);
574
+ return ctx;
575
+ },
576
+ },
526
577
  create: {
527
578
  get: () => entity.interfaces?.master?.create,
528
579
  update: (updater) => {
@@ -576,25 +627,98 @@ function createModifierContext(entity) {
576
627
 
577
628
  const AXP_ENTITY_MODIFIER = new InjectionToken('AXP_ENTITY_MODIFIER');
578
629
 
630
+ function ensureListActions(ctx) {
631
+ ctx.interfaces.update((i) => {
632
+ const next = i ?? {};
633
+ next.master = next.master ?? {};
634
+ next.master.list = next.master.list ?? { actions: [], views: [] };
635
+ next.master.list.actions = next.master.list.actions ?? [];
636
+ return next;
637
+ });
638
+ }
639
+ function actionExists(actions, commandName, name) {
640
+ if (!actions)
641
+ return false;
642
+ return actions.some((a) => {
643
+ const cmd = typeof a.command === 'object' ? a.command?.name : a.command;
644
+ if (name && a.name) {
645
+ return a.name === name;
646
+ }
647
+ return cmd === commandName;
648
+ });
649
+ }
650
+
651
+ const AXP_ENTITY_ACTION_PLUGIN = new InjectionToken('AXP_ENTITY_ACTION_PLUGIN');
652
+
579
653
  class AXPEntityMiddleware {
654
+ //#endregion
655
+ //#region ---- Constructor ----
580
656
  constructor() {
581
- this.modifiers = new Map();
657
+ //#region ---- Fields ----
658
+ this.exactModifiers = new Map();
659
+ this.patternModifiers = [];
582
660
  this.providedModifiers = inject(AXP_ENTITY_MODIFIER, { optional: true }) || [];
661
+ this.providedActionPlugins = inject(AXP_ENTITY_ACTION_PLUGIN, { optional: true }) || [];
662
+ this.injector = inject(Injector);
583
663
  for (const { entityName, modifier } of this.providedModifiers) {
584
664
  this.register(entityName, modifier);
585
665
  }
586
666
  }
667
+ //#endregion
668
+ //#region ---- Registration Methods ----
587
669
  register(entityName, modifier) {
588
- this.modifiers.set(entityName, modifier);
670
+ if (entityName instanceof RegExp) {
671
+ this.patternModifiers.push({ pattern: this.normalizeRegExp(entityName), modifier });
672
+ return;
673
+ }
674
+ if (entityName.includes('*')) {
675
+ const pattern = this.wildcardToRegExp(entityName);
676
+ this.patternModifiers.push({ pattern, modifier });
677
+ return;
678
+ }
679
+ this.exactModifiers.set(entityName, modifier);
589
680
  }
590
- process(entity) {
591
- const modifier = this.modifiers.get(entity.name);
592
- if (!modifier)
593
- return entity;
681
+ //#endregion
682
+ //#region ---- Processing ----
683
+ async process(entity) {
684
+ // First, expand action plugins if entity.plugins exists
594
685
  const context = createModifierContext(entity);
686
+ const plugins = entity.plugins;
687
+ if (plugins && plugins.length) {
688
+ const sorted = [...this.providedActionPlugins].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
689
+ for (const p of plugins) {
690
+ const contrib = sorted.find((x) => x.name === p.name);
691
+ if (contrib) {
692
+ try {
693
+ await runInInjectionContext(this.injector, () => contrib.apply(context, p.options));
694
+ }
695
+ catch (err) {
696
+ console.error('[AXPEntityMiddleware] action plugin failed:', p.name, err);
697
+ }
698
+ }
699
+ }
700
+ }
701
+ // Then apply entity-specific modifiers
702
+ // Exact match first
703
+ const exact = this.exactModifiers.get(entity.name);
704
+ const modifier = exact ?? this.patternModifiers.find((x) => x.pattern.test(entity.name))?.modifier;
705
+ if (!modifier) {
706
+ return context.toEntity();
707
+ }
595
708
  modifier(context);
596
709
  return context.toEntity();
597
710
  }
711
+ //#endregion
712
+ //#region ---- Helpers ----
713
+ wildcardToRegExp(pattern) {
714
+ const escaped = pattern.replace(/[.+?^${}()|\[\]\\]/g, '\\$&');
715
+ const regexStr = `^${escaped.replace(/\*/g, '.*')}$`;
716
+ return new RegExp(regexStr);
717
+ }
718
+ normalizeRegExp(rx) {
719
+ const flags = rx.flags.replace('g', '');
720
+ return new RegExp(rx.source, flags);
721
+ }
598
722
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityMiddleware, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
599
723
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityMiddleware, providedIn: 'root' }); }
600
724
  }
@@ -608,11 +732,15 @@ class AXPEntityDefinitionRegistryService {
608
732
  this.providers = inject(AXP_ENTITY_DEFINITION_LOADER);
609
733
  this.resolver = inject(AXPEntityResolver);
610
734
  this.middleware = inject(AXPEntityMiddleware);
735
+ this.onChanged = new Subject();
611
736
  // Stores AXPEntityConfig objects, keyed by a combination of module and entity name.
612
737
  this.entities = new Map();
613
738
  // Entity resolver service for dynamically loading entity configurations.
614
739
  this.entityResolver = inject(AXPEntityResolver); // Assuming AXPEntityLoader is the correct type
615
740
  }
741
+ get onChanged$() {
742
+ return this.onChanged.asObservable();
743
+ }
616
744
  async preload() {
617
745
  const providers = Array.isArray(this.providers)
618
746
  ? this.providers
@@ -633,14 +761,14 @@ class AXPEntityDefinitionRegistryService {
633
761
  .catch(err => {
634
762
  console.error(`[AXPEntityDefinitionRegistryService] Failed to load entity ${item.module}.${item.entity}:`, err);
635
763
  return null;
636
- }), 3000, `${item.module}.${item.entity}`));
764
+ }), 10000, `${item.module}.${item.entity}`));
637
765
  });
638
766
  });
639
767
  const results = await Promise.allSettled(promises);
640
768
  const loadedEntities = [];
641
- results.forEach((result, idx) => {
769
+ results.forEach(async (result, idx) => {
642
770
  if (result.status === 'fulfilled' && result.value != null) {
643
- this.register(this.middleware.process(result.value));
771
+ this.register(await this.middleware.process(result.value));
644
772
  loadedEntities.push(result.value);
645
773
  }
646
774
  else if (result.status === 'rejected') {
@@ -649,6 +777,43 @@ class AXPEntityDefinitionRegistryService {
649
777
  });
650
778
  //console.log('[AXPEntityDefinitionRegistryService] Loaded entities:', loadedEntities);
651
779
  }
780
+ async refresh(arg1, arg2) {
781
+ // No parameters: refresh all currently registered entities
782
+ if (typeof arg1 === 'undefined' && typeof arg2 === 'undefined') {
783
+ const keys = Array.from(this.entities.keys());
784
+ for (const key of keys) {
785
+ const [m, e] = key.split('.');
786
+ if (m && e) {
787
+ await this.refreshOne(m, e);
788
+ }
789
+ }
790
+ return;
791
+ }
792
+ // One parameter: treat as fully-qualified name
793
+ if (typeof arg1 === 'string' && typeof arg2 === 'undefined') {
794
+ const [moduleName, entityName] = arg1.split('.');
795
+ if (!moduleName || !entityName) {
796
+ throw new Error(`Invalid entity full name: ${arg1}`);
797
+ }
798
+ await this.refreshOne(moduleName, entityName);
799
+ return;
800
+ }
801
+ // Two parameters: module + entity
802
+ if (typeof arg1 === 'string' && typeof arg2 === 'string') {
803
+ await this.refreshOne(arg1, arg2);
804
+ return;
805
+ }
806
+ }
807
+ /** Executes the actual refresh for a single entity */
808
+ async refreshOne(moduleName, entityName) {
809
+ const config = await this.entityResolver.get(moduleName, entityName);
810
+ if (!config) {
811
+ throw new Error(`Invalid entity name: ${moduleName}.${entityName}`);
812
+ }
813
+ const processedConfig = await this.middleware.process(config);
814
+ this.register(processedConfig);
815
+ }
816
+ //#endregion
652
817
  /**
653
818
  * Registers a new entity configuration. Entities are identified uniquely by a combination
654
819
  * of their module and name.
@@ -658,6 +823,7 @@ class AXPEntityDefinitionRegistryService {
658
823
  register(config) {
659
824
  const key = this.createEntityKey(config.module, config.name);
660
825
  this.entities.set(key, config);
826
+ this.onChanged.next({ name: key });
661
827
  }
662
828
  /**
663
829
  * Returns an array of all registered entity configurations.
@@ -684,7 +850,7 @@ class AXPEntityDefinitionRegistryService {
684
850
  try {
685
851
  config = await this.entityResolver.get(moduleName, entityName);
686
852
  if (config) {
687
- const processedConfig = this.middleware.process(config);
853
+ const processedConfig = await this.middleware.process(config);
688
854
  this.register(processedConfig);
689
855
  return processedConfig;
690
856
  }
@@ -778,6 +944,7 @@ class AXPEntityCreateViewElementViewModel {
778
944
  children: widget.children,
779
945
  formula: widget.formula,
780
946
  triggers: widget.triggers,
947
+ defaultValue: schema.defaultValue,
781
948
  valueTransforms: widget.valueTransforms,
782
949
  options: merge(schema.interface?.options, {
783
950
  validations: this.property.validations?.map((c) => ({ rule: c.rule, message: c.message, options: c.options })),
@@ -820,22 +987,6 @@ class AXPEntityMasterCreateViewModel {
820
987
  },
821
988
  },
822
989
  };
823
- const processDefault = async (value) => {
824
- if (typeof value == 'function') {
825
- return value();
826
- }
827
- else if (typeof value == 'string' && value.startsWith('{{')) {
828
- return await this.expressionEvaluator.evaluate(value, scope);
829
- }
830
- return value;
831
- };
832
- this.config.properties
833
- .filter((c) => !isNil(c.schema.defaultValue))
834
- .forEach(async (p) => {
835
- const value = await processDefault(p.schema.defaultValue);
836
- set(initialData, p.name, value);
837
- });
838
- //
839
990
  this.context.set(initialData);
840
991
  this.options.set(commandOptions);
841
992
  //
@@ -918,7 +1069,7 @@ class AXPEntityMasterListViewModel {
918
1069
  this.applyViewColumns();
919
1070
  this.applyViewFilters();
920
1071
  // this.applyFilterAndSort();
921
- this.applySettings();
1072
+ await this.applySettings();
922
1073
  }
923
1074
  }
924
1075
  constructor(injector, config) {
@@ -932,9 +1083,12 @@ class AXPEntityMasterListViewModel {
932
1083
  this.settings = this.injector.get(AXPSettingService);
933
1084
  this.widgetResolver = this.injector.get(AXPWidgetRegistryService);
934
1085
  this.expressionEvaluator = this.injector.get(AXPExpressionEvaluatorService);
1086
+ this.commandService = this.injector.get(AXPCommandService);
935
1087
  this.filterOperatorMiddleware = this.injector.get(AXPFilterOperatorMiddlewareService);
936
1088
  this.settingEntityKey = `${this.config.module}:${this.config.name}`;
937
1089
  this.destroyed = new Subject();
1090
+ this.lastAppliedSortKey = null;
1091
+ this.lastAppliedFilterKey = null;
938
1092
  this.events$ = new Subject();
939
1093
  //****************** Views ******************//
940
1094
  this.views = computed(() => {
@@ -1048,7 +1202,7 @@ class AXPEntityMasterListViewModel {
1048
1202
  return await this.expressionEvaluator.evaluate(options, scope);
1049
1203
  };
1050
1204
  this.workflow.events$
1051
- .pipe(ofType(AXPRefreshEvent))
1205
+ .pipe(ofType(AXPRefreshEvent, AXPReloadEvent))
1052
1206
  .pipe(takeUntil(this.destroyed))
1053
1207
  .subscribe((event) => {
1054
1208
  if (event.payload.entity == getEntityInfo(this.entityDef).source) {
@@ -1062,19 +1216,37 @@ class AXPEntityMasterListViewModel {
1062
1216
  this.saveSettings('view');
1063
1217
  const listViewSetting = await this.settings.get(this.settingEntityKey);
1064
1218
  if (listViewSetting) {
1065
- const columns = listViewSetting.list.views[this.view().name].columns;
1066
- const pageSize = listViewSetting.list.views[this.view().name].pageSize;
1067
- const columnVisibilityMap = new Map(columns.map((col) => [col.name, col.visible]));
1068
- const columnWidthsMap = new Map(columns.map((col) => [col.name, col.width]));
1069
- // if (pageSize) {
1070
- // this.dataSource.setPageSize(pageSize);
1071
- // }
1072
- this.columns.update((prev) => prev
1073
- .map((c) => {
1074
- return { ...c, width: columnWidthsMap.get(c.name), visible: columnVisibilityMap.get(c.name) ?? c.visible };
1075
- }) // Update visibility
1076
- .sort((a, b) => columns.findIndex((col) => col.name === a.name) -
1077
- columns.findIndex((col) => col.name === b.name)));
1219
+ const columns = listViewSetting.list?.views?.[this.view().name]?.columns;
1220
+ const pageSize = listViewSetting.list?.views?.[this.view().name]?.pageSize;
1221
+ const sorts = listViewSetting.list?.views?.[this.view().name]?.sorts;
1222
+ const filters = listViewSetting.list?.views?.[this.view().name]?.filters;
1223
+ let columnVisibilityMap;
1224
+ let columnWidthsMap;
1225
+ if (columns) {
1226
+ columnVisibilityMap = new Map(columns.map((col) => [col.name, col.visible]));
1227
+ columnWidthsMap = new Map(columns.map((col) => [col.name, col.width]));
1228
+ }
1229
+ // Do not set pageSize here to avoid triggering an extra load
1230
+ if (columns && columnVisibilityMap && columnWidthsMap) {
1231
+ this.columns.update((prev) => prev
1232
+ .map((c) => {
1233
+ return {
1234
+ ...c,
1235
+ width: columnWidthsMap.get(c.name),
1236
+ visible: columnVisibilityMap.get(c.name) ?? c.visible,
1237
+ };
1238
+ }) // Update visibility
1239
+ .sort((a, b) => columns.findIndex((col) => col.name === a.name) -
1240
+ columns.findIndex((col) => col.name === b.name)));
1241
+ }
1242
+ if (Array.isArray(sorts)) {
1243
+ // sorts are AXPSortQuery[]; ensure we map by name
1244
+ const sortsMap = new Map(sorts.map((s) => [s.name, s.dir]));
1245
+ this.sortedFields.update((prev) => prev.map((sf) => ({ ...sf, dir: sortsMap.get(sf.name) || sf.dir })));
1246
+ }
1247
+ if (Array.isArray(filters)) {
1248
+ this.filterQueries.set(filters);
1249
+ }
1078
1250
  }
1079
1251
  }
1080
1252
  async saveSettings(changesType, data) {
@@ -1128,6 +1300,36 @@ class AXPEntityMasterListViewModel {
1128
1300
  },
1129
1301
  }));
1130
1302
  break;
1303
+ case 'filters':
1304
+ updateSettings((prev) => ({
1305
+ ...prev,
1306
+ list: {
1307
+ ...prev?.list,
1308
+ views: {
1309
+ ...prev?.list?.views,
1310
+ [this.view().name]: {
1311
+ ...prev?.list?.views?.[this.view().name],
1312
+ filters: data,
1313
+ },
1314
+ },
1315
+ },
1316
+ }));
1317
+ break;
1318
+ case 'sorts':
1319
+ updateSettings((prev) => ({
1320
+ ...prev,
1321
+ list: {
1322
+ ...prev?.list,
1323
+ views: {
1324
+ ...prev?.list?.views,
1325
+ [this.view().name]: {
1326
+ ...prev?.list?.views?.[this.view().name],
1327
+ sorts: data,
1328
+ },
1329
+ },
1330
+ },
1331
+ }));
1332
+ break;
1131
1333
  default:
1132
1334
  break;
1133
1335
  }
@@ -1220,21 +1422,30 @@ class AXPEntityMasterListViewModel {
1220
1422
  operator: f.operator,
1221
1423
  value: f.value,
1222
1424
  }));
1223
- this.filterQueries.update((prev) => ({ ...prev, filters: viewFilters }));
1425
+ this.filterQueries.set(viewFilters);
1224
1426
  }
1225
1427
  resetFilters() {
1226
1428
  this.applyViewFilters();
1227
1429
  }
1228
1430
  async applyFilterAndSort() {
1229
- this.dataSource.clearFilter();
1230
- this.dataSource.sort(...this.sortedFields()
1431
+ const sorts = this.sortedFields()
1231
1432
  .filter((sf) => sf.dir)
1232
- .map((s) => ({ dir: s.dir, field: s.name })));
1433
+ .map((s) => ({ name: s.name, dir: s.dir }));
1434
+ const filters = this.filterQueries();
1435
+ const sortKey = JSON.stringify(sorts);
1436
+ const filterKey = JSON.stringify(filters);
1437
+ if (sortKey === this.lastAppliedSortKey && filterKey === this.lastAppliedFilterKey) {
1438
+ return; // No effective change; avoid redundant refresh
1439
+ }
1440
+ this.lastAppliedSortKey = sortKey;
1441
+ this.lastAppliedFilterKey = filterKey;
1442
+ this.dataSource.clearFilter();
1443
+ this.dataSource.sort(...sorts.map((s) => ({ dir: s.dir, field: s.name })));
1233
1444
  this.dataSource.filter(this.filterOperatorMiddleware.transformFilter({
1234
1445
  field: null,
1235
1446
  logic: 'and',
1236
1447
  operator: null,
1237
- filters: this.filterQueries(),
1448
+ filters: filters,
1238
1449
  }));
1239
1450
  this.dataSource.refresh();
1240
1451
  }
@@ -1282,19 +1493,24 @@ class AXPEntityMasterListViewModel {
1282
1493
  });
1283
1494
  const command = commandName.split('&')[0];
1284
1495
  const options = await this.evaluateExpressions(action?.options, data);
1285
- await this.workflow.execute(command, {
1286
- entity: getEntityInfo(this.entityDef).source,
1287
- entityInfo: {
1288
- name: this.entityDef.name,
1289
- module: this.entityDef.module,
1290
- title: this.entityDef.title,
1291
- parentKey: this.entityDef.parentKey,
1292
- source: this.entityDef.source,
1293
- },
1294
- data: action?.scope == AXPEntityCommandScope.Selected ? this.selectedItems() : data,
1295
- options: options,
1296
- metadata: action?.metadata,
1297
- });
1496
+ if (this.workflow.exists(command)) {
1497
+ await this.workflow.execute(command, {
1498
+ entity: getEntityInfo(this.entityDef).source,
1499
+ entityInfo: {
1500
+ name: this.entityDef.name,
1501
+ module: this.entityDef.module,
1502
+ title: this.entityDef.title,
1503
+ parentKey: this.entityDef.parentKey,
1504
+ source: this.entityDef.source,
1505
+ },
1506
+ data: action?.scope == AXPEntityCommandScope.Selected ? this.selectedItems() : data,
1507
+ options: options,
1508
+ metadata: action?.metadata,
1509
+ });
1510
+ }
1511
+ else {
1512
+ this.commandService.execute(command, options);
1513
+ }
1298
1514
  }
1299
1515
  async execute(command) {
1300
1516
  switch (command?.name) {
@@ -1596,7 +1812,6 @@ class AXPEntityMasterUpdateViewModel {
1596
1812
  this.props = props;
1597
1813
  this.entityDef = cloneDeep(this.config);
1598
1814
  this.workflow = this.injector.get(AXPWorkflowService);
1599
- this.lockService = this.injector.get(AXPLockService);
1600
1815
  this.sessionService = this.injector.get(AXPSessionService);
1601
1816
  this.isInProgress = signal(false, ...(ngDevMode ? [{ debugName: "isInProgress" }] : []));
1602
1817
  this.context = signal(cloneDeep(this.entityData), ...(ngDevMode ? [{ debugName: "context" }] : []));
@@ -1606,19 +1821,6 @@ class AXPEntityMasterUpdateViewModel {
1606
1821
  return new AXPEntityMasterUpdateElementViewModel(this.entityDef, e);
1607
1822
  });
1608
1823
  }, ...(ngDevMode ? [{ debugName: "elements" }] : []));
1609
- // Lock the record on creation
1610
- if (this.entityId) {
1611
- this.lockService.lock({
1612
- refId: this.entityId,
1613
- refType: `${this.moduleName}.${this.entityName}`,
1614
- type: 'user',
1615
- date: new Date().toISOString(),
1616
- lockedBy: {
1617
- id: this.sessionService.user?.id ?? 'system',
1618
- type: 'oidc.users',
1619
- },
1620
- });
1621
- }
1622
1824
  }
1623
1825
  async save() {
1624
1826
  this.isInProgress.set(true);
@@ -1643,15 +1845,6 @@ class AXPEntityMasterUpdateViewModel {
1643
1845
  reset() {
1644
1846
  this.context.set(cloneDeep(this.entityData));
1645
1847
  }
1646
- async unlock() {
1647
- if (this.entityId) {
1648
- await this.lockService.unlock({
1649
- refId: this.entityId,
1650
- refType: `${this.moduleName}.${this.entityName}`,
1651
- type: 'user',
1652
- });
1653
- }
1654
- }
1655
1848
  }
1656
1849
  class AXPEntityMasterUpdateViewModelFactory {
1657
1850
  constructor() {
@@ -1856,10 +2049,14 @@ class AXPEntityMasterSingleViewModel {
1856
2049
  this.session = this.injector.get(AXPSessionService);
1857
2050
  this.formatService = this.injector.get(AXFormatService);
1858
2051
  this.workflow = this.injector.get(AXPWorkflowService);
2052
+ this.commandService = this.injector.get(AXPCommandService);
1859
2053
  this.destroyed = new Subject();
1860
2054
  this.translateService = this.injector.get(AXTranslationService);
1861
2055
  this.entityService = this.injector.get(AXPEntityService);
1862
2056
  this.expressionEvaluator = this.injector.get(AXPExpressionEvaluatorService);
2057
+ this.entityDefinitionRegistryService = this.injector.get(AXPEntityDefinitionRegistryService);
2058
+ this._updateTrigger = signal(1, ...(ngDevMode ? [{ debugName: "_updateTrigger" }] : []));
2059
+ this.updateTrigger = this._updateTrigger.asReadonly();
1863
2060
  this.context = signal(cloneDeep(this.entityData), ...(ngDevMode ? [{ debugName: "context" }] : []));
1864
2061
  this.actions = computed(() => {
1865
2062
  return (this.entityDef.interfaces?.master?.single?.actions?.map((tr) => new AXPEntityCommandTriggerViewModel(this.entityDef, tr)) ?? []);
@@ -1943,6 +2140,13 @@ class AXPEntityMasterSingleViewModel {
1943
2140
  this.context.set(event.payload.values);
1944
2141
  }
1945
2142
  });
2143
+ this.entityDefinitionRegistryService.onChanged$
2144
+ .pipe(takeUntil(this.destroyed))
2145
+ .subscribe((event) => {
2146
+ if (event.name == getEntityInfo(this.entityDef).source) {
2147
+ this._updateTrigger.set(this._updateTrigger() + 1);
2148
+ }
2149
+ });
1946
2150
  }
1947
2151
  navigateToUp() {
1948
2152
  this.workflow.execute('navigate', {
@@ -1952,7 +2156,7 @@ class AXPEntityMasterSingleViewModel {
1952
2156
  });
1953
2157
  }
1954
2158
  async executeCommand(commandName, data = null) {
1955
- //TODO: syntact for workflow
2159
+ //TODO: syntax for workflow
1956
2160
  const command = commandName.split('&')[0];
1957
2161
  switch (command) {
1958
2162
  case 'modify-entity-section': {
@@ -1968,11 +2172,17 @@ class AXPEntityMasterSingleViewModel {
1968
2172
  default: {
1969
2173
  const action = this.actions().find((c) => c.name == commandName);
1970
2174
  const options = await this.evaluateExpressions(action?.options, this.context());
1971
- this.workflow.execute(command, {
1972
- entity: getEntityInfo(this.entityDef).source,
1973
- data: this.context(),
1974
- options,
1975
- });
2175
+ //
2176
+ if (this.workflow.exists(command)) {
2177
+ this.workflow.execute(command, {
2178
+ entity: getEntityInfo(this.entityDef).source,
2179
+ data: this.context(),
2180
+ options,
2181
+ });
2182
+ }
2183
+ else {
2184
+ this.commandService.execute(command, data);
2185
+ }
1976
2186
  }
1977
2187
  }
1978
2188
  }
@@ -2030,6 +2240,9 @@ const AXPEntityDetailViewModelResolver = (route, state, service = inject(AXPEnti
2030
2240
  return service.create(moduleName, entityName, id);
2031
2241
  };
2032
2242
 
2243
+ const AXP_ENTITY_STORAGE_BACKEND = new InjectionToken('AXP_ENTITY_STORAGE_BACKEND');
2244
+ const AXP_ENTITY_STORAGE_MIDDLEWARE = new InjectionToken('AXP_ENTITY_STORAGE_MIDDLEWARE');
2245
+
2033
2246
  class AXPEntityStorageService {
2034
2247
  }
2035
2248
  class AXPEntityDataProvider {
@@ -2153,734 +2366,1083 @@ class AXMEntityCrudServiceImpl {
2153
2366
  }
2154
2367
  }
2155
2368
 
2156
- /**
2157
- * Compose entity storage middlewares into a pipeline
2158
- */
2159
- function composeEntityStorageMiddlewares(middlewares) {
2160
- return (handler) => {
2161
- let composed = handler;
2162
- // Reverse order composition for proper middleware chain
2163
- for (let i = middlewares.length - 1; i >= 0; i--) {
2164
- const mw = middlewares[i];
2165
- const next = composed;
2166
- composed = (context) => mw(context, next);
2167
- }
2168
- return composed;
2169
- };
2170
- }
2171
- /**
2172
- * Helper function to generate unique request ID
2173
- */
2174
- function generateRequestId() {
2175
- return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
2176
- }
2177
-
2178
- /**
2179
- * Registry for managing entity storage middlewares
2180
- */
2181
- class AXPEntityStorageRegistry {
2369
+ class AXPMiddlewareEntityStorageService extends AXPEntityStorageService {
2182
2370
  constructor() {
2183
- this.globalMiddlewares = [];
2184
- this.entitySpecificMiddlewares = new Map();
2185
- this.operationSpecificMiddlewares = new Map();
2186
- }
2187
- /**
2188
- * Add a global middleware that applies to all operations
2189
- */
2190
- useGlobal(middleware) {
2191
- this.globalMiddlewares.push(middleware);
2371
+ super(...arguments);
2372
+ this.backend = inject(AXP_ENTITY_STORAGE_BACKEND);
2373
+ this.allMiddlewares = (inject(AXP_ENTITY_STORAGE_MIDDLEWARE, { optional: true }) || []).slice();
2374
+ this.injector = inject(EnvironmentInjector);
2192
2375
  }
2193
- /**
2194
- * Add middleware for specific entity
2195
- */
2196
- useForEntity(entityName, middleware) {
2197
- if (!this.entitySpecificMiddlewares.has(entityName)) {
2198
- this.entitySpecificMiddlewares.set(entityName, []);
2199
- }
2200
- this.entitySpecificMiddlewares.get(entityName).push(middleware);
2376
+ get dbName() {
2377
+ return this.backend.dbName;
2378
+ }
2379
+ filterMiddlewares(ctx) {
2380
+ return this.allMiddlewares
2381
+ .filter((mw) => {
2382
+ const t = mw.target;
2383
+ if (!t)
2384
+ return true;
2385
+ if (t.ops && !t.ops.includes(ctx.op))
2386
+ return false;
2387
+ if (t.entity) {
2388
+ if (typeof t.entity === 'string' && t.entity !== ctx.entityName)
2389
+ return false;
2390
+ if (t.entity instanceof RegExp && !t.entity.test(ctx.entityName))
2391
+ return false;
2392
+ }
2393
+ if (t.predicate && !t.predicate(ctx))
2394
+ return false;
2395
+ return true;
2396
+ })
2397
+ .sort((a, b) => (a.target?.order ?? 0) - (b.target?.order ?? 0));
2398
+ }
2399
+ compose(mws, leaf, ctx) {
2400
+ return mws
2401
+ .slice()
2402
+ .reverse()
2403
+ .reduce((next, mw) => {
2404
+ return async () => runInInjectionContext(this.injector, () => mw.execute(ctx, next));
2405
+ }, leaf);
2406
+ }
2407
+ async run(ctx, delegate) {
2408
+ const chain = this.compose(this.filterMiddlewares(ctx), async () => {
2409
+ ctx.result = await delegate();
2410
+ }, ctx);
2411
+ await chain();
2412
+ return ctx.result;
2413
+ }
2414
+ createCtx(op, entityName, init) {
2415
+ return {
2416
+ op,
2417
+ entityName,
2418
+ locals: new Map(),
2419
+ backend: {
2420
+ getOneRaw: (name, id) => this.backend.getOne(name, id),
2421
+ insertOneRaw: (name, e) => this.backend.insertOne(name, e),
2422
+ },
2423
+ ...init,
2424
+ };
2201
2425
  }
2202
- /**
2203
- * Add middleware for specific operation (getOne, insertOne, etc.)
2204
- */
2205
- useForOperation(operation, middleware) {
2206
- if (!this.operationSpecificMiddlewares.has(operation)) {
2207
- this.operationSpecificMiddlewares.set(operation, []);
2208
- }
2209
- this.operationSpecificMiddlewares.get(operation).push(middleware);
2426
+ async initial(entityName, collection, options) {
2427
+ const ctx = this.createCtx('initial', entityName, { data: collection });
2428
+ return this.run(ctx, () => this.backend.initial(entityName, ctx.data, options));
2210
2429
  }
2211
- /**
2212
- * Get all applicable middlewares for a given context
2213
- */
2214
- getMiddlewares(entityName, operation) {
2215
- const middlewares = [];
2216
- // Add global middlewares
2217
- middlewares.push(...this.globalMiddlewares);
2218
- // Add entity-specific middlewares
2219
- const entityMiddlewares = this.entitySpecificMiddlewares.get(entityName);
2220
- if (entityMiddlewares) {
2221
- middlewares.push(...entityMiddlewares);
2222
- }
2223
- // Add operation-specific middlewares
2224
- const operationMiddlewares = this.operationSpecificMiddlewares.get(operation);
2225
- if (operationMiddlewares) {
2226
- middlewares.push(...operationMiddlewares);
2227
- }
2228
- return middlewares;
2430
+ async getOne(entityName, id) {
2431
+ const ctx = this.createCtx('getOne', entityName, { id });
2432
+ return this.run(ctx, () => this.backend.getOne(entityName, id));
2229
2433
  }
2230
- /**
2231
- * Get all global middlewares
2232
- */
2233
- getGlobalMiddlewares() {
2234
- return [...this.globalMiddlewares];
2434
+ async updateOne(entityName, id, keyValues) {
2435
+ const ctx = this.createCtx('update', entityName, { id, data: keyValues });
2436
+ return this.run(ctx, () => this.backend.updateOne(entityName, id, ctx.data));
2235
2437
  }
2236
- /**
2237
- * Remove middleware from global middlewares
2238
- */
2239
- removeGlobalMiddleware(middleware) {
2240
- const index = this.globalMiddlewares.indexOf(middleware);
2241
- if (index > -1) {
2242
- this.globalMiddlewares.splice(index, 1);
2243
- return true;
2244
- }
2245
- return false;
2438
+ async deleteOne(entityName, id) {
2439
+ const ctx = this.createCtx('delete', entityName, { id });
2440
+ return this.run(ctx, () => this.backend.deleteOne(entityName, id));
2246
2441
  }
2247
- /**
2248
- * Clear all middlewares
2249
- */
2250
- clear() {
2251
- this.globalMiddlewares.length = 0;
2252
- this.entitySpecificMiddlewares.clear();
2253
- this.operationSpecificMiddlewares.clear();
2442
+ async insertOne(entityName, entity) {
2443
+ const ctx = this.createCtx('create', entityName, { data: entity });
2444
+ return this.run(ctx, () => this.backend.insertOne(entityName, ctx.data));
2254
2445
  }
2255
- /**
2256
- * Get registered entity names that have specific middlewares
2257
- */
2258
- getRegisteredEntityNames() {
2259
- return Array.from(this.entitySpecificMiddlewares.keys());
2446
+ async getAll(entityName) {
2447
+ const ctx = this.createCtx('getAll', entityName);
2448
+ return this.run(ctx, () => this.backend.getAll(entityName));
2260
2449
  }
2261
- /**
2262
- * Get registered operation names that have specific middlewares
2263
- */
2264
- getRegisteredOperations() {
2265
- return Array.from(this.operationSpecificMiddlewares.keys());
2450
+ async query(entityName, request) {
2451
+ const ctx = this.createCtx('query', entityName, { request });
2452
+ return this.run(ctx, () => this.backend.query(entityName, request));
2266
2453
  }
2267
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2268
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageRegistry, providedIn: 'root' }); }
2454
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMiddlewareEntityStorageService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
2455
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMiddlewareEntityStorageService }); }
2269
2456
  }
2270
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageRegistry, decorators: [{
2271
- type: Injectable,
2272
- args: [{ providedIn: 'root' }]
2457
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMiddlewareEntityStorageService, decorators: [{
2458
+ type: Injectable
2273
2459
  }] });
2274
2460
 
2275
2461
  /**
2276
- * Executor that wraps entity storage operations with middleware pipeline
2462
+ * Entity Event Dispatcher - A wrapper for entity-specific events
2463
+ * Handles pattern-based dispatching for entity operations with wildcard support
2277
2464
  */
2278
- class AXPEntityStorageExecutor {
2279
- constructor(storageService) {
2280
- this.storageService = storageService;
2281
- this.injector = inject(EnvironmentInjector);
2282
- this.registry = inject(AXPEntityStorageRegistry);
2465
+ class AXPEntityEventDispatcherService {
2466
+ constructor() {
2467
+ this.eventService = inject(AXPDistributedEventListenerService);
2283
2468
  }
2284
- /**
2285
- * Execute getOne operation with middleware pipeline
2286
- */
2287
- async getOne(entityName, id) {
2288
- const context = {
2289
- operation: 'getOne',
2469
+ async dispatchEntityEvent(operation, entityName, data) {
2470
+ const enhancedData = {
2471
+ ...data,
2290
2472
  entityName,
2291
- dbName: this.storageService.dbName,
2292
- input: { id },
2293
- metadata: {
2294
- startTime: Date.now(),
2295
- requestId: generateRequestId(),
2296
- },
2297
- };
2298
- const handler = async (ctx) => {
2299
- return this.storageService.getOne(ctx.entityName, ctx.input.id);
2473
+ operation,
2474
+ timestamp: new Date(),
2475
+ source: 'entity-dispatcher',
2300
2476
  };
2301
- return this.executeWithMiddleware(context, handler);
2477
+ const eventKeysToDispatch = await this.getAllMatchingEventKeys(operation, entityName);
2478
+ const dispatchPromises = eventKeysToDispatch.map((key) => this.eventService.dispatch(key, enhancedData));
2479
+ await Promise.all(dispatchPromises);
2480
+ }
2481
+ async getAllMatchingEventKeys(operation, entityName) {
2482
+ const eventKeys = new Set();
2483
+ const exactKeys = this.generateEventKeys(operation, entityName);
2484
+ exactKeys.forEach((key) => eventKeys.add(key));
2485
+ const wildcardKeys = await this.findMatchingWildcardKeys(operation, entityName);
2486
+ wildcardKeys.forEach((key) => eventKeys.add(key));
2487
+ return Array.from(eventKeys);
2488
+ }
2489
+ async findMatchingWildcardKeys(operation, entityName) {
2490
+ const matchingKeys = [];
2491
+ const allListenerKeys = await this.eventService.getRegisteredKeys();
2492
+ const actualEventKey = `entity.${operation}.${entityName}`;
2493
+ for (const listenerKey of allListenerKeys) {
2494
+ if (listenerKey.includes('*') && this.matchesEntityPattern(actualEventKey, listenerKey)) {
2495
+ matchingKeys.push(listenerKey);
2496
+ }
2497
+ }
2498
+ return matchingKeys;
2302
2499
  }
2303
- /**
2304
- * Execute getAll operation with middleware pipeline
2305
- */
2306
- async getAll(entityName) {
2307
- const context = {
2308
- operation: 'getAll',
2309
- entityName,
2310
- dbName: this.storageService.dbName,
2311
- input: {},
2312
- metadata: {
2313
- startTime: Date.now(),
2314
- requestId: generateRequestId(),
2315
- },
2316
- };
2317
- const handler = async (ctx) => {
2318
- return this.storageService.getAll(ctx.entityName);
2319
- };
2320
- return this.executeWithMiddleware(context, handler);
2500
+ matchesEntityPattern(eventKey, pattern) {
2501
+ if (!pattern.startsWith('entity.') || !pattern.includes('*')) {
2502
+ return false;
2503
+ }
2504
+ const regexPattern = pattern.replace(/\./g, '\\.').replace(/\*/g, '.*');
2505
+ const regex = new RegExp(`^${regexPattern}$`);
2506
+ return regex.test(eventKey);
2507
+ }
2508
+ generateEventKeys(operation, entityName) {
2509
+ const keys = [];
2510
+ keys.push(`entity.${operation}`);
2511
+ keys.push(`entity.${operation}.${entityName}`);
2512
+ const entityParts = entityName.split('.');
2513
+ if (entityParts.length > 1) {
2514
+ const moduleName = entityParts[0];
2515
+ keys.push(`entity.${operation}.${moduleName}`);
2516
+ }
2517
+ return keys;
2321
2518
  }
2322
- /**
2323
- * Execute insertOne operation with middleware pipeline
2324
- */
2325
- async insertOne(entityName, entity) {
2326
- const context = {
2327
- operation: 'insertOne',
2328
- entityName,
2329
- dbName: this.storageService.dbName,
2330
- input: { entity },
2331
- metadata: {
2332
- startTime: Date.now(),
2333
- requestId: generateRequestId(),
2334
- },
2335
- };
2336
- const handler = async (ctx) => {
2337
- return this.storageService.insertOne(ctx.entityName, ctx.input.entity);
2338
- };
2339
- return this.executeWithMiddleware(context, handler);
2519
+ async dispatchInserted(entityName, data) {
2520
+ await this.dispatchEntityEvent('inserted', entityName, data);
2340
2521
  }
2341
- /**
2342
- * Execute updateOne operation with middleware pipeline
2343
- */
2344
- async updateOne(entityName, id, keyValues) {
2345
- const context = {
2346
- operation: 'updateOne',
2347
- entityName,
2348
- dbName: this.storageService.dbName,
2349
- input: { id, keyValues },
2350
- metadata: {
2351
- startTime: Date.now(),
2352
- requestId: generateRequestId(),
2353
- },
2354
- };
2355
- const handler = async (ctx) => {
2356
- return this.storageService.updateOne(ctx.entityName, ctx.input.id, ctx.input.keyValues);
2357
- };
2358
- return this.executeWithMiddleware(context, handler);
2522
+ async dispatchUpdated(entityName, data) {
2523
+ await this.dispatchEntityEvent('updated', entityName, data);
2359
2524
  }
2360
- /**
2361
- * Execute deleteOne operation with middleware pipeline
2362
- */
2363
- async deleteOne(entityName, id) {
2364
- const context = {
2365
- operation: 'deleteOne',
2366
- entityName,
2367
- dbName: this.storageService.dbName,
2368
- input: { id },
2369
- metadata: {
2370
- startTime: Date.now(),
2371
- requestId: generateRequestId(),
2372
- },
2373
- };
2374
- const handler = async (ctx) => {
2375
- return this.storageService.deleteOne(ctx.entityName, ctx.input.id);
2376
- };
2377
- return this.executeWithMiddleware(context, handler);
2525
+ async dispatchDeleted(entityName, data) {
2526
+ await this.dispatchEntityEvent('deleted', entityName, data);
2378
2527
  }
2379
- /**
2380
- * Execute query operation with middleware pipeline
2381
- */
2382
- async query(entityName, request) {
2383
- const context = {
2384
- operation: 'query',
2385
- entityName,
2386
- dbName: this.storageService.dbName,
2387
- input: { request },
2388
- metadata: {
2389
- startTime: Date.now(),
2390
- requestId: generateRequestId(),
2391
- },
2392
- };
2393
- const handler = async (ctx) => {
2394
- return this.storageService.query(ctx.entityName, ctx.input.request);
2528
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityEventDispatcherService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2529
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityEventDispatcherService, providedIn: 'root' }); }
2530
+ }
2531
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityEventDispatcherService, decorators: [{
2532
+ type: Injectable,
2533
+ args: [{
2534
+ providedIn: 'root',
2535
+ }]
2536
+ }] });
2537
+
2538
+ class AXPLayoutAdapterBuilder {
2539
+ constructor() {
2540
+ this.adapter = {};
2541
+ }
2542
+ setEntity(entity, rootContext) {
2543
+ this.entity = entity;
2544
+ this.rootContext = rootContext;
2545
+ return this;
2546
+ }
2547
+ setDependencies(dependencies) {
2548
+ this.dependencies = dependencies;
2549
+ return this;
2550
+ }
2551
+ setMainPage(mainPage) {
2552
+ this.adapter.pages = [mainPage];
2553
+ return this;
2554
+ }
2555
+ setRelatedPages(relatedPages) {
2556
+ this.adapter.pages = [...(this.adapter.pages || []), ...relatedPages];
2557
+ return this;
2558
+ }
2559
+ build() {
2560
+ return {
2561
+ title: this.entity?.formats.plural || this.entity?.title,
2562
+ actions: [],
2563
+ breadcrumbs: this.createBreadcrumbs(),
2564
+ execute: this.createExecuteFunction(),
2565
+ load: this.createLoadFunction(),
2566
+ pages: this.adapter.pages || [],
2395
2567
  };
2396
- return this.executeWithMiddleware(context, handler);
2397
2568
  }
2398
- /**
2399
- * Execute initial operation with middleware pipeline
2400
- */
2401
- async initial(entityName, collection, options) {
2402
- const context = {
2403
- operation: 'initial',
2404
- entityName,
2405
- dbName: this.storageService.dbName,
2406
- input: { collection, options },
2407
- metadata: {
2408
- startTime: Date.now(),
2409
- requestId: generateRequestId(),
2569
+ createBreadcrumbs() {
2570
+ const session = this.dependencies.session;
2571
+ const moduleName = this.entity?.module;
2572
+ const entityName = this.entity?.name;
2573
+ return [
2574
+ {
2575
+ title: this.entity?.formats.plural ?? '',
2576
+ command: {
2577
+ name: 'navigate',
2578
+ options: {
2579
+ path: `/${session.application?.name}/m/${moduleName}/e/${entityName}/list`,
2580
+ },
2581
+ },
2410
2582
  },
2583
+ {
2584
+ title: this.entity?.interfaces?.master?.single?.title ?? '',
2585
+ command: {
2586
+ name: 'navigate',
2587
+ options: {
2588
+ path: `/${session.application?.name}/m/${moduleName}/e/${entityName}/${this.rootContext.id}/new-view`,
2589
+ },
2590
+ },
2591
+ },
2592
+ ];
2593
+ }
2594
+ createExecuteFunction() {
2595
+ return (command, context) => {
2596
+ console.log('layout execute', command, context);
2597
+ return Promise.resolve({ success: true });
2411
2598
  };
2412
- const handler = async (ctx) => {
2413
- return this.storageService.initial(ctx.entityName, ctx.input.collection, ctx.input.options);
2414
- };
2415
- return this.executeWithMiddleware(context, handler);
2416
2599
  }
2417
- /**
2418
- * Execute operation with middleware pipeline
2419
- */
2420
- async executeWithMiddleware(context, handler) {
2421
- const middlewares = this.registry.getMiddlewares(context.entityName, context.operation);
2422
- // Wrap middlewares with injection context
2423
- const wrappedMiddlewares = middlewares.map(middleware => {
2424
- return (ctx, next) => runInInjectionContext(this.injector, () => middleware(ctx, next));
2425
- });
2426
- const composed = composeEntityStorageMiddlewares(wrappedMiddlewares)(handler);
2427
- return composed(context);
2600
+ createLoadFunction() {
2601
+ return async () => {
2602
+ return {
2603
+ success: true,
2604
+ result: this.rootContext,
2605
+ };
2606
+ };
2428
2607
  }
2429
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageExecutor, deps: [{ token: AXPEntityStorageService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2430
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageExecutor, providedIn: 'root' }); }
2608
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterBuilder, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2609
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterBuilder, providedIn: 'root' }); }
2431
2610
  }
2432
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageExecutor, decorators: [{
2611
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterBuilder, decorators: [{
2433
2612
  type: Injectable,
2434
- args: [{ providedIn: 'root' }]
2435
- }], ctorParameters: () => [{ type: AXPEntityStorageService }] });
2613
+ args: [{
2614
+ providedIn: 'root',
2615
+ }]
2616
+ }] });
2436
2617
 
2437
- /**
2438
- * Entity Storage Service with middleware support
2439
- *
2440
- * This service wraps the original AXPEntityStorageService and adds middleware pipeline support.
2441
- * It delegates all operations to the middleware executor which applies the middleware chain.
2442
- */
2443
- class AXPEntityStorageWithMiddlewareService extends AXPEntityStorageService {
2444
- constructor(originalStorageService, registry) {
2445
- super();
2446
- this.originalStorageService = originalStorageService;
2447
- this.registry = registry;
2448
- this.executor = new AXPEntityStorageExecutor(originalStorageService);
2449
- }
2450
- get dbName() {
2451
- return this.originalStorageService.dbName;
2452
- }
2453
- // Middleware Management Methods
2454
- /**
2455
- * Add a global middleware that applies to all operations
2456
- */
2457
- useGlobal(middleware) {
2458
- this.registry.useGlobal(middleware);
2459
- }
2460
- /**
2461
- * Add middleware for specific entity
2462
- */
2463
- useForEntity(entityName, middleware) {
2464
- this.registry.useForEntity(entityName, middleware);
2465
- }
2466
- /**
2467
- * Add middleware for specific operation
2468
- */
2469
- useForOperation(operation, middleware) {
2470
- this.registry.useForOperation(operation, middleware);
2618
+ class AXPBaseRelatedEntityConverter {
2619
+ async getEntityDefinition(relatedEntity, entityResolver) {
2620
+ const [moduleName, entityName] = relatedEntity.entity.split('.');
2621
+ const entityDef = await entityResolver.resolve(moduleName, entityName);
2622
+ if (!entityDef) {
2623
+ throw new Error(`Entity ${relatedEntity.entity} not found`);
2624
+ }
2625
+ return { entityDef, moduleName, entityName };
2471
2626
  }
2472
- // Storage Operations with Middleware Pipeline
2473
- async initial(entityName, collection, options) {
2474
- return this.executor.initial(entityName, collection, options);
2627
+ createExpressionEvaluator(context, expressionEvaluator) {
2628
+ return async (actionData) => {
2629
+ const scope = {
2630
+ context: {
2631
+ eval: (path) => get(context, path),
2632
+ },
2633
+ };
2634
+ return await expressionEvaluator.evaluate(actionData, scope);
2635
+ };
2475
2636
  }
2476
- async getOne(entityName, id) {
2477
- return this.executor.getOne(entityName, id);
2637
+ async createFilters(relatedEntity, evaluateExpressions) {
2638
+ return (relatedEntity.conditions?.map(async (c) => {
2639
+ const value = await evaluateExpressions(c.value);
2640
+ return {
2641
+ field: c.name,
2642
+ operator: c.operator,
2643
+ value: value,
2644
+ };
2645
+ }) ?? []);
2478
2646
  }
2479
- async updateOne(entityName, id, keyValues) {
2480
- return this.executor.updateOne(entityName, id, keyValues);
2647
+ createEntityHelpers(entityDef) {
2648
+ const groups = entityDef?.groups ?? [];
2649
+ const singleInterface = entityDef?.interfaces?.master?.single;
2650
+ return {
2651
+ getGroupById: (id) => groups.find((s) => s.id === id),
2652
+ getPropertyByGroupId: (groupId) => entityDef?.properties.filter((p) => p.groupId === groupId) ?? [],
2653
+ getPropertyLayout: (name) => singleInterface?.properties?.find((p) => p.name === name)?.layout,
2654
+ singleInterface,
2655
+ groups,
2656
+ };
2481
2657
  }
2482
- async deleteOne(entityName, id) {
2483
- return this.executor.deleteOne(entityName, id);
2658
+ createGridLayoutStructure(singleInterface, helpers) {
2659
+ return {
2660
+ type: 'grid-layout',
2661
+ options: {
2662
+ grid: {
2663
+ default: {
2664
+ gridTemplateColumns: 'repeat(12, 1fr)',
2665
+ gridTemplateRows: 'repeat(1, 1fr)',
2666
+ gap: '20px',
2667
+ },
2668
+ },
2669
+ },
2670
+ children: singleInterface?.sections.map((s) => ({
2671
+ type: 'grid-item-layout',
2672
+ name: s.id,
2673
+ options: {
2674
+ colSpan: s.layout?.positions?.lg?.colSpan ?? 12,
2675
+ colStart: s.layout?.positions?.lg?.colStart,
2676
+ colEnd: s.layout?.positions?.lg?.colEnd,
2677
+ },
2678
+ children: [
2679
+ {
2680
+ type: 'fieldset-layout',
2681
+ options: {
2682
+ title: helpers.getGroupById(s.id)?.title ?? '',
2683
+ collapsible: true,
2684
+ },
2685
+ children: [this.createPropertyGrid(s.id, helpers)],
2686
+ },
2687
+ ],
2688
+ })),
2689
+ };
2484
2690
  }
2485
- async insertOne(entityName, entity) {
2486
- return this.executor.insertOne(entityName, entity);
2691
+ createPropertyGrid(sectionId, helpers) {
2692
+ return {
2693
+ type: 'grid-layout',
2694
+ mode: 'edit',
2695
+ options: {
2696
+ grid: {
2697
+ default: {
2698
+ gridTemplateColumns: 'repeat(12, 1fr)',
2699
+ gridTemplateRows: 'repeat(1, 1fr)',
2700
+ gap: '20px',
2701
+ },
2702
+ },
2703
+ },
2704
+ children: helpers
2705
+ .getPropertyByGroupId(sectionId)
2706
+ .filter((property) => !property.schema.hidden)
2707
+ .map((p) => {
2708
+ const layout = helpers.getPropertyLayout(p.name);
2709
+ return {
2710
+ type: 'grid-item-layout',
2711
+ name: p.name,
2712
+ options: {
2713
+ colSpan: layout?.positions?.lg?.colSpan ?? 12,
2714
+ colStart: layout?.positions?.lg?.colStart,
2715
+ colEnd: layout?.positions?.lg?.colEnd,
2716
+ },
2717
+ children: [
2718
+ {
2719
+ type: 'form-field',
2720
+ options: {
2721
+ label: p.title,
2722
+ },
2723
+ children: [
2724
+ {
2725
+ type: p.schema.interface?.type ?? '',
2726
+ path: p.name,
2727
+ name: p.name,
2728
+ defaultValue: p.schema.defaultValue,
2729
+ children: p.schema.interface?.children,
2730
+ options: p.schema.interface?.options,
2731
+ triggers: p.schema.interface?.triggers,
2732
+ valueTransforms: p.schema.interface?.valueTransforms,
2733
+ },
2734
+ ],
2735
+ },
2736
+ ],
2737
+ };
2738
+ }),
2739
+ };
2487
2740
  }
2488
- async getAll(entityName) {
2489
- return this.executor.getAll(entityName);
2741
+ }
2742
+
2743
+ class AXPPageDetailsConverter extends AXPBaseRelatedEntityConverter {
2744
+ async convert(relatedEntity, context) {
2745
+ const { entityDef } = await this.getEntityDefinition(relatedEntity, context.entityResolver);
2746
+ const helpers = this.createEntityHelpers(entityDef);
2747
+ return {
2748
+ id: entityDef?.name ?? '',
2749
+ title: relatedEntity.title ?? entityDef?.title ?? '',
2750
+ label: relatedEntity.title ?? entityDef?.formats.displayName ?? '',
2751
+ icon: relatedEntity.icon || entityDef.icon,
2752
+ settings: this.createPageSettings(),
2753
+ load: this.createLoadFunction(entityDef, relatedEntity),
2754
+ execute: this.createExecuteFunction(entityDef),
2755
+ content: [this.createGridLayoutStructure(helpers.singleInterface, helpers)],
2756
+ };
2490
2757
  }
2491
- async query(entityName, request) {
2492
- return this.executor.query(entityName, request);
2758
+ createPageSettings() {
2759
+ return {
2760
+ commands: {
2761
+ reject: {
2762
+ title: 't("discard")',
2763
+ color: 'default',
2764
+ visible: '{{context.isDirty()}}',
2765
+ command: { name: 'discard' },
2766
+ },
2767
+ accept: {
2768
+ title: 't("confirm")',
2769
+ color: 'secondary',
2770
+ visible: '{{context.isDirty()}}',
2771
+ command: { name: 'update-entity' },
2772
+ },
2773
+ },
2774
+ };
2493
2775
  }
2494
- // Direct access to original service (bypass middleware)
2495
- get originalService() {
2496
- return this.originalStorageService;
2776
+ createLoadFunction(entityDef, relatedEntity) {
2777
+ return async (context) => {
2778
+ const fn = entityDef?.queries.byKey?.execute;
2779
+ const conditionNames = relatedEntity.conditions?.map((c) => c.name) ?? [];
2780
+ const id = getSmart(context, conditionNames[0]);
2781
+ const result = await fn(id);
2782
+ return { success: true, result };
2783
+ };
2497
2784
  }
2498
- // Access to registry for advanced middleware management
2499
- get middlewareRegistry() {
2500
- return this.registry;
2785
+ createExecuteFunction(entityDef) {
2786
+ return async (e, context) => {
2787
+ if (e.name === 'update-entity') {
2788
+ const fn = entityDef?.commands?.update?.execute;
2789
+ const result = await fn(context);
2790
+ return { success: true, result };
2791
+ }
2792
+ else {
2793
+ return {
2794
+ success: false,
2795
+ error: { code: 'invalid_command', message: 'Invalid command' },
2796
+ };
2797
+ }
2798
+ };
2501
2799
  }
2502
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageWithMiddlewareService, deps: [{ token: AXPEntityStorageService }, { token: AXPEntityStorageRegistry }], target: i0.ɵɵFactoryTarget.Injectable }); }
2503
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageWithMiddlewareService }); }
2504
2800
  }
2505
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageWithMiddlewareService, decorators: [{
2506
- type: Injectable
2507
- }], ctorParameters: () => [{ type: AXPEntityStorageService }, { type: AXPEntityStorageRegistry }] });
2508
2801
 
2509
- /**
2510
- * Injection token for entity storage middleware setup
2511
- */
2512
- const AXP_ENTITY_STORAGE_MIDDLEWARE_SETUP = new InjectionToken('AXP_ENTITY_STORAGE_MIDDLEWARE_SETUP');
2513
- /**
2514
- * Injection token for entity storage middleware extensions
2515
- */
2516
- const AXP_ENTITY_STORAGE_EXTENSION = new InjectionToken('AXP_ENTITY_STORAGE_EXTENSION');
2517
- /**
2518
- * Provide entity storage middleware configuration
2519
- */
2520
- function provideEntityStorageMiddleware(config) {
2521
- const providers = [];
2522
- // Register extension middlewares
2523
- if (config.extensions) {
2524
- providers.push(...config.extensions.map(ext => ({
2525
- provide: AXP_ENTITY_STORAGE_EXTENSION,
2526
- useValue: ext,
2527
- multi: true,
2528
- })));
2529
- }
2530
- // Main setup provider
2531
- providers.push({
2532
- provide: AXP_ENTITY_STORAGE_MIDDLEWARE_SETUP,
2533
- useFactory: () => {
2534
- const registry = inject(AXPEntityStorageRegistry);
2535
- // Register global middlewares
2536
- if (config.global) {
2537
- for (const middleware of config.global) {
2538
- registry.useGlobal(middleware);
2539
- }
2540
- }
2541
- // Register entity-specific middlewares
2542
- if (config.entities) {
2543
- for (const [entityName, middlewares] of Object.entries(config.entities)) {
2544
- for (const middleware of middlewares) {
2545
- registry.useForEntity(entityName, middleware);
2802
+ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
2803
+ async convert(relatedEntity, context) {
2804
+ const { entityDef } = await this.getEntityDefinition(relatedEntity, context.entityResolver);
2805
+ const evaluateExpressions = async (actionData) => {
2806
+ const scope = {
2807
+ context: {
2808
+ eval: (path) => {
2809
+ return get(context.context, path);
2810
+ },
2811
+ },
2812
+ };
2813
+ return await context.expressionEvaluator.evaluate(actionData, scope);
2814
+ };
2815
+ const filters = relatedEntity.conditions?.map(async (c) => {
2816
+ const value = await evaluateExpressions(c.value);
2817
+ return {
2818
+ field: c.name,
2819
+ operator: c.operator,
2820
+ value: value,
2821
+ hidden: true,
2822
+ };
2823
+ }) ?? [];
2824
+ return {
2825
+ id: entityDef?.name ?? '',
2826
+ title: `${context.rootTitle}`,
2827
+ label: relatedEntity.title,
2828
+ icon: relatedEntity.icon || entityDef.icon,
2829
+ actions: this.mergeActions(entityDef, relatedEntity)
2830
+ ?.filter((a) => a.priority === 'primary')
2831
+ ?.map((a) => {
2832
+ return {
2833
+ ...a,
2834
+ zone: 'header',
2835
+ // visible:
2836
+ // a.scope === AXPEntityCommandScope.Selected
2837
+ // ? "{{widget.find('table').outputs().selectedItem().length > 0}}"
2838
+ // : true,
2839
+ visible: '{{context.eval("table")}}',
2840
+ priority: 'primary',
2841
+ name: a.name,
2842
+ title: a.title,
2843
+ scope: a.scope,
2844
+ icon: a.icon,
2845
+ color: a.color,
2846
+ disabled: a.disabled,
2847
+ command: {
2848
+ name: a.name,
2849
+ options: a.options,
2850
+ metadata: a.metadata,
2851
+ },
2852
+ };
2853
+ }),
2854
+ execute: async (command, executeContext) => {
2855
+ try {
2856
+ const commandName = command.name.split('&')[0];
2857
+ const mergedActions = this.mergeActions(entityDef, relatedEntity);
2858
+ const action = mergedActions.find((a) => {
2859
+ return a.name === commandName || a.name.split('&')[0] === commandName;
2860
+ });
2861
+ if (!action) {
2862
+ console.warn(`Action ${commandName} not found in entity definition`);
2863
+ return {
2864
+ success: false,
2865
+ error: {
2866
+ code: 'ACTION_NOT_FOUND',
2867
+ message: `Action ${commandName} not found`,
2868
+ details: command,
2869
+ },
2870
+ };
2546
2871
  }
2547
- }
2548
- }
2549
- // Register operation-specific middlewares
2550
- if (config.operations) {
2551
- for (const [operation, middlewares] of Object.entries(config.operations)) {
2552
- for (const middleware of middlewares) {
2553
- registry.useForOperation(operation, middleware);
2872
+ let evaluatedOptions = command.options;
2873
+ if (action.options) {
2874
+ evaluatedOptions = await evaluateExpressions(action.options);
2554
2875
  }
2876
+ await context.workflowService.execute(commandName, {
2877
+ entity: getEntityInfo(entityDef).source,
2878
+ entityInfo: {
2879
+ name: entityDef.name,
2880
+ module: entityDef.module,
2881
+ title: entityDef.title,
2882
+ parentKey: entityDef.parentKey,
2883
+ source: entityDef.source,
2884
+ },
2885
+ data: action.scope == AXPEntityCommandScope.Selected
2886
+ ? executeContext
2887
+ : evaluatedOptions?.['process']?.data || null,
2888
+ options: evaluatedOptions,
2889
+ metadata: action.metadata,
2890
+ });
2891
+ return { success: true };
2892
+ }
2893
+ catch (error) {
2894
+ console.error('Error executing command:', error);
2895
+ return {
2896
+ success: false,
2897
+ error: {
2898
+ code: 'EXECUTION_ERROR',
2899
+ message: error instanceof Error ? error.message : 'Unknown error occurred',
2900
+ details: error,
2901
+ },
2902
+ };
2555
2903
  }
2904
+ },
2905
+ content: [
2906
+ {
2907
+ type: AXPWidgetsCatalog.entityList,
2908
+ name: 'page-list',
2909
+ defaultValue: {
2910
+ toolbar: {
2911
+ filters: await Promise.all(filters),
2912
+ },
2913
+ },
2914
+ options: {
2915
+ entity: relatedEntity.entity,
2916
+ showEntityActions: false,
2917
+ },
2918
+ },
2919
+ ],
2920
+ };
2921
+ }
2922
+ mergeActions(entityDef, relatedEntity) {
2923
+ const originalList = entityDef?.interfaces?.master?.list?.actions ?? [];
2924
+ const relatedEntityActionList = relatedEntity.actions ?? [];
2925
+ // Create a map to track which actions from relatedEntityActionList have been used
2926
+ const usedOverrideActions = new Set();
2927
+ // Start with original actions, applying overrides where they exist
2928
+ const mergedActions = originalList.map((originalAction) => {
2929
+ const originalCommandName = typeof originalAction.command === 'string' ? originalAction.command : originalAction.command.name;
2930
+ const overrideAction = relatedEntityActionList.find((action) => {
2931
+ const actionCommandName = typeof action.command === 'string' ? action.command : action.command.name;
2932
+ return actionCommandName === originalCommandName && action.name === originalAction.name;
2933
+ });
2934
+ if (overrideAction) {
2935
+ // Mark this override action as used
2936
+ const overrideKey = `${typeof overrideAction.command === 'string' ? overrideAction.command : overrideAction.command.name}_${overrideAction.name}`;
2937
+ usedOverrideActions.add(overrideKey);
2938
+ return new AXPEntityCommandTriggerViewModel(entityDef, overrideAction);
2556
2939
  }
2557
- return true;
2558
- },
2559
- multi: true,
2560
- });
2561
- return makeEnvironmentProviders(providers);
2562
- }
2563
- /**
2564
- * Simplified provider for global middleware only
2565
- */
2566
- function provideGlobalEntityStorageMiddleware(middlewares) {
2567
- return provideEntityStorageMiddleware({ global: middlewares });
2568
- }
2569
- /**
2570
- * Provider for entity-specific middlewares
2571
- */
2572
- function provideEntitySpecificMiddleware(entityName, middlewares) {
2573
- return provideEntityStorageMiddleware({
2574
- entities: { [entityName]: middlewares }
2575
- });
2576
- }
2577
- /**
2578
- * Provider for operation-specific middlewares
2579
- */
2580
- function provideOperationSpecificMiddleware(operation, middlewares) {
2581
- return provideEntityStorageMiddleware({
2582
- operations: { [operation]: middlewares }
2583
- });
2940
+ return new AXPEntityCommandTriggerViewModel(entityDef, originalAction);
2941
+ });
2942
+ // Add any remaining actions from relatedEntityActionList that weren't used as overrides
2943
+ const additionalActions = relatedEntityActionList
2944
+ .filter((action) => {
2945
+ const actionKey = `${typeof action.command === 'string' ? action.command : action.command.name}_${action.name}`;
2946
+ return !usedOverrideActions.has(actionKey);
2947
+ })
2948
+ .map((action) => new AXPEntityCommandTriggerViewModel(entityDef, action));
2949
+ return [...additionalActions, ...mergedActions].filter((a) => !a.hidden);
2950
+ }
2584
2951
  }
2585
2952
 
2586
- /**
2587
- * Logging middleware for entity storage operations
2588
- */
2589
- const loggingMiddleware = async (context, next) => {
2590
- const startTime = Date.now();
2591
- console.group(`🔄 Entity Storage Operation: ${context.operation}`);
2592
- console.log('📋 Entity:', context.entityName);
2593
- console.log('🗄️ Database:', context.dbName);
2594
- console.log('📨 Input:', context.input);
2595
- console.log('🆔 Request ID:', context.metadata.requestId);
2596
- try {
2597
- const result = await next(context);
2598
- const duration = Date.now() - startTime;
2599
- console.log('✅ Success');
2600
- console.log('⏱️ Duration:', `${duration}ms`);
2601
- console.log('📤 Result:', result);
2602
- console.groupEnd();
2603
- return result;
2604
- }
2605
- catch (error) {
2606
- const duration = Date.now() - startTime;
2607
- console.error('❌ Error');
2608
- console.error('⏱️ Duration:', `${duration}ms`);
2609
- console.error('💥 Error:', error);
2610
- console.groupEnd();
2611
- throw error;
2612
- }
2613
- };
2614
- /**
2615
- * Performance monitoring middleware
2616
- */
2617
- const performanceMiddleware = async (context, next) => {
2618
- const startTime = performance.now();
2619
- try {
2620
- const result = await next(context);
2621
- const duration = performance.now() - startTime;
2622
- // Log slow operations (> 1000ms)
2623
- if (duration > 1000) {
2624
- console.warn(`⚠️ Slow operation detected: ${context.operation} on ${context.entityName} took ${duration.toFixed(2)}ms`);
2625
- }
2626
- // Add performance metrics to context
2627
- context.metadata['performanceMetrics'] = {
2628
- duration,
2629
- operation: context.operation,
2630
- entityName: context.entityName,
2953
+ class AXPTabDetailsConverter extends AXPBaseRelatedEntityConverter {
2954
+ async convert(relatedEntity, context) {
2955
+ const { entityDef } = await this.getEntityDefinition(relatedEntity, context.entityResolver);
2956
+ const helpers = this.createEntityHelpers(entityDef);
2957
+ return {
2958
+ id: entityDef?.name ?? '',
2959
+ title: relatedEntity.title ?? entityDef?.title ?? '',
2960
+ icon: relatedEntity.icon || entityDef.icon,
2961
+ content: [this.createGridLayoutStructure(helpers.singleInterface, helpers)],
2631
2962
  };
2632
- return result;
2633
2963
  }
2634
- catch (error) {
2635
- const duration = performance.now() - startTime;
2636
- console.error(`❌ Failed operation: ${context.operation} on ${context.entityName} failed after ${duration.toFixed(2)}ms`);
2637
- throw error;
2964
+ }
2965
+
2966
+ class AXPTabListConverter extends AXPBaseRelatedEntityConverter {
2967
+ async convert(relatedEntity, context) {
2968
+ const { entityDef } = await this.getEntityDefinition(relatedEntity, context.entityResolver);
2969
+ const evaluateExpressions = async (actionData) => {
2970
+ const scope = {
2971
+ context: {
2972
+ eval: (path) => {
2973
+ return get(context.context, path);
2974
+ },
2975
+ },
2976
+ };
2977
+ return await context.expressionEvaluator.evaluate(actionData, scope);
2978
+ };
2979
+ // console.log({ relatedEntity });
2980
+ const filters = relatedEntity.conditions?.map(async (c) => {
2981
+ const value = await evaluateExpressions(c.value);
2982
+ return {
2983
+ field: c.name,
2984
+ operator: c.operator,
2985
+ value: value,
2986
+ hidden: true,
2987
+ };
2988
+ }) ?? [];
2989
+ return {
2990
+ id: entityDef?.name ?? '',
2991
+ title: relatedEntity.title ?? entityDef?.title ?? '',
2992
+ icon: relatedEntity.icon || entityDef.icon,
2993
+ content: [
2994
+ {
2995
+ type: AXPWidgetsCatalog.entityList,
2996
+ name: 'tab-list',
2997
+ defaultValue: {
2998
+ toolbar: {
2999
+ filters: await Promise.all(filters),
3000
+ },
3001
+ },
3002
+ options: {
3003
+ entity: relatedEntity.entity,
3004
+ showEntityActions: true,
3005
+ showToolbar: true,
3006
+ },
3007
+ },
3008
+ ],
3009
+ };
2638
3010
  }
2639
- };
2640
- /**
2641
- * Error handling middleware with retry logic
2642
- */
2643
- const errorHandlingMiddleware = async (context, next) => {
2644
- const maxRetries = 3;
2645
- let attempt = 0;
2646
- while (attempt < maxRetries) {
2647
- try {
2648
- const result = await next(context);
2649
- if (attempt > 0) {
2650
- console.log(`✅ Operation succeeded on retry ${attempt}/${maxRetries}`);
2651
- }
2652
- return result;
2653
- }
2654
- catch (error) {
2655
- attempt++;
2656
- // Don't retry for certain operations or error types
2657
- if (context.operation === 'deleteOne' ||
2658
- error?.code === 'VALIDATION_ERROR' ||
2659
- attempt >= maxRetries) {
2660
- console.error(`❌ Operation failed after ${attempt} attempts:`, error);
2661
- throw error;
2662
- }
2663
- console.warn(`⚠️ Attempt ${attempt}/${maxRetries} failed, retrying...`, error.message);
2664
- // Wait before retry (exponential backoff)
2665
- await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
3011
+ }
3012
+
3013
+ class AXPRelatedEntityConverterFactory {
3014
+ createConverter(type) {
3015
+ switch (type) {
3016
+ case 'page-detail':
3017
+ return new AXPPageDetailsConverter();
3018
+ case 'page-list':
3019
+ return new AXPPageListConverter();
3020
+ case 'tab-detail':
3021
+ return new AXPTabDetailsConverter();
3022
+ case 'tab-list':
3023
+ return new AXPTabListConverter();
3024
+ default:
3025
+ throw new Error(`Unsupported converter type: ${type}`);
2666
3026
  }
2667
3027
  }
2668
- throw new Error('Max retries exceeded');
2669
- };
2670
- /**
2671
- * Validation middleware
2672
- */
2673
- const validationMiddleware = async (context, next) => {
2674
- // Validate input based on operation
2675
- switch (context.operation) {
2676
- case 'insertOne':
2677
- if (!context.input.entity) {
2678
- throw new Error('Entity is required for insertOne operation');
2679
- }
2680
- break;
2681
- case 'updateOne':
2682
- if (!context.input.id) {
2683
- throw new Error('ID is required for updateOne operation');
2684
- }
2685
- if (!context.input.keyValues) {
2686
- throw new Error('Key values are required for updateOne operation');
2687
- }
2688
- break;
2689
- case 'deleteOne':
2690
- case 'getOne':
2691
- if (!context.input.id) {
2692
- throw new Error(`ID is required for ${context.operation} operation`);
2693
- }
2694
- break;
2695
- case 'query':
2696
- if (!context.input.request) {
2697
- throw new Error('Request is required for query operation');
2698
- }
2699
- break;
2700
- case 'initial':
2701
- if (!context.input.collection || !Array.isArray(context.input.collection)) {
2702
- throw new Error('Collection array is required for initial operation');
2703
- }
2704
- break;
2705
- }
2706
- return next(context);
2707
- };
2708
- /**
2709
- * Caching middleware (simple in-memory cache)
2710
- */
2711
- const cachingMiddleware = (() => {
2712
- const cache = new Map();
2713
- const DEFAULT_TTL = 5 * 60 * 1000; // 5 minutes
2714
- return async (context, next) => {
2715
- // Only cache read operations
2716
- if (!['getOne', 'getAll', 'query'].includes(context.operation)) {
2717
- // Clear cache for write operations on the same entity
2718
- const keysToDelete = Array.from(cache.keys()).filter(key => key.includes(`${context.entityName}:`));
2719
- keysToDelete.forEach(key => cache.delete(key));
2720
- return next(context);
2721
- }
2722
- // Generate cache key
2723
- const cacheKey = `${context.entityName}:${context.operation}:${JSON.stringify(context.input)}`;
2724
- // Check cache
2725
- const cached = cache.get(cacheKey);
2726
- if (cached && Date.now() - cached.timestamp < cached.ttl) {
2727
- console.log(`💾 Cache hit for ${cacheKey}`);
2728
- return cached.data;
2729
- }
2730
- // Execute and cache result
2731
- const result = await next(context);
2732
- cache.set(cacheKey, {
2733
- data: result,
2734
- timestamp: Date.now(),
2735
- ttl: DEFAULT_TTL,
2736
- });
2737
- console.log(`💾 Cached result for ${cacheKey}`);
2738
- return result;
2739
- };
2740
- })();
2741
-
2742
- /**
2743
- * Simple in-memory audit storage (for demo purposes)
2744
- */
2745
- class InMemoryAuditStorage {
2746
- constructor() {
2747
- this.entries = [];
3028
+ createPageDetailsConverter() {
3029
+ return this.createConverter('page-detail');
2748
3030
  }
2749
- async save(entry) {
2750
- this.entries.push(entry);
2751
- console.log('📋 Audit entry saved:', entry);
3031
+ createPageListConverter() {
3032
+ return this.createConverter('page-list');
2752
3033
  }
2753
- getEntries() {
2754
- return [...this.entries];
3034
+ createTabDetailsConverter() {
3035
+ return this.createConverter('tab-detail');
2755
3036
  }
2756
- getEntriesForEntity(entityName) {
2757
- return this.entries.filter(entry => entry.entityName === entityName);
2758
- }
2759
- clear() {
2760
- this.entries.length = 0;
3037
+ createTabListConverter() {
3038
+ return this.createConverter('tab-list');
2761
3039
  }
3040
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPRelatedEntityConverterFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3041
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPRelatedEntityConverterFactory, providedIn: 'root' }); }
2762
3042
  }
2763
- // Global audit storage instance
2764
- const auditStorage = new InMemoryAuditStorage();
2765
- /**
2766
- * Audit middleware that tracks all entity operations
2767
- */
2768
- const auditMiddleware = async (context, next) => {
2769
- const auditEntry = {
2770
- id: `audit_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
2771
- entityName: context.entityName,
2772
- operation: context.operation,
2773
- user: context.metadata.user?.id || 'system',
2774
- timestamp: new Date(),
2775
- requestId: context.metadata.requestId,
2776
- };
2777
- // Add operation-specific data
2778
- switch (context.operation) {
2779
- case 'insertOne':
2780
- auditEntry.changes = { created: context.input.entity };
2781
- break;
2782
- case 'updateOne':
2783
- auditEntry.entityId = context.input.id;
2784
- auditEntry.changes = { updated: context.input.keyValues };
2785
- break;
2786
- case 'deleteOne':
2787
- auditEntry.entityId = context.input.id;
2788
- auditEntry.changes = { deleted: true };
2789
- break;
2790
- case 'getOne':
2791
- auditEntry.entityId = context.input.id;
2792
- break;
2793
- case 'query':
2794
- auditEntry.metadata = { queryRequest: context.input.request };
2795
- break;
2796
- case 'initial':
2797
- auditEntry.metadata = {
2798
- collectionSize: context.input.collection?.length,
2799
- options: context.input.options
2800
- };
2801
- break;
2802
- }
2803
- try {
2804
- const result = await next(context);
2805
- // For insert operations, capture the generated ID
2806
- if (context.operation === 'insertOne' && result) {
2807
- auditEntry.entityId = result;
2808
- }
2809
- // Save audit entry
2810
- await auditStorage.save(auditEntry);
2811
- return result;
2812
- }
2813
- catch (error) {
2814
- // Save audit entry even for failed operations
2815
- auditEntry.metadata = {
2816
- ...auditEntry.metadata,
2817
- error: error instanceof Error ? error.message : 'Unknown error'
3043
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPRelatedEntityConverterFactory, decorators: [{
3044
+ type: Injectable,
3045
+ args: [{
3046
+ providedIn: 'root',
3047
+ }]
3048
+ }] });
3049
+
3050
+ class AXPMainEntityContentBuilder {
3051
+ constructor(relatedEntityConverterFactory) {
3052
+ this.relatedEntityConverterFactory = relatedEntityConverterFactory;
3053
+ this.workflowService = inject(AXPWorkflowService);
3054
+ this.commandService = inject(AXPCommandService);
3055
+ }
3056
+ async build(entity, rootContext, dependencies) {
3057
+ const groups = entity?.groups ?? [];
3058
+ const singleInterface = entity?.interfaces?.master?.single;
3059
+ const getGroupById = (id) => {
3060
+ return groups.find((s) => s.id === id);
3061
+ };
3062
+ const filterValidSections = (sections) => {
3063
+ return (sections?.filter((section) => {
3064
+ return groups.some((group) => group.id === section.id);
3065
+ }) ?? []);
3066
+ };
3067
+ const getPropertyByGroupId = (groupId) => {
3068
+ return entity?.properties.filter((p) => p.groupId === groupId) ?? [];
3069
+ };
3070
+ const getPropertyLayout = (name) => {
3071
+ return singleInterface?.properties?.find((p) => p.name === name)?.layout;
3072
+ };
3073
+ // Get related entities for tabs
3074
+ const tabDetailEntities = entity?.relatedEntities?.filter((re) => !re.hidden && re.layoutType === 'tab-detail');
3075
+ const tabListEntities = entity?.relatedEntities?.filter((re) => !re.hidden && (!re.layoutType || re.layoutType === 'tab-list'));
3076
+ // Build related tabs if dependencies are provided
3077
+ const tabDetailTabs = await this.buildTabDetails(tabDetailEntities ?? [], dependencies);
3078
+ const tabListTabs = await this.buildTabLists(tabListEntities ?? [], rootContext, dependencies);
3079
+ // Build actions from single interface
3080
+ const actions = this.buildActions(entity, singleInterface);
3081
+ // Create expression evaluator for actions
3082
+ const evaluateExpressions = dependencies?.expressionEvaluator
3083
+ ? this.createExpressionEvaluator(rootContext, dependencies.expressionEvaluator)
3084
+ : null;
3085
+ return {
3086
+ id: entity?.name ?? '',
3087
+ title: singleInterface?.title ?? entity?.formats.individual ?? '',
3088
+ label: entity?.formats.displayName ?? singleInterface?.title ?? '',
3089
+ icon: entity?.icon,
3090
+ actions: await this.buildEvaluatedActions(actions, evaluateExpressions),
3091
+ settings: {
3092
+ commands: {
3093
+ reject: {
3094
+ title: 't("discard")',
3095
+ color: 'default',
3096
+ visible: '{{context.isDirty()}}',
3097
+ command: {
3098
+ name: 'discard',
3099
+ },
3100
+ },
3101
+ accept: {
3102
+ title: 't("confirm")',
3103
+ color: 'secondary',
3104
+ visible: '{{context.isDirty()}}',
3105
+ command: {
3106
+ name: 'update-entity',
3107
+ },
3108
+ },
3109
+ },
3110
+ },
3111
+ load: async () => {
3112
+ return {
3113
+ success: true,
3114
+ result: rootContext,
3115
+ };
3116
+ },
3117
+ execute: async (e, context) => {
3118
+ if (e.name == 'update-entity') {
3119
+ const fn = entity?.commands?.update?.execute;
3120
+ const result = await fn(context);
3121
+ return {
3122
+ success: true,
3123
+ result: result,
3124
+ };
3125
+ }
3126
+ else {
3127
+ // Find action in single interface actions
3128
+ const action = actions.find((a) => a.name === e.name);
3129
+ if (action && dependencies?.workflowService) {
3130
+ // Evaluate action options with current context
3131
+ let evaluatedOptions = action.options;
3132
+ if (evaluateExpressions && action.options) {
3133
+ try {
3134
+ evaluatedOptions = await evaluateExpressions(action.options);
3135
+ }
3136
+ catch {
3137
+ // Keep original options if evaluation fails
3138
+ }
3139
+ }
3140
+ const commandName = e.name.split('&')[0];
3141
+ if (this.workflowService.exists(commandName)) {
3142
+ await this.workflowService.execute(commandName, {
3143
+ entity: getEntityInfo(entity).source,
3144
+ data: context,
3145
+ entityInfo: {
3146
+ name: entity.name,
3147
+ module: entity.module,
3148
+ title: entity.title,
3149
+ parentKey: entity.parentKey,
3150
+ source: entity.source,
3151
+ },
3152
+ options: evaluatedOptions,
3153
+ metadata: action.metadata,
3154
+ });
3155
+ return {
3156
+ success: true,
3157
+ };
3158
+ }
3159
+ if (this.commandService.exists(commandName)) {
3160
+ // check options for evaluation
3161
+ await this.commandService.execute(commandName, e.options);
3162
+ }
3163
+ }
3164
+ return {
3165
+ success: false,
3166
+ error: {
3167
+ code: 'invalid_command',
3168
+ message: 'Invalid command',
3169
+ },
3170
+ };
3171
+ }
3172
+ },
3173
+ tabs: [...tabDetailTabs, ...tabListTabs],
3174
+ content: [
3175
+ {
3176
+ type: 'grid-layout',
3177
+ mode: 'edit',
3178
+ options: {
3179
+ grid: {
3180
+ default: {
3181
+ gridTemplateColumns: 'repeat(12, 1fr)',
3182
+ gridTemplateRows: 'repeat(1, 1fr)',
3183
+ gap: '20px',
3184
+ },
3185
+ },
3186
+ },
3187
+ children: filterValidSections(singleInterface?.sections ?? []).map((s) => ({
3188
+ type: 'grid-item-layout',
3189
+ name: s.id,
3190
+ options: {
3191
+ colSpan: s.layout?.positions?.lg?.colSpan ?? 12,
3192
+ colStart: s.layout?.positions?.lg?.colStart ?? 1,
3193
+ colEnd: s.layout?.positions?.lg?.colEnd ?? 13,
3194
+ },
3195
+ children: [
3196
+ {
3197
+ type: 'fieldset-layout',
3198
+ options: {
3199
+ title: getGroupById(s.id)?.title ?? '',
3200
+ collapsible: true,
3201
+ isOpen: !s.collapsed,
3202
+ },
3203
+ children: [
3204
+ {
3205
+ type: 'grid-layout',
3206
+ options: {
3207
+ grid: {
3208
+ default: {
3209
+ gridTemplateColumns: 'repeat(12, 1fr)',
3210
+ gridTemplateRows: 'repeat(1, 1fr)',
3211
+ gap: '20px',
3212
+ },
3213
+ },
3214
+ },
3215
+ children: getPropertyByGroupId(s.id)
3216
+ .filter((property) => !property.schema.hidden)
3217
+ .map((p) => {
3218
+ const layout = getPropertyLayout(p.name);
3219
+ return {
3220
+ type: 'grid-item-layout',
3221
+ name: p.name,
3222
+ options: {
3223
+ colSpan: layout?.positions?.lg?.colSpan,
3224
+ colStart: layout?.positions?.lg?.colStart,
3225
+ colEnd: layout?.positions?.lg?.colEnd,
3226
+ },
3227
+ children: [
3228
+ {
3229
+ type: 'form-field',
3230
+ options: {
3231
+ label: p.title,
3232
+ },
3233
+ children: [
3234
+ {
3235
+ type: p.schema.interface?.type ?? '',
3236
+ path: p.name,
3237
+ name: p.name,
3238
+ defaultValue: p.schema.defaultValue,
3239
+ children: p.schema.interface?.children,
3240
+ triggers: p.schema.interface?.triggers,
3241
+ valueTransforms: p.schema.interface?.valueTransforms,
3242
+ options: merge(p.schema.interface?.options, {
3243
+ validations: p.validations?.map((c) => ({
3244
+ rule: c.rule,
3245
+ message: c.message,
3246
+ options: c.options,
3247
+ })),
3248
+ }),
3249
+ },
3250
+ ],
3251
+ },
3252
+ ],
3253
+ };
3254
+ }),
3255
+ },
3256
+ ],
3257
+ },
3258
+ ],
3259
+ })),
3260
+ },
3261
+ ],
2818
3262
  };
2819
- await auditStorage.save(auditEntry);
2820
- throw error;
2821
- }
2822
- };
2823
- /**
2824
- * User context middleware - adds user information to context
2825
- */
2826
- const userContextMiddleware = async (context, next) => {
2827
- // In a real application, you would inject your auth service here
2828
- // const authService = inject(AuthService);
2829
- // const user = authService.getCurrentUser();
2830
- // For demo purposes, we'll use a mock user
2831
- const mockUser = {
2832
- id: 'user123',
2833
- name: 'John Doe',
2834
- role: 'admin',
2835
- };
2836
- context.metadata.user = mockUser;
2837
- return next(context);
2838
- };
2839
- /**
2840
- * Data sanitization middleware - removes sensitive data from logs
2841
- */
2842
- const dataSanitizationMiddleware = async (context, next) => {
2843
- const sensitiveFields = ['password', 'ssn', 'creditCard', 'apiKey', 'token'];
2844
- // Sanitize input data
2845
- if (context.input.entity) {
2846
- context.input.entity = sanitizeObject(context.input.entity, sensitiveFields);
2847
3263
  }
2848
- if (context.input.keyValues) {
2849
- context.input.keyValues = sanitizeObject(context.input.keyValues, sensitiveFields);
3264
+ buildActions(entity, singleInterface) {
3265
+ const actions = singleInterface?.actions ?? [];
3266
+ return actions.map((action) => new AXPEntityCommandTriggerViewModel(entity, action));
2850
3267
  }
2851
- const result = await next(context);
2852
- // Sanitize result data if needed
2853
- if (result && typeof result === 'object') {
2854
- return sanitizeObject(result, sensitiveFields);
3268
+ createExpressionEvaluator(context, expressionEvaluator) {
3269
+ return async (actionData) => {
3270
+ const scope = {
3271
+ context: {
3272
+ eval: (path) => {
3273
+ return get(context, path);
3274
+ },
3275
+ },
3276
+ };
3277
+ return await expressionEvaluator.evaluate(actionData, scope);
3278
+ };
2855
3279
  }
2856
- return result;
2857
- };
2858
- /**
2859
- * Helper function to sanitize objects by removing sensitive fields
2860
- */
2861
- function sanitizeObject(obj, sensitiveFields) {
2862
- if (!obj || typeof obj !== 'object') {
2863
- return obj;
3280
+ async buildEvaluatedActions(actions, evaluateExpressions) {
3281
+ const evaluatedActions = [];
3282
+ for (const action of actions) {
3283
+ // Evaluate disabled condition
3284
+ let disabled = action.disabled;
3285
+ if (disabled && typeof disabled === 'string' && evaluateExpressions) {
3286
+ try {
3287
+ const result = await evaluateExpressions({ disabled: disabled });
3288
+ disabled = result.disabled;
3289
+ }
3290
+ catch {
3291
+ disabled = false;
3292
+ }
3293
+ }
3294
+ // Evaluate hidden condition
3295
+ let hidden = action.hidden;
3296
+ if (hidden && typeof hidden === 'string' && evaluateExpressions) {
3297
+ try {
3298
+ const result = await evaluateExpressions({ hidden: hidden });
3299
+ hidden = result.hidden;
3300
+ }
3301
+ catch {
3302
+ hidden = false;
3303
+ }
3304
+ }
3305
+ // Skip if hidden
3306
+ if (hidden)
3307
+ continue;
3308
+ // Evaluate options
3309
+ let options = action.options;
3310
+ if (options && evaluateExpressions) {
3311
+ try {
3312
+ options = await evaluateExpressions(options);
3313
+ }
3314
+ catch {
3315
+ // Keep original options if evaluation fails
3316
+ }
3317
+ }
3318
+ evaluatedActions.push({
3319
+ name: action.name,
3320
+ title: action.title,
3321
+ icon: action.icon,
3322
+ color: action.color,
3323
+ disabled: disabled || false,
3324
+ zone: 'header',
3325
+ priority: action.priority,
3326
+ command: {
3327
+ name: action.name,
3328
+ options: options,
3329
+ metadata: action.metadata,
3330
+ },
3331
+ });
3332
+ }
3333
+ return evaluatedActions;
2864
3334
  }
2865
- if (Array.isArray(obj)) {
2866
- return obj.map(item => sanitizeObject(item, sensitiveFields));
3335
+ async buildTabDetails(tabDetailEntities, dependencies) {
3336
+ if (!dependencies?.entityResolver || !tabDetailEntities?.length) {
3337
+ return [];
3338
+ }
3339
+ const tabs = [];
3340
+ for (const relatedEntity of tabDetailEntities) {
3341
+ const converter = this.relatedEntityConverterFactory.createTabDetailsConverter();
3342
+ tabs.push(await converter.convert(relatedEntity, {
3343
+ entityResolver: dependencies.entityResolver,
3344
+ }));
3345
+ }
3346
+ return tabs;
2867
3347
  }
2868
- const sanitized = { ...obj };
2869
- for (const field of sensitiveFields) {
2870
- if (field in sanitized) {
2871
- sanitized[field] = '[REDACTED]';
3348
+ async buildTabLists(tabListEntities, rootContext, dependencies) {
3349
+ if (!dependencies?.entityResolver || !tabListEntities?.length) {
3350
+ return [];
3351
+ }
3352
+ const tabs = [];
3353
+ for (const relatedEntity of tabListEntities) {
3354
+ const converter = this.relatedEntityConverterFactory.createTabListConverter();
3355
+ tabs.push(await converter.convert(relatedEntity, {
3356
+ entityResolver: dependencies.entityResolver,
3357
+ expressionEvaluator: dependencies.expressionEvaluator,
3358
+ context: rootContext,
3359
+ }));
2872
3360
  }
3361
+ return tabs;
2873
3362
  }
2874
- // Recursively sanitize nested objects
2875
- for (const [key, value] of Object.entries(sanitized)) {
2876
- if (value && typeof value === 'object') {
2877
- sanitized[key] = sanitizeObject(value, sensitiveFields);
3363
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMainEntityContentBuilder, deps: [{ token: AXPRelatedEntityConverterFactory }], target: i0.ɵɵFactoryTarget.Injectable }); }
3364
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMainEntityContentBuilder, providedIn: 'root' }); }
3365
+ }
3366
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMainEntityContentBuilder, decorators: [{
3367
+ type: Injectable,
3368
+ args: [{
3369
+ providedIn: 'root',
3370
+ }]
3371
+ }], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }] });
3372
+
3373
+ class AXPLayoutAdapterFactory {
3374
+ constructor(relatedEntityConverterFactory, mainEntityContentBuilder, layoutAdapterBuilder) {
3375
+ this.relatedEntityConverterFactory = relatedEntityConverterFactory;
3376
+ this.mainEntityContentBuilder = mainEntityContentBuilder;
3377
+ this.layoutAdapterBuilder = layoutAdapterBuilder;
3378
+ }
3379
+ async createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies) {
3380
+ const entity = await entityResolver.resolve(moduleName, entityName);
3381
+ if (!entity) {
3382
+ throw new Error(`Entity ${moduleName}.${entityName} not found`);
3383
+ }
3384
+ const rootContext = await this.loadRootContext(entity, id);
3385
+ return this.layoutAdapterBuilder
3386
+ .setEntity(entity, rootContext)
3387
+ .setDependencies(dependencies)
3388
+ .setMainPage(await this.buildMainPage(entity, rootContext, dependencies))
3389
+ .setRelatedPages(await this.buildRelatedPages(entity, rootContext, dependencies))
3390
+ .build();
3391
+ }
3392
+ async loadRootContext(entity, id) {
3393
+ const fn = entity?.queries.byKey?.execute;
3394
+ return await fn(id);
3395
+ }
3396
+ async buildMainPage(entity, rootContext, dependencies) {
3397
+ return this.mainEntityContentBuilder.build(entity, rootContext, dependencies);
3398
+ }
3399
+ async buildRelatedPages(entity, rootContext, dependencies) {
3400
+ const pages = [];
3401
+ // Page Details
3402
+ const pageDetailEntities = entity?.relatedEntities?.filter((re) => !re.hidden && re.layoutType === 'page-detail');
3403
+ for (const relatedEntity of pageDetailEntities || []) {
3404
+ const converter = this.relatedEntityConverterFactory.createPageDetailsConverter();
3405
+ pages.push(await converter.convert(relatedEntity, { entityResolver: dependencies.entityResolver }));
2878
3406
  }
3407
+ // Page Lists
3408
+ const pageListEntities = entity?.relatedEntities?.filter((re) => !re.hidden && re.layoutType === 'page-list');
3409
+ for (const relatedEntity of pageListEntities || []) {
3410
+ const converter = this.relatedEntityConverterFactory.createPageListConverter();
3411
+ pages.push(await converter.convert(relatedEntity, {
3412
+ ...dependencies,
3413
+ context: rootContext,
3414
+ rootTitle: await this.getRootTitle(entity, rootContext, dependencies),
3415
+ }));
3416
+ }
3417
+ return pages;
2879
3418
  }
2880
- return sanitized;
3419
+ async getRootTitle(entity, rootContext, dependencies) {
3420
+ // Logic for getting root title
3421
+ return await dependencies.expressionEvaluator.evaluate(entity.interfaces?.master?.single?.title, rootContext);
3422
+ }
3423
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterFactory, deps: [{ token: AXPRelatedEntityConverterFactory }, { token: AXPMainEntityContentBuilder }, { token: AXPLayoutAdapterBuilder }], target: i0.ɵɵFactoryTarget.Injectable }); }
3424
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterFactory, providedIn: 'root' }); }
2881
3425
  }
3426
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterFactory, decorators: [{
3427
+ type: Injectable,
3428
+ args: [{
3429
+ providedIn: 'root',
3430
+ }]
3431
+ }], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }, { type: AXPMainEntityContentBuilder }, { type: AXPLayoutAdapterBuilder }] });
2882
3432
 
2883
- // Core middleware types and utilities
3433
+ const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver = inject(AXPEntityDefinitionRegistryService), expressionEvaluator = inject(AXPExpressionEvaluatorService), session = inject(AXPSessionService), formatService = inject(AXFormatService), workflowService = inject(AXPWorkflowService), layoutAdapterFactory = inject(AXPLayoutAdapterFactory)) => {
3434
+ const moduleName = route.parent?.paramMap.get('module');
3435
+ const entityName = route.paramMap.get('entity');
3436
+ const id = route.paramMap.get('id');
3437
+ const dependencies = {
3438
+ entityResolver,
3439
+ expressionEvaluator,
3440
+ session,
3441
+ formatService,
3442
+ workflowService,
3443
+ };
3444
+ return await layoutAdapterFactory.createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies);
3445
+ };
2884
3446
 
2885
3447
  class AXPEntityCommandSearchDefinitionProvider {
2886
3448
  async provide(context) {
@@ -2924,6 +3486,944 @@ class AXPEntitySearchDefinitionProvider {
2924
3486
  }
2925
3487
  }
2926
3488
 
3489
+ class AXPEntityListTableService {
3490
+ constructor() {
3491
+ //#region ---- Services & Dependencies ----
3492
+ this.entityResolver = inject(AXPEntityResolver);
3493
+ this.workflow = inject(AXPWorkflowService);
3494
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
3495
+ this.evaluateExpressions = async (options, data) => {
3496
+ const scope = {
3497
+ context: {
3498
+ eval: (path) => {
3499
+ return get(data, path);
3500
+ },
3501
+ },
3502
+ };
3503
+ return await this.expressionEvaluator.evaluate(options, scope);
3504
+ };
3505
+ }
3506
+ //#endregion
3507
+ //#region ---- Public Methods ----
3508
+ /**
3509
+ * Convert Entity to List Widget Options
3510
+ */
3511
+ async convertEntityToListOptions(entity, options) {
3512
+ const allActions = entity.interfaces?.master?.list?.actions?.map((tr) => new AXPEntityCommandTriggerViewModel(entity, tr)) ?? [];
3513
+ const listOptions = {
3514
+ // 📊 Data Source
3515
+ dataSource: this.createDataSource(entity),
3516
+ // 📋 Columns from Properties
3517
+ columns: this.createColumnsFromProperties(entity, options),
3518
+ // 🎯 Row Commands from Actions
3519
+ primaryCommands: this.createRowCommands(allActions, 'primary'),
3520
+ secondaryCommands: this.createRowCommands(allActions, 'secondary'),
3521
+ // ⚙️ Table Features
3522
+ showIndex: entity.interfaces?.master?.list?.views?.[0]?.indexCol ?? false,
3523
+ allowSelection: this.hasSelectedScopeActions(entity),
3524
+ paging: true,
3525
+ showHeader: true,
3526
+ showFooter: false,
3527
+ // 🔗 Entity Configuration
3528
+ parentField: entity.parentKey,
3529
+ fetchDataMode: 'manual',
3530
+ minHeight: 250,
3531
+ // 🎪 Events
3532
+ ...this.createDefaultEvents(entity, allActions),
3533
+ };
3534
+ return listOptions;
3535
+ }
3536
+ //#endregion
3537
+ //#region ---- Private Methods ----
3538
+ /**
3539
+ * Create DataSource for Entity
3540
+ */
3541
+ createDataSource(entity) {
3542
+ return new AXDataSource({
3543
+ byKey: (key) => {
3544
+ const func = entity.queries.byKey.execute;
3545
+ return func(key);
3546
+ },
3547
+ load: (e) => {
3548
+ const func = entity.queries.list?.execute;
3549
+ if (!func) {
3550
+ throw new Error(`Entity ${entity.name} does not have a list query`);
3551
+ }
3552
+ return func(e);
3553
+ },
3554
+ pageSize: entity.interfaces?.master?.list?.views?.[0]?.pageSize || 10,
3555
+ key: 'id',
3556
+ });
3557
+ }
3558
+ /**
3559
+ * Convert Properties to Columns
3560
+ */
3561
+ createColumnsFromProperties(entity, options) {
3562
+ const excludeColumns = options?.excludeColumns || [];
3563
+ const includeColumns = options?.includeColumns || [];
3564
+ let columns = [];
3565
+ // If columns are defined, use them
3566
+ if (entity.columns && entity.columns.length > 0) {
3567
+ columns = entity.columns.map((col) => this.mapEntityColumnToWidgetColumn(entity, col));
3568
+ }
3569
+ else {
3570
+ // Otherwise use properties
3571
+ columns = entity.properties
3572
+ .filter((prop) => !prop.schema.hidden) // Only visible properties
3573
+ .map((prop) => ({
3574
+ name: prop.name,
3575
+ title: prop.title,
3576
+ visible: true,
3577
+ widget: prop.schema.interface
3578
+ ? {
3579
+ type: prop.schema.interface.type || 'text-editor',
3580
+ path: prop.name,
3581
+ options: {
3582
+ readonly: true,
3583
+ ...prop.schema.interface.options,
3584
+ },
3585
+ }
3586
+ : {
3587
+ type: 'text-editor',
3588
+ path: prop.name,
3589
+ options: { readonly: true },
3590
+ },
3591
+ }));
3592
+ }
3593
+ // Apply include/exclude filters
3594
+ if (includeColumns.length > 0) {
3595
+ // If includeColumns is specified, only include those columns
3596
+ columns = columns.filter((col) => includeColumns.includes(col.name));
3597
+ }
3598
+ if (excludeColumns.length > 0) {
3599
+ // If excludeColumns is specified, exclude those columns
3600
+ columns = columns.filter((col) => !excludeColumns.includes(col.name));
3601
+ }
3602
+ return columns;
3603
+ }
3604
+ /**
3605
+ * Map EntityTableColumn to ListWidgetColumn
3606
+ */
3607
+ mapEntityColumnToWidgetColumn(entity, column) {
3608
+ // Find corresponding property
3609
+ const property = entity.properties.find((p) => p.name === column.name);
3610
+ return {
3611
+ name: column.name,
3612
+ title: column.title || property?.title || column.name,
3613
+ width: column.options?.width,
3614
+ visible: column.options?.visible !== false,
3615
+ widget: property?.schema.interface
3616
+ ? {
3617
+ type: property.schema.interface.type || 'text-editor',
3618
+ path: column.options?.dataPath || column.name,
3619
+ options: {
3620
+ readonly: true,
3621
+ ...property.schema.interface.options,
3622
+ },
3623
+ }
3624
+ : {
3625
+ type: 'text-editor',
3626
+ path: column.options?.dataPath || column.name,
3627
+ options: { readonly: true },
3628
+ },
3629
+ };
3630
+ }
3631
+ /**
3632
+ * Convert Entity Actions to Row Commands
3633
+ */
3634
+ createRowCommands(actions, priority) {
3635
+ return actions
3636
+ .filter((action) => action.scope === AXPEntityCommandScope.Individual && // Only individual actions
3637
+ action.priority === priority && // Matching priority
3638
+ !action.hidden)
3639
+ .map((action) => ({
3640
+ name: action.name,
3641
+ text: action.title,
3642
+ icon: action.icon,
3643
+ color: action.color,
3644
+ look: 'outline',
3645
+ visible: action.hidden,
3646
+ disabled: action.disabled,
3647
+ }));
3648
+ }
3649
+ /**
3650
+ * Check if entity has Selected Scope Actions
3651
+ */
3652
+ hasSelectedScopeActions(entity) {
3653
+ const actions = entity.interfaces?.master?.list?.actions || [];
3654
+ return actions.some((action) => action.scope === AXPEntityCommandScope.Selected);
3655
+ }
3656
+ /**
3657
+ * Create default events
3658
+ */
3659
+ createDefaultEvents(entity, allActions) {
3660
+ return {
3661
+ onRowClick: (row) => {
3662
+ console.log('Entity List - Row clicked:', row);
3663
+ },
3664
+ onRowDoubleClick: (row) => {
3665
+ console.log('Entity List - Row double clicked:', row);
3666
+ },
3667
+ onSelectionChange: (selectedRows) => {
3668
+ console.log('Entity List - Selection changed:', selectedRows);
3669
+ },
3670
+ onRowCommand: async (e, selectedRows) => {
3671
+ const data = e.data;
3672
+ const commandName = e.name;
3673
+ const action = allActions.find((c) => {
3674
+ return (c.name == e.name &&
3675
+ ((selectedRows?.length
3676
+ ? c.scope == AXPEntityCommandScope.Selected
3677
+ : c.scope == AXPEntityCommandScope.Individual) ||
3678
+ c.scope == AXPEntityCommandScope.TypeLevel));
3679
+ });
3680
+ const command = commandName.split('&')[0];
3681
+ const options = await this.evaluateExpressions(action?.options, data);
3682
+ await this.workflow.execute(command, {
3683
+ entity: getEntityInfo(entity).source,
3684
+ entityInfo: {
3685
+ name: entity.name,
3686
+ module: entity.module,
3687
+ title: entity.title,
3688
+ parentKey: entity.parentKey,
3689
+ source: entity.source,
3690
+ },
3691
+ data: action?.scope == AXPEntityCommandScope.Selected ? selectedRows : data,
3692
+ options: options,
3693
+ metadata: action?.metadata,
3694
+ });
3695
+ console.log('Entity List - Row command:', e.name, e.data);
3696
+ },
3697
+ };
3698
+ }
3699
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListTableService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3700
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListTableService }); }
3701
+ }
3702
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListTableService, decorators: [{
3703
+ type: Injectable
3704
+ }] });
3705
+
3706
+ class AXPEntityListToolbarService {
3707
+ constructor() {
3708
+ //#region ---- Services & Dependencies ----
3709
+ this.widgetResolver = inject(AXPWidgetRegistryService);
3710
+ }
3711
+ //#endregion
3712
+ //#region ---- Public Methods ----
3713
+ /**
3714
+ * Convert Entity to Toolbar Options
3715
+ */
3716
+ async convertEntityToolbarOptions(entity, options) {
3717
+ const toolbarOptions = {
3718
+ filterDefinitions: this.createFilterDefinitions(entity),
3719
+ columnDefinitions: this.createColumnDefinitions(entity, options),
3720
+ sortDefinitions: this.createSortDefinitions(entity),
3721
+ };
3722
+ return toolbarOptions;
3723
+ }
3724
+ //#endregion
3725
+ //#region ---- Private Methods ----
3726
+ /**
3727
+ * Create Filter Definitions for Toolbar
3728
+ */
3729
+ createFilterDefinitions(entity) {
3730
+ const props = entity.properties.filter((c) => c.options?.filter?.advance?.enabled || c.options?.filter?.inline?.enabled);
3731
+ return props.map((e) => {
3732
+ const widgetConfig = this.widgetResolver.resolve(e.schema.interface?.type);
3733
+ const type = (e.options?.filter?.advance?.widgetType ||
3734
+ widgetConfig?.defaultFilterWidgetName ||
3735
+ e.schema.interface?.type);
3736
+ return {
3737
+ title: e.title,
3738
+ field: e.name,
3739
+ operator: {
3740
+ type: 'contains',
3741
+ },
3742
+ widget: { ...e.schema.interface, path: e.name, type },
3743
+ filters: [],
3744
+ isParametric: false,
3745
+ icon: widgetConfig?.icon,
3746
+ filterType: {
3747
+ advance: e.options?.filter?.advance?.enabled ?? false,
3748
+ inline: e.options?.filter?.inline?.enabled ?? false,
3749
+ },
3750
+ };
3751
+ });
3752
+ }
3753
+ /**
3754
+ * Create Column Definitions for Toolbar
3755
+ */
3756
+ createColumnDefinitions(entity, options) {
3757
+ const { columns = [], properties } = entity;
3758
+ const excludeColumns = options?.excludeColumns || [];
3759
+ const includeColumns = options?.includeColumns || [];
3760
+ const visibleProperties = properties.filter(({ schema }) => !schema?.hidden);
3761
+ const visiblePropNames = new Set(visibleProperties.map(({ name }) => name));
3762
+ let filteredColumns = columns.filter(({ name }) => visiblePropNames.has(name));
3763
+ // Apply include/exclude filters
3764
+ if (includeColumns.length > 0) {
3765
+ // If includeColumns is specified, only include those columns
3766
+ filteredColumns = filteredColumns.filter((col) => includeColumns.includes(col.name));
3767
+ }
3768
+ if (excludeColumns.length > 0) {
3769
+ // If excludeColumns is specified, exclude those columns
3770
+ filteredColumns = filteredColumns.filter((col) => !excludeColumns.includes(col.name));
3771
+ }
3772
+ return filteredColumns.map((column) => {
3773
+ const property = visibleProperties.find(({ name }) => name === column.name);
3774
+ return {
3775
+ name: column.name,
3776
+ title: property?.title,
3777
+ visible: column?.options?.visible ?? true,
3778
+ };
3779
+ });
3780
+ }
3781
+ /**
3782
+ * Create Sort Definitions for Toolbar
3783
+ */
3784
+ createSortDefinitions(entity) {
3785
+ const props = entity.properties.filter((c) => c.options?.sort?.enabled);
3786
+ return props.map((e) => {
3787
+ return {
3788
+ name: e.name,
3789
+ title: e.title,
3790
+ };
3791
+ });
3792
+ }
3793
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListToolbarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3794
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListToolbarService }); }
3795
+ }
3796
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListToolbarService, decorators: [{
3797
+ type: Injectable
3798
+ }] });
3799
+
3800
+ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
3801
+ constructor() {
3802
+ super(...arguments);
3803
+ this.entityResolver = inject(AXPEntityResolver);
3804
+ this.workflow = inject(AXPWorkflowService);
3805
+ this.entityListTableService = inject(AXPEntityListTableService);
3806
+ this.entityListToolbarService = inject(AXPEntityListToolbarService);
3807
+ this.layoutThemeService = inject(AXPLayoutThemeService);
3808
+ this.container = viewChild(AXPWidgetContainerComponent, ...(ngDevMode ? [{ debugName: "container" }] : []));
3809
+ this.isMounted = signal(false, ...(ngDevMode ? [{ debugName: "isMounted" }] : []));
3810
+ this.entity = signal(null, ...(ngDevMode ? [{ debugName: "entity" }] : []));
3811
+ this.listNode = signal(null, ...(ngDevMode ? [{ debugName: "listNode" }] : []));
3812
+ this.list = viewChild('list', ...(ngDevMode ? [{ debugName: "list" }] : []));
3813
+ this.allWidgets = viewChildren(AXPWidgetRendererDirective, ...(ngDevMode ? [{ debugName: "allWidgets" }] : []));
3814
+ this.listWidget = linkedSignal(() => this.allWidgets().find((widget) => widget.node()?.type === AXPWidgetsCatalog.list));
3815
+ this.toolbarWidget = computed(() => this.allWidgets().find((widget) => widget.node()?.type === AXPWidgetsCatalog.listToolbar), ...(ngDevMode ? [{ debugName: "toolbarWidget" }] : []));
3816
+ this.selectedItems = computed(() => this.getValue()?.table || [], ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
3817
+ this.toolbarNode = signal(null, ...(ngDevMode ? [{ debugName: "toolbarNode" }] : []));
3818
+ this.destroyed = new Subject();
3819
+ //options
3820
+ this.entitySource = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entitySource" }] : []));
3821
+ this.excludeColumns = computed(() => this.options()['excludeColumns'], ...(ngDevMode ? [{ debugName: "excludeColumns" }] : []));
3822
+ this.includeColumns = computed(() => this.options()['includeColumns'], ...(ngDevMode ? [{ debugName: "includeColumns" }] : []));
3823
+ this.showEntityActions = computed(() => this.options()['showEntityActions'] ?? true, ...(ngDevMode ? [{ debugName: "showEntityActions" }] : []));
3824
+ this.showToolbar = computed(() => this.options()['showToolbar'] ?? true, ...(ngDevMode ? [{ debugName: "showToolbar" }] : []));
3825
+ //actions
3826
+ this.allActions = computed(() => {
3827
+ const list = this.entity()?.interfaces?.master?.list?.actions ?? [];
3828
+ return list.map((tr) => new AXPEntityCommandTriggerViewModel(this.entity(), tr)) ?? [];
3829
+ }, ...(ngDevMode ? [{ debugName: "allActions" }] : []));
3830
+ this.primaryActions = computed(() => {
3831
+ const actions = this.allActions()
3832
+ .filter((a) => a.priority == 'primary' &&
3833
+ ((a.scope == AXPEntityCommandScope.Selected && this.selectedItems().length) ||
3834
+ (a.scope == AXPEntityCommandScope.TypeLevel && !this.selectedItems().length)))
3835
+ .map((tr) => ({
3836
+ name: tr.name,
3837
+ title: tr.title,
3838
+ icon: tr.icon,
3839
+ color: tr.color,
3840
+ disabled: tr.disabled,
3841
+ command: {
3842
+ name: tr.name,
3843
+ options: tr.options,
3844
+ metadata: tr.metadata,
3845
+ },
3846
+ }));
3847
+ return actions;
3848
+ }, ...(ngDevMode ? [{ debugName: "primaryActions" }] : []));
3849
+ this.secondaryActions = computed(() => {
3850
+ const actions = this.allActions()
3851
+ .filter((a) => a.priority == 'secondary' && a.scope == AXPEntityCommandScope.TypeLevel)
3852
+ .map((tr) => ({
3853
+ name: tr.name,
3854
+ title: tr.title,
3855
+ icon: tr.icon,
3856
+ color: tr.color,
3857
+ disabled: tr.disabled,
3858
+ separated: tr.separated,
3859
+ command: {
3860
+ name: tr.name,
3861
+ options: tr.options,
3862
+ metadata: tr.metadata,
3863
+ },
3864
+ }));
3865
+ return actions;
3866
+ }, ...(ngDevMode ? [{ debugName: "secondaryActions" }] : []));
3867
+ //#region ---- Query Change Handler ----
3868
+ this.#effect = effect(() => {
3869
+ const queries = this.getValue()?.toolbar;
3870
+ const listInstance = this.listWidget()?.instance;
3871
+ const dataSource = this.listWidget()?.options()['dataSource'];
3872
+ const isMounted = this.isMounted();
3873
+ if (!this.hasRequiredDependencies(dataSource, queries, listInstance)) {
3874
+ return;
3875
+ }
3876
+ untracked(() => {
3877
+ this.handleQueryChanges(queries, dataSource, listInstance, isMounted);
3878
+ });
3879
+ }, ...(ngDevMode ? [{ debugName: "#effect" }] : []));
3880
+ //#endregion
3881
+ this.context = {};
3882
+ this.previousQueries = null;
3883
+ }
3884
+ handleActionClick(item) {
3885
+ if (item.command && (item.items?.length ?? 0) == 0) {
3886
+ this.execute(item.command.name, null);
3887
+ }
3888
+ }
3889
+ handleSecondaryActionClick(item) {
3890
+ if (item.command) {
3891
+ this.execute(item.command.name, null);
3892
+ }
3893
+ }
3894
+ // ngDoCheck(): void {
3895
+ // console.log(this.listWidget()?.instance.output('selectedRows'));
3896
+ // }
3897
+ async execute(commandName, data) {
3898
+ const action = this.allActions().find((c) => {
3899
+ return (c.name == commandName &&
3900
+ ((this.selectedItems().length
3901
+ ? c.scope == AXPEntityCommandScope.Selected
3902
+ : c.scope == AXPEntityCommandScope.Individual) ||
3903
+ c.scope == AXPEntityCommandScope.TypeLevel));
3904
+ });
3905
+ const command = commandName.split('&')[0];
3906
+ // const options = await this.evaluateExpressions(action?.options, data);
3907
+ await this.workflow.execute(command, {
3908
+ entity: this.entitySource(),
3909
+ entityInfo: {
3910
+ name: this.entity()?.name,
3911
+ module: this.entity()?.module,
3912
+ title: this.entity()?.title,
3913
+ parentKey: this.entity()?.parentKey,
3914
+ source: this.entity()?.source,
3915
+ },
3916
+ data: action?.scope == AXPEntityCommandScope.Selected ? this.selectedItems() : data,
3917
+ options: action?.options,
3918
+ metadata: action?.metadata,
3919
+ });
3920
+ }
3921
+ //#region ---- Query Change Handler ----
3922
+ #effect;
3923
+ /**
3924
+ * Validates that all required dependencies are available
3925
+ */
3926
+ hasRequiredDependencies(dataSource, queries, listInstance) {
3927
+ return !!(dataSource && queries && listInstance);
3928
+ }
3929
+ /**
3930
+ * Handles all query-related changes (filters, sorts, columns)
3931
+ */
3932
+ handleQueryChanges(queries, dataSource, listInstance, isMounted) {
3933
+ const changeTracker = this.analyzeChanges(queries);
3934
+ this.previousQueries = queries;
3935
+ this.applyDataSourceChanges(dataSource, queries, changeTracker);
3936
+ this.handleListRefresh(listInstance, changeTracker, isMounted);
3937
+ this.handleColumnChanges(changeTracker);
3938
+ }
3939
+ /**
3940
+ * Analyzes what has changed between current and previous queries
3941
+ */
3942
+ analyzeChanges(queries) {
3943
+ const changes = getChangedPaths(queries, this.previousQueries);
3944
+ return {
3945
+ isFilterChanged: changes.includes('filters'),
3946
+ isSortChanged: changes.includes('sorts'),
3947
+ isColumnsChanged: changes.includes('columns'),
3948
+ hasAnyChange: changes.length > 0,
3949
+ };
3950
+ }
3951
+ /**
3952
+ * Applies filter and sort changes to the data source
3953
+ */
3954
+ applyDataSourceChanges(dataSource, queries, changeTracker) {
3955
+ if (changeTracker.isFilterChanged) {
3956
+ dataSource.filter({
3957
+ filters: queries?.filters,
3958
+ });
3959
+ }
3960
+ if (changeTracker.isSortChanged) {
3961
+ dataSource.sort(...(queries.sorts || []));
3962
+ }
3963
+ }
3964
+ /**
3965
+ * Handles list refresh logic based on changes and mount status
3966
+ */
3967
+ handleListRefresh(listInstance, changeTracker, isMounted) {
3968
+ const shouldRefresh = changeTracker.isFilterChanged || changeTracker.isSortChanged || !isMounted;
3969
+ if (shouldRefresh) {
3970
+ listInstance.call('refresh');
3971
+ // Set mounted flag only on initial load (not when filters/sorts change)
3972
+ if (!changeTracker.isFilterChanged && !changeTracker.isSortChanged) {
3973
+ this.isMounted.set(true);
3974
+ }
3975
+ }
3976
+ }
3977
+ /**
3978
+ * Handles column-related changes
3979
+ * TODO: Implement column change logic
3980
+ */
3981
+ handleColumnChanges(changeTracker) {
3982
+ if (changeTracker.isColumnsChanged) {
3983
+ // TODO: Implement column change handling
3984
+ console.log('Column changes detected - implementation needed');
3985
+ }
3986
+ }
3987
+ async ngOnInit() {
3988
+ super.ngOnInit();
3989
+ const [moduleName, entityName] = this.entitySource().split('.');
3990
+ if (!moduleName || !entityName) {
3991
+ throw new Error('Invalid entity source');
3992
+ }
3993
+ // Resolve entity and set it in the signal
3994
+ const resolvedEntity = await this.entityResolver.get(moduleName, entityName);
3995
+ if (!resolvedEntity) {
3996
+ throw new Error(`Entity not found: ${this.entitySource()}`);
3997
+ }
3998
+ this.entity.set(resolvedEntity);
3999
+ const options = {
4000
+ excludeColumns: this.excludeColumns(),
4001
+ includeColumns: this.includeColumns(),
4002
+ };
4003
+ const listOptions = await this.entityListTableService.convertEntityToListOptions(resolvedEntity, options);
4004
+ const toolbarOptions = await this.entityListToolbarService.convertEntityToolbarOptions(resolvedEntity, options);
4005
+ this.listNode.set({
4006
+ type: AXPWidgetsCatalog.list,
4007
+ options: listOptions,
4008
+ path: `table`,
4009
+ name: 'table',
4010
+ mode: 'view',
4011
+ defaultValue: this.getValue()?.table,
4012
+ });
4013
+ this.toolbarNode.set({
4014
+ type: AXPWidgetsCatalog.listToolbar,
4015
+ path: `toolbar`,
4016
+ options: toolbarOptions,
4017
+ mode: 'view',
4018
+ defaultValue: {
4019
+ filters: this.getValue()?.toolbar?.filters,
4020
+ sorts: this.getValue()?.toolbar?.sorts,
4021
+ columns: this.getValue()?.toolbar?.columns,
4022
+ },
4023
+ });
4024
+ }
4025
+ ngAfterViewInit() {
4026
+ this.workflow.events$
4027
+ .pipe(ofType(AXPRefreshEvent))
4028
+ .pipe(takeUntil(this.destroyed))
4029
+ .subscribe((event) => {
4030
+ if (event.payload.entity == this.entitySource()) {
4031
+ this.listWidget()?.instance.call('refresh');
4032
+ }
4033
+ });
4034
+ }
4035
+ ngOnDestroy() {
4036
+ this.listWidget.set(undefined);
4037
+ this.destroyed.next();
4038
+ this.destroyed.complete();
4039
+ }
4040
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4041
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: AXPEntityListWidgetViewComponent, isStandalone: true, selector: "ng-component", host: { properties: { "class": "\"ax-h-full\"" } }, providers: [AXPEntityListTableService, AXPEntityListToolbarService], viewQueries: [{ propertyName: "container", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }, { propertyName: "list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "allWidgets", predicate: AXPWidgetRendererDirective, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
4042
+ @if (showEntityActions()) {
4043
+ <div class="ax-flex ax-gap-2 ax-justify-end ax-mb-4">
4044
+ @for (action of primaryActions(); track $index) {
4045
+ @if (action.visible != false) {
4046
+ <ax-button
4047
+ [class.ax-sm]="layoutThemeService.isSmall()"
4048
+ [iconOnly]="layoutThemeService.isSmall()"
4049
+ [disabled]="action.disabled"
4050
+ [text]="action.title"
4051
+ [look]="'solid'"
4052
+ [color]="action.color"
4053
+ (onClick)="handleActionClick(action)"
4054
+ >
4055
+ <ax-prefix>
4056
+ <i class="{{ action.icon }}"></i>
4057
+ </ax-prefix>
4058
+ @if (action?.items) {
4059
+ <ax-dropdown-panel #panel>
4060
+ <ax-button-item-list>
4061
+ @for (sub of action?.items; track $index) {
4062
+ @if (sub.visible != false) {
4063
+ <ax-button-item
4064
+ [text]="sub.title"
4065
+ [color]="sub.color"
4066
+ [disabled]="sub.disabled"
4067
+ (onClick)="handleActionClick(sub)"
4068
+ >
4069
+ <ax-prefix>
4070
+ <ax-icon icon="fa-light {{ sub.icon }}"></ax-icon>
4071
+ </ax-prefix>
4072
+ </ax-button-item>
4073
+ @if (sub.break) {
4074
+ <ax-divider></ax-divider>
4075
+ }
4076
+ }
4077
+ }
4078
+ </ax-button-item-list>
4079
+ </ax-dropdown-panel>
4080
+ }
4081
+ </ax-button>
4082
+ }
4083
+ }
4084
+ @if (secondaryActions().length) {
4085
+ <ax-button
4086
+ [class.ax-sm]="layoutThemeService.isSmall()"
4087
+ [iconOnly]="layoutThemeService.isSmall()"
4088
+ [text]="'actions'"
4089
+ [look]="layoutThemeService.isSmall() ? 'blank' : 'solid'"
4090
+ [color]="'default'"
4091
+ >
4092
+ <ax-prefix>
4093
+ <i class="fa-solid fa-ellipsis-vertical"></i>
4094
+ </ax-prefix>
4095
+ <ax-dropdown-panel #panel>
4096
+ <ax-button-item-list>
4097
+ @for (item of secondaryActions(); track $index) {
4098
+ @if (item.visible != false) {
4099
+ <ax-button-item
4100
+ [text]="item.title"
4101
+ [color]="item.color"
4102
+ [disabled]="item.disabled"
4103
+ (onClick)="handleSecondaryActionClick(item)"
4104
+ >
4105
+ <ax-prefix>
4106
+ <ax-icon icon="fa-light {{ item.icon }}"></ax-icon>
4107
+ </ax-prefix>
4108
+ </ax-button-item>
4109
+ @if (item.break) {
4110
+ <ax-divider></ax-divider>
4111
+ }
4112
+ }
4113
+ }
4114
+ </ax-button-item-list>
4115
+ </ax-dropdown-panel>
4116
+ </ax-button>
4117
+ }
4118
+ </div>
4119
+ }
4120
+ <div class="ax-flex ax-flex-col ax-gap-2 ax-h-full">
4121
+ @if (toolbarNode() != null && showToolbar()) {
4122
+ <ng-container
4123
+ #toolbar
4124
+ axp-widget-renderer
4125
+ [node]="toolbarNode()!"
4126
+ [parentNode]="this"
4127
+ [index]="index"
4128
+ [mode]="this.mode"
4129
+ ></ng-container>
4130
+ }
4131
+ @if (listNode() != null) {
4132
+ <ng-container
4133
+ #list
4134
+ axp-widget-renderer
4135
+ [node]="listNode()!"
4136
+ [parentNode]="this"
4137
+ [index]="index"
4138
+ [mode]="this.mode"
4139
+ ></ng-container>
4140
+ }
4141
+ </div>
4142
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXPLayoutBuilderModule }, { kind: "directive", type: i2.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i3$1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i3$1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i4.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4143
+ }
4144
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListWidgetViewComponent, decorators: [{
4145
+ type: Component,
4146
+ args: [{
4147
+ template: `
4148
+ @if (showEntityActions()) {
4149
+ <div class="ax-flex ax-gap-2 ax-justify-end ax-mb-4">
4150
+ @for (action of primaryActions(); track $index) {
4151
+ @if (action.visible != false) {
4152
+ <ax-button
4153
+ [class.ax-sm]="layoutThemeService.isSmall()"
4154
+ [iconOnly]="layoutThemeService.isSmall()"
4155
+ [disabled]="action.disabled"
4156
+ [text]="action.title"
4157
+ [look]="'solid'"
4158
+ [color]="action.color"
4159
+ (onClick)="handleActionClick(action)"
4160
+ >
4161
+ <ax-prefix>
4162
+ <i class="{{ action.icon }}"></i>
4163
+ </ax-prefix>
4164
+ @if (action?.items) {
4165
+ <ax-dropdown-panel #panel>
4166
+ <ax-button-item-list>
4167
+ @for (sub of action?.items; track $index) {
4168
+ @if (sub.visible != false) {
4169
+ <ax-button-item
4170
+ [text]="sub.title"
4171
+ [color]="sub.color"
4172
+ [disabled]="sub.disabled"
4173
+ (onClick)="handleActionClick(sub)"
4174
+ >
4175
+ <ax-prefix>
4176
+ <ax-icon icon="fa-light {{ sub.icon }}"></ax-icon>
4177
+ </ax-prefix>
4178
+ </ax-button-item>
4179
+ @if (sub.break) {
4180
+ <ax-divider></ax-divider>
4181
+ }
4182
+ }
4183
+ }
4184
+ </ax-button-item-list>
4185
+ </ax-dropdown-panel>
4186
+ }
4187
+ </ax-button>
4188
+ }
4189
+ }
4190
+ @if (secondaryActions().length) {
4191
+ <ax-button
4192
+ [class.ax-sm]="layoutThemeService.isSmall()"
4193
+ [iconOnly]="layoutThemeService.isSmall()"
4194
+ [text]="'actions'"
4195
+ [look]="layoutThemeService.isSmall() ? 'blank' : 'solid'"
4196
+ [color]="'default'"
4197
+ >
4198
+ <ax-prefix>
4199
+ <i class="fa-solid fa-ellipsis-vertical"></i>
4200
+ </ax-prefix>
4201
+ <ax-dropdown-panel #panel>
4202
+ <ax-button-item-list>
4203
+ @for (item of secondaryActions(); track $index) {
4204
+ @if (item.visible != false) {
4205
+ <ax-button-item
4206
+ [text]="item.title"
4207
+ [color]="item.color"
4208
+ [disabled]="item.disabled"
4209
+ (onClick)="handleSecondaryActionClick(item)"
4210
+ >
4211
+ <ax-prefix>
4212
+ <ax-icon icon="fa-light {{ item.icon }}"></ax-icon>
4213
+ </ax-prefix>
4214
+ </ax-button-item>
4215
+ @if (item.break) {
4216
+ <ax-divider></ax-divider>
4217
+ }
4218
+ }
4219
+ }
4220
+ </ax-button-item-list>
4221
+ </ax-dropdown-panel>
4222
+ </ax-button>
4223
+ }
4224
+ </div>
4225
+ }
4226
+ <div class="ax-flex ax-flex-col ax-gap-2 ax-h-full">
4227
+ @if (toolbarNode() != null && showToolbar()) {
4228
+ <ng-container
4229
+ #toolbar
4230
+ axp-widget-renderer
4231
+ [node]="toolbarNode()!"
4232
+ [parentNode]="this"
4233
+ [index]="index"
4234
+ [mode]="this.mode"
4235
+ ></ng-container>
4236
+ }
4237
+ @if (listNode() != null) {
4238
+ <ng-container
4239
+ #list
4240
+ axp-widget-renderer
4241
+ [node]="listNode()!"
4242
+ [parentNode]="this"
4243
+ [index]="index"
4244
+ [mode]="this.mode"
4245
+ ></ng-container>
4246
+ }
4247
+ </div>
4248
+ `,
4249
+ standalone: true,
4250
+ host: {
4251
+ '[class]': '"ax-h-full"',
4252
+ },
4253
+ changeDetection: ChangeDetectionStrategy.OnPush,
4254
+ providers: [AXPEntityListTableService, AXPEntityListToolbarService],
4255
+ imports: [CommonModule, AXDecoratorModule, AXPLayoutBuilderModule, AXButtonModule, AXDropdownModule],
4256
+ }]
4257
+ }] });
4258
+
4259
+ var entityListWidgetView_component = /*#__PURE__*/Object.freeze({
4260
+ __proto__: null,
4261
+ AXPEntityListWidgetViewComponent: AXPEntityListWidgetViewComponent
4262
+ });
4263
+
4264
+ const AXPEntityListWidget = {
4265
+ name: 'entity-list',
4266
+ title: 'Entity List',
4267
+ description: 'Displays entity data in a table format',
4268
+ type: 'view',
4269
+ categories: [],
4270
+ groups: [AXPWidgetGroupEnum.EntityWidget],
4271
+ icon: 'fa-solid fa-square',
4272
+ properties: [AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY],
4273
+ components: {
4274
+ view: {
4275
+ component: () => Promise.resolve().then(function () { return entityListWidgetView_component; }).then((c) => c.AXPEntityListWidgetViewComponent),
4276
+ },
4277
+ edit: {
4278
+ component: () => Promise.resolve().then(function () { return entityListWidgetView_component; }).then((c) => c.AXPEntityListWidgetViewComponent),
4279
+ },
4280
+ print: {
4281
+ component: () => Promise.resolve().then(function () { return entityListWidgetView_component; }).then((c) => c.AXPEntityListWidgetViewComponent),
4282
+ },
4283
+ designer: {
4284
+ component: () => Promise.resolve().then(function () { return entityListWidgetView_component; }).then((c) => c.AXPEntityListWidgetViewComponent),
4285
+ },
4286
+ },
4287
+ };
4288
+
4289
+ class AXPEntityReferenceWidgetViewComponent extends AXPLayoutWidgetComponent {
4290
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4291
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4292
+ }
4293
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetViewComponent, decorators: [{
4294
+ type: Component,
4295
+ args: [{
4296
+ template: ``,
4297
+ standalone: true,
4298
+ changeDetection: ChangeDetectionStrategy.OnPush,
4299
+ imports: [CommonModule]
4300
+ }]
4301
+ }] });
4302
+
4303
+ var entityReferenceWidgetView_component = /*#__PURE__*/Object.freeze({
4304
+ __proto__: null,
4305
+ AXPEntityReferenceWidgetViewComponent: AXPEntityReferenceWidgetViewComponent
4306
+ });
4307
+
4308
+ class AXPEntityReferenceWidgetEditComponent extends AXPLayoutWidgetComponent {
4309
+ constructor() {
4310
+ super(...arguments);
4311
+ this.injector = inject(Injector);
4312
+ this.entityResolver = inject(AXPEntityResolver);
4313
+ this.entity = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entity" }] : []));
4314
+ this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : []));
4315
+ this.#efEntity = effect(async () => {
4316
+ const [module, entity] = this.entity().split('.');
4317
+ this.entityDef.set(await this.entityResolver.get(module, entity));
4318
+ console.log(this.entityDef());
4319
+ }, ...(ngDevMode ? [{ debugName: "#efEntity" }] : []));
4320
+ }
4321
+ #efEntity;
4322
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4323
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetEditComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4324
+ }
4325
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetEditComponent, decorators: [{
4326
+ type: Component,
4327
+ args: [{
4328
+ template: ``,
4329
+ standalone: true,
4330
+ changeDetection: ChangeDetectionStrategy.OnPush,
4331
+ imports: [CommonModule, FormsModule],
4332
+ }]
4333
+ }] });
4334
+
4335
+ var entityReferenceWidgetEdit_component = /*#__PURE__*/Object.freeze({
4336
+ __proto__: null,
4337
+ AXPEntityReferenceWidgetEditComponent: AXPEntityReferenceWidgetEditComponent
4338
+ });
4339
+
4340
+ class AXPEntityReferenceWidgetColumnComponent extends AXPColumnWidgetComponent {
4341
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetColumnComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4342
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetColumnComponent, isStandalone: true, selector: "ng-component", inputs: { rawValue: "rawValue" }, usesInheritance: true, ngImport: i0, template: `{{rawValue}}`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4343
+ }
4344
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetColumnComponent, decorators: [{
4345
+ type: Component,
4346
+ args: [{
4347
+ template: `{{rawValue}}`,
4348
+ standalone: true,
4349
+ changeDetection: ChangeDetectionStrategy.OnPush,
4350
+ imports: [CommonModule],
4351
+ inputs: ['rawValue']
4352
+ }]
4353
+ }] });
4354
+
4355
+ var entityReferenceWidgetColumn_component = /*#__PURE__*/Object.freeze({
4356
+ __proto__: null,
4357
+ AXPEntityReferenceWidgetColumnComponent: AXPEntityReferenceWidgetColumnComponent
4358
+ });
4359
+
4360
+ class AXPEntityReferenceWidgetPrintComponent extends AXPLayoutWidgetComponent {
4361
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetPrintComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4362
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetPrintComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4363
+ }
4364
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetPrintComponent, decorators: [{
4365
+ type: Component,
4366
+ args: [{
4367
+ template: ``,
4368
+ standalone: true,
4369
+ changeDetection: ChangeDetectionStrategy.OnPush,
4370
+ imports: [CommonModule],
4371
+ inputs: []
4372
+ }]
4373
+ }] });
4374
+
4375
+ var entityReferenceWidgetPrint_component = /*#__PURE__*/Object.freeze({
4376
+ __proto__: null,
4377
+ AXPEntityReferenceWidgetPrintComponent: AXPEntityReferenceWidgetPrintComponent
4378
+ });
4379
+
4380
+ class AXPEntityReferenceWidgetDesignerComponent extends AXPLayoutWidgetComponent {
4381
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetDesignerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4382
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetDesignerComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4383
+ }
4384
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetDesignerComponent, decorators: [{
4385
+ type: Component,
4386
+ args: [{
4387
+ template: ``,
4388
+ standalone: true,
4389
+ changeDetection: ChangeDetectionStrategy.OnPush,
4390
+ imports: [CommonModule]
4391
+ }]
4392
+ }] });
4393
+
4394
+ var entityReferenceWidgetDesigner_component = /*#__PURE__*/Object.freeze({
4395
+ __proto__: null,
4396
+ AXPEntityReferenceWidgetDesignerComponent: AXPEntityReferenceWidgetDesignerComponent
4397
+ });
4398
+
4399
+ const AXPEntityReferenceWidget = {
4400
+ name: 'entity-reference',
4401
+ title: 'Entity Reference',
4402
+ description: '',
4403
+ type: 'view',
4404
+ categories: [],
4405
+ groups: [AXPWidgetGroupEnum.EntityWidget],
4406
+ icon: 'fa-solid fa-square',
4407
+ properties: [AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY],
4408
+ components: {
4409
+ view: {
4410
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetView_component; }).then((c) => c.AXPEntityReferenceWidgetViewComponent),
4411
+ },
4412
+ edit: {
4413
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetEdit_component; }).then((c) => c.AXPEntityReferenceWidgetEditComponent),
4414
+ },
4415
+ column: {
4416
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetColumn_component; }).then((c) => c.AXPEntityReferenceWidgetColumnComponent),
4417
+ },
4418
+ print: {
4419
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetPrint_component; }).then((c) => c.AXPEntityReferenceWidgetPrintComponent),
4420
+ },
4421
+ designer: {
4422
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetDesigner_component; }).then((c) => c.AXPEntityReferenceWidgetDesignerComponent),
4423
+ },
4424
+ },
4425
+ };
4426
+
2927
4427
  class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
2928
4428
  constructor() {
2929
4429
  super(...arguments);
@@ -3169,7 +4669,7 @@ class AXPLookupWidgetSelectorComponent extends AXBasePageComponent {
3169
4669
  }
3170
4670
  </ax-suffix>
3171
4671
  </ax-footer>
3172
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXCommonModule }, { kind: "directive", type: i1$2.AXAutoFocusDirective, selector: "[axAutoFocus]", inputs: ["axAutoFocus", "axAutoFocusTime"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDataTableModule }, { kind: "component", type: i4.AXDataTableComponent, selector: "ax-data-table", inputs: ["dataSource", "selectedRows", "parentField", "rowTemplate", "emptyTemplate", "noDataTemplate", "alternative", "showHeader", "fixedHeader", "showFooter", "fixedFooter", "itemHeight", "allowReordering", "paging", "fetchDataMode", "loading", "focusedRow"], outputs: ["selectedRowsChange", "focusedRowChange", "onRowClick", "onRowDbClick", "onColumnsOrderChanged", "onColumnSizeChanged", "onPageChanged"] }, { kind: "component", type: i4.AXRowSelectColumnComponent, selector: "ax-select-column", inputs: ["width", "caption", "fixed"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i5.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXPLayoutBuilderModule }, { kind: "component", type: i6.AXPWidgetColumnRendererComponent, selector: "axp-widget-column-renderer", inputs: ["caption", "customExpandIcon", "customCollapseIcon", "customWidth", "node", "footerTemplate", "expandHandler", "cellTemplate", "headerTemplate"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i8.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4672
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXCommonModule }, { kind: "directive", type: i1$2.AXAutoFocusDirective, selector: "[axAutoFocus]", inputs: ["axAutoFocus", "axAutoFocusTime"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDataTableModule }, { kind: "component", type: i4$1.AXDataTableComponent, selector: "ax-data-table", inputs: ["dataSource", "selectedRows", "parentField", "rowTemplate", "emptyTemplate", "noDataTemplate", "alternative", "showHeader", "fixedHeader", "showFooter", "fixedFooter", "itemHeight", "allowReordering", "paging", "fetchDataMode", "loading", "focusedRow"], outputs: ["selectedRowsChange", "focusedRowChange", "onRowClick", "onRowDbClick", "onColumnsOrderChanged", "onColumnSizeChanged", "onPageChanged"] }, { kind: "component", type: i4$1.AXRowSelectColumnComponent, selector: "ax-select-column", inputs: ["width", "caption", "fixed"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i5.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXPLayoutBuilderModule }, { kind: "component", type: i2.AXPWidgetColumnRendererComponent, selector: "axp-widget-column-renderer", inputs: ["caption", "customExpandIcon", "customCollapseIcon", "customWidth", "node", "footerTemplate", "expandHandler", "cellTemplate", "headerTemplate"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i8.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3173
4673
  }
3174
4674
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLookupWidgetSelectorComponent, decorators: [{
3175
4675
  type: Component,
@@ -3418,6 +4918,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
3418
4918
  this.customFilter = computed(() => this.options()['filter'], ...(ngDevMode ? [{ debugName: "customFilter" }] : []));
3419
4919
  this.multiple = computed(() => (this.options()['multiple'] ?? false), ...(ngDevMode ? [{ debugName: "multiple" }] : []));
3420
4920
  this.look = computed(() => this.options()['look'] ?? 'lookup', ...(ngDevMode ? [{ debugName: "look" }] : []));
4921
+ this.allowClear = computed(() => (this.options()['allowClear'] ?? false), ...(ngDevMode ? [{ debugName: "allowClear" }] : []));
3421
4922
  this.textField = computed(() => {
3422
4923
  return (this.entityDef()?.formats.lookup ?? this.entityDef()?.properties.find((c) => c.name != 'id')?.name ?? 'title');
3423
4924
  }, ...(ngDevMode ? [{ debugName: "textField" }] : []));
@@ -3485,11 +4986,11 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
3485
4986
  }
3486
4987
  showSelector() {
3487
4988
  this.isOpen.set(true);
3488
- const columnsCount = this.columns().length > 0 ? this.columns().length : this.vm()?.columns().length ?? 0;
4989
+ const columnsCount = this.columns().length > 0 ? this.columns().length : (this.vm()?.columns().length ?? 0);
3489
4990
  this.popupService
3490
4991
  .open(AXPLookupWidgetSelectorComponent, {
3491
4992
  title: `${this.translateService.translateSync('widget.lookup.search')} ${this.translateService.translateSync(this.entityDef()?.formats.plural ?? '')}`,
3492
- size: columnsCount < 4 ? 'md' : 'lg',
4993
+ size: columnsCount < 3 ? 'md' : 'lg',
3493
4994
  data: {
3494
4995
  vm: new AXPLookupWidgetSelectorViewModel(this.injector, this.entityDef(), {
3495
4996
  customFilter: this.customFilter(),
@@ -3621,47 +5122,56 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
3621
5122
  [multiple]="multiple()"
3622
5123
  (onValueChanged)="selectBoxValueChange($event)"
3623
5124
  >
3624
- <ax-search-box>
3625
- </ax-search-box>
3626
- </ax-select-box>
5125
+ <ax-search-box>
5126
+ <ax-clear-button></ax-clear-button>
5127
+ </ax-search-box>
5128
+ @if (allowClear()) {
5129
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5130
+ }
5131
+ </ax-select-box>
3627
5132
  } @else {
3628
- <ax-tag-box
3629
- [ngModel]="selectedItems()"
3630
- [textField]="textField()"
3631
- [valueField]="valueField()"
3632
- (onValueChanged)="handleValueChange($event)"
3633
- [placeholder]="placeholder() | translate | async"
3634
- [addOnEnter]="false"
3635
- [addOnComma]="false"
3636
- [disabled]="disabled()"
3637
- (onKeyUp)="handleKeyUp($event)"
3638
- (onBlur)="handleOnBlur($event)"
3639
- >
3640
- @for (validation of validationRules(); track $index) {
3641
- <ax-validation-rule
3642
- [rule]="validation.rule"
3643
- [message]="validation.options?.message"
3644
- [options]="validation.options"
3645
- ></ax-validation-rule>
3646
- }
3647
- @if (selectedItems().length > 1) {
3648
- <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
3649
- }
5133
+ <ax-tag-box
5134
+ [ngModel]="selectedItems()"
5135
+ [textField]="textField()"
5136
+ [valueField]="valueField()"
5137
+ (onValueChanged)="handleValueChange($event)"
5138
+ [placeholder]="placeholder() | translate | async"
5139
+ [addOnEnter]="false"
5140
+ [addOnComma]="false"
5141
+ [disabled]="disabled()"
5142
+ (onKeyUp)="handleKeyUp($event)"
5143
+ (onBlur)="handleOnBlur($event)"
5144
+ >
5145
+ @for (validation of validationRules(); track $index) {
5146
+ <ax-validation-rule
5147
+ [rule]="validation.rule"
5148
+ [message]="validation.options?.message"
5149
+ [options]="validation.options"
5150
+ ></ax-validation-rule>
5151
+ }
5152
+ @if (selectedItems().length > 1 || allowClear()) {
5153
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5154
+ }
3650
5155
 
3651
- <ax-suffix>
3652
- <ax-button color="ghost" look="blank" [disabled]="isLoading() || disabled()" (onClick)="handleOnClick($event)">
3653
- @if (isLoading()) {
3654
- <ax-loading></ax-loading>
3655
- } @else {
3656
- <ax-icon icon="far fa-search"> </ax-icon>
3657
- }
3658
- </ax-button>
3659
- </ax-suffix>
3660
- </ax-tag-box>
3661
- }
5156
+ <ax-suffix>
5157
+ <ax-button
5158
+ color="ghost"
5159
+ look="blank"
5160
+ [disabled]="isLoading() || disabled()"
5161
+ (onClick)="handleOnClick($event)"
5162
+ >
5163
+ @if (isLoading()) {
5164
+ <ax-loading></ax-loading>
5165
+ } @else {
5166
+ <ax-icon icon="far fa-search"> </ax-icon>
5167
+ }
5168
+ </ax-button>
5169
+ </ax-suffix>
5170
+ </ax-tag-box>
5171
+ }
3662
5172
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type:
3663
5173
  //
3664
- AXButtonModule }, { kind: "component", type: i2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i1.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$1.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXTagBoxModule }, { kind: "component", type: i6$1.AXTagBoxComponent, selector: "ax-tag-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "allowNull", "type", "look", "addOnComma", "addOnEnter", "valueField", "textField", "readonlyField", "allowDuplicateValues"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i7$1.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed"] }, { kind: "component", type: AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i8.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5174
+ AXButtonModule }, { kind: "component", type: i3$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i1.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$1.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXTagBoxModule }, { kind: "component", type: i6.AXTagBoxComponent, selector: "ax-tag-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "allowNull", "type", "look", "addOnComma", "addOnEnter", "valueField", "textField", "readonlyField", "allowDuplicateValues"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i7$1.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed"] }, { kind: "component", type: AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i8.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3665
5175
  }
3666
5176
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLookupWidgetEditComponent, decorators: [{
3667
5177
  type: Component,
@@ -3678,44 +5188,53 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
3678
5188
  [multiple]="multiple()"
3679
5189
  (onValueChanged)="selectBoxValueChange($event)"
3680
5190
  >
3681
- <ax-search-box>
3682
- </ax-search-box>
3683
- </ax-select-box>
5191
+ <ax-search-box>
5192
+ <ax-clear-button></ax-clear-button>
5193
+ </ax-search-box>
5194
+ @if (allowClear()) {
5195
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5196
+ }
5197
+ </ax-select-box>
3684
5198
  } @else {
3685
- <ax-tag-box
3686
- [ngModel]="selectedItems()"
3687
- [textField]="textField()"
3688
- [valueField]="valueField()"
3689
- (onValueChanged)="handleValueChange($event)"
3690
- [placeholder]="placeholder() | translate | async"
3691
- [addOnEnter]="false"
3692
- [addOnComma]="false"
3693
- [disabled]="disabled()"
3694
- (onKeyUp)="handleKeyUp($event)"
3695
- (onBlur)="handleOnBlur($event)"
3696
- >
3697
- @for (validation of validationRules(); track $index) {
3698
- <ax-validation-rule
3699
- [rule]="validation.rule"
3700
- [message]="validation.options?.message"
3701
- [options]="validation.options"
3702
- ></ax-validation-rule>
3703
- }
3704
- @if (selectedItems().length > 1) {
3705
- <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
3706
- }
5199
+ <ax-tag-box
5200
+ [ngModel]="selectedItems()"
5201
+ [textField]="textField()"
5202
+ [valueField]="valueField()"
5203
+ (onValueChanged)="handleValueChange($event)"
5204
+ [placeholder]="placeholder() | translate | async"
5205
+ [addOnEnter]="false"
5206
+ [addOnComma]="false"
5207
+ [disabled]="disabled()"
5208
+ (onKeyUp)="handleKeyUp($event)"
5209
+ (onBlur)="handleOnBlur($event)"
5210
+ >
5211
+ @for (validation of validationRules(); track $index) {
5212
+ <ax-validation-rule
5213
+ [rule]="validation.rule"
5214
+ [message]="validation.options?.message"
5215
+ [options]="validation.options"
5216
+ ></ax-validation-rule>
5217
+ }
5218
+ @if (selectedItems().length > 1 || allowClear()) {
5219
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5220
+ }
3707
5221
 
3708
- <ax-suffix>
3709
- <ax-button color="ghost" look="blank" [disabled]="isLoading() || disabled()" (onClick)="handleOnClick($event)">
3710
- @if (isLoading()) {
3711
- <ax-loading></ax-loading>
3712
- } @else {
3713
- <ax-icon icon="far fa-search"> </ax-icon>
3714
- }
3715
- </ax-button>
3716
- </ax-suffix>
3717
- </ax-tag-box>
3718
- }
5222
+ <ax-suffix>
5223
+ <ax-button
5224
+ color="ghost"
5225
+ look="blank"
5226
+ [disabled]="isLoading() || disabled()"
5227
+ (onClick)="handleOnClick($event)"
5228
+ >
5229
+ @if (isLoading()) {
5230
+ <ax-loading></ax-loading>
5231
+ } @else {
5232
+ <ax-icon icon="far fa-search"> </ax-icon>
5233
+ }
5234
+ </ax-button>
5235
+ </ax-suffix>
5236
+ </ax-tag-box>
5237
+ }
3719
5238
  `,
3720
5239
  changeDetection: ChangeDetectionStrategy.OnPush,
3721
5240
  imports: [
@@ -3730,7 +5249,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
3730
5249
  AXTagBoxModule,
3731
5250
  AXTranslationModule,
3732
5251
  AXSelectBoxModule,
3733
- AXSearchBoxComponent
5252
+ AXSearchBoxComponent,
3734
5253
  ],
3735
5254
  }]
3736
5255
  }] });
@@ -3809,6 +5328,7 @@ const AXPLookupWidget = {
3809
5328
  type: 'editor',
3810
5329
  properties: [
3811
5330
  AXP_DISABLED_PROPERTY,
5331
+ AXP_ALLOW_CLEAR_PROPERTY,
3812
5332
  AXP_DATA_PATH_PROPERTY,
3813
5333
  {
3814
5334
  name: 'expose',
@@ -3992,7 +5512,7 @@ class AXPTagableBoxWidgetEditComponent extends AXPValueWidgetComponent {
3992
5512
  </ax-prefix>
3993
5513
  </ax-button>
3994
5514
  </div>
3995
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXTextBoxModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$1.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i7$1.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i5.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5515
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXTextBoxModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$1.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i7$1.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i5.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3996
5516
  }
3997
5517
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPTagableBoxWidgetEditComponent, decorators: [{
3998
5518
  type: Component,
@@ -4200,6 +5720,7 @@ const AXPTagableBoxWidget = {
4200
5720
  description: 'Inputs text with tags',
4201
5721
  categories: AXP_WIDGETS_EDITOR_CATEGORY,
4202
5722
  type: 'editor',
5723
+ groups: [AXPWidgetGroupEnum.EntityWidget],
4203
5724
  defaultFilterWidgetName: 'string-filter',
4204
5725
  properties: [AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY],
4205
5726
  components: {
@@ -4288,7 +5809,7 @@ class AXPWidgetSelectorWidgetEditComponent extends AXPValueWidgetComponent {
4288
5809
  <axp-widget-property-viewer [widget]="selectedWidgetNode()!" (onChanged)="handleChangeWidget($event)">
4289
5810
  </axp-widget-property-viewer>
4290
5811
  }
4291
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "component", type: i2$1.AXTextBoxComponent, selector: "ax-text-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "maxLength", "allowNull", "type", "autoComplete", "look", "mask-options", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$1.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "component", type: AXPWidgetPropertyViewerComponent, selector: "axp-widget-property-viewer", inputs: ["widget", "mode"], outputs: ["onChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5812
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "component", type: i2$1.AXTextBoxComponent, selector: "ax-text-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "maxLength", "allowNull", "type", "autoComplete", "look", "mask-options", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$1.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "component", type: AXPWidgetPropertyViewerComponent, selector: "axp-widget-property-viewer", inputs: ["widget", "mode"], outputs: ["onChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4292
5813
  }
4293
5814
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPWidgetSelectorWidgetEditComponent, decorators: [{
4294
5815
  type: Component,
@@ -4596,10 +6117,10 @@ class AXPShowDetailViewAction extends AXPWorkflowAction {
4596
6117
  this.sessionService = inject(AXPSessionService);
4597
6118
  }
4598
6119
  async execute(context) {
4599
- const [module, entity] = context.getVariable('entity').split(".");
6120
+ const [module, entity] = context.getVariable('entity').split('.');
4600
6121
  const { id } = context.getVariable('data');
4601
6122
  const newPayload = {
4602
- commands: `/${this.sessionService.application?.name}/m/${module}/e/${entity}/${id}/view`,
6123
+ commands: `/${this.sessionService.application?.name}/m/${module}/e/${entity}/${id}/new-view`,
4603
6124
  };
4604
6125
  context.setVariable('payload', newPayload);
4605
6126
  this.navigation.execute(context);
@@ -4641,6 +6162,7 @@ class AXPShowFileUploaderPopupAction extends AXPWorkflowAction {
4641
6162
  multiple: multiple,
4642
6163
  accept: accept,
4643
6164
  fileEditable: fileEditable,
6165
+ // maxFileSize: maxFileSize,
4644
6166
  });
4645
6167
  // Handle case when result is undefined or empty array
4646
6168
  if (!res || res.length === 0) {
@@ -4730,146 +6252,56 @@ const AXPShowListViewWorkflow = {
4730
6252
  },
4731
6253
  };
4732
6254
 
4733
- class AXPEntityReferenceWidgetViewComponent extends AXPLayoutWidgetComponent {
4734
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4735
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4736
- }
4737
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetViewComponent, decorators: [{
4738
- type: Component,
4739
- args: [{
4740
- template: ``,
4741
- standalone: true,
4742
- changeDetection: ChangeDetectionStrategy.OnPush,
4743
- imports: [CommonModule]
4744
- }]
4745
- }] });
4746
-
4747
- var entityReferenceWidgetView_component = /*#__PURE__*/Object.freeze({
4748
- __proto__: null,
4749
- AXPEntityReferenceWidgetViewComponent: AXPEntityReferenceWidgetViewComponent
4750
- });
4751
-
4752
- class AXPEntityReferenceWidgetEditComponent extends AXPLayoutWidgetComponent {
4753
- constructor() {
4754
- super(...arguments);
4755
- this.injector = inject(Injector);
4756
- this.entityResolver = inject(AXPEntityResolver);
4757
- this.entity = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entity" }] : []));
4758
- this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : []));
4759
- this.#efEntity = effect(async () => {
4760
- const [module, entity] = this.entity().split('.');
4761
- this.entityDef.set(await this.entityResolver.get(module, entity));
4762
- console.log(this.entityDef());
4763
- }, ...(ngDevMode ? [{ debugName: "#efEntity" }] : []));
4764
- }
4765
- #efEntity;
4766
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4767
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetEditComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4768
- }
4769
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetEditComponent, decorators: [{
4770
- type: Component,
4771
- args: [{
4772
- template: ``,
4773
- standalone: true,
4774
- changeDetection: ChangeDetectionStrategy.OnPush,
4775
- imports: [CommonModule, FormsModule],
4776
- }]
4777
- }] });
4778
-
4779
- var entityReferenceWidgetEdit_component = /*#__PURE__*/Object.freeze({
4780
- __proto__: null,
4781
- AXPEntityReferenceWidgetEditComponent: AXPEntityReferenceWidgetEditComponent
4782
- });
4783
-
4784
- class AXPEntityReferenceWidgetColumnComponent extends AXPColumnWidgetComponent {
4785
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetColumnComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4786
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetColumnComponent, isStandalone: true, selector: "ng-component", inputs: { rawValue: "rawValue" }, usesInheritance: true, ngImport: i0, template: `{{rawValue}}`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4787
- }
4788
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetColumnComponent, decorators: [{
4789
- type: Component,
4790
- args: [{
4791
- template: `{{rawValue}}`,
4792
- standalone: true,
4793
- changeDetection: ChangeDetectionStrategy.OnPush,
4794
- imports: [CommonModule],
4795
- inputs: ['rawValue']
4796
- }]
4797
- }] });
4798
-
4799
- var entityReferenceWidgetColumn_component = /*#__PURE__*/Object.freeze({
4800
- __proto__: null,
4801
- AXPEntityReferenceWidgetColumnComponent: AXPEntityReferenceWidgetColumnComponent
4802
- });
4803
-
4804
- class AXPEntityReferenceWidgetPrintComponent extends AXPLayoutWidgetComponent {
4805
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetPrintComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4806
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetPrintComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4807
- }
4808
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetPrintComponent, decorators: [{
4809
- type: Component,
4810
- args: [{
4811
- template: ``,
4812
- standalone: true,
4813
- changeDetection: ChangeDetectionStrategy.OnPush,
4814
- imports: [CommonModule],
4815
- inputs: []
4816
- }]
4817
- }] });
4818
-
4819
- var entityReferenceWidgetPrint_component = /*#__PURE__*/Object.freeze({
4820
- __proto__: null,
4821
- AXPEntityReferenceWidgetPrintComponent: AXPEntityReferenceWidgetPrintComponent
4822
- });
4823
-
4824
- class AXPEntityReferenceWidgetDesignerComponent extends AXPLayoutWidgetComponent {
4825
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetDesignerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4826
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetDesignerComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4827
- }
4828
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetDesignerComponent, decorators: [{
4829
- type: Component,
4830
- args: [{
4831
- template: ``,
4832
- standalone: true,
4833
- changeDetection: ChangeDetectionStrategy.OnPush,
4834
- imports: [CommonModule]
4835
- }]
4836
- }] });
4837
-
4838
- var entityReferenceWidgetDesigner_component = /*#__PURE__*/Object.freeze({
4839
- __proto__: null,
4840
- AXPEntityReferenceWidgetDesignerComponent: AXPEntityReferenceWidgetDesignerComponent
4841
- });
4842
-
4843
- const AXPEntityReferenceWidget = {
4844
- name: "entity-reference",
4845
- title: "Entity Reference",
4846
- description: '',
4847
- type: 'view',
4848
- categories: [],
4849
- groups: [AXPWidgetGroupEnum.FormElement],
4850
- icon: "fa-solid fa-square",
4851
- properties: [
4852
- AXP_NAME_PROPERTY,
4853
- AXP_DATA_PATH_PROPERTY,
4854
- ],
4855
- components: {
4856
- view: {
4857
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetView_component; }).then((c) => c.AXPEntityReferenceWidgetViewComponent),
4858
- },
4859
- edit: {
4860
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetEdit_component; }).then((c) => c.AXPEntityReferenceWidgetEditComponent),
4861
- },
4862
- column: {
4863
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetColumn_component; }).then((c) => c.AXPEntityReferenceWidgetColumnComponent),
4864
- },
4865
- print: {
4866
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetPrint_component; }).then((c) => c.AXPEntityReferenceWidgetPrintComponent),
4867
- },
4868
- designer: {
4869
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetDesigner_component; }).then((c) => c.AXPEntityReferenceWidgetDesignerComponent),
4870
- },
4871
- }
6255
+ /**
6256
+ * Default widths for common text columns
6257
+ */
6258
+ const DEFAULT_COLUMN_WIDTHS = {
6259
+ title: '250px',
6260
+ description: '500px',
6261
+ note: '350px',
6262
+ notes: '350px',
6263
+ content: '500px'
6264
+ };
6265
+ /**
6266
+ * Factory to create a column width middleware using provided config map.
6267
+ * Sets width for columns defined in the map if not already defined on the column.
6268
+ */
6269
+ const columnWidthMiddlewareFactory = (widths) => {
6270
+ return (context) => {
6271
+ const columns = context.columns.list();
6272
+ if (!columns) {
6273
+ return;
6274
+ }
6275
+ columns.forEach((column) => {
6276
+ const desiredWidth = widths[column.name];
6277
+ if (desiredWidth && !column.options?.width) {
6278
+ const normalizedWidth = typeof desiredWidth === 'number' ? `${desiredWidth}px` : desiredWidth;
6279
+ context.columns.find(column.name).update((col) => ({
6280
+ ...col,
6281
+ options: {
6282
+ ...col.options,
6283
+ width: normalizedWidth
6284
+ }
6285
+ }));
6286
+ }
6287
+ });
6288
+ };
4872
6289
  };
6290
+ //#endregion
6291
+ //#region ---- Provider Registration ----
6292
+ /**
6293
+ * Helper to create a provider for the column width middleware.
6294
+ * By default it applies to all entities using the '*' pattern.
6295
+ */
6296
+ const createColumnWidthMiddlewareProvider = (widths, entityName = '*') => ({
6297
+ entityName,
6298
+ modifier: columnWidthMiddlewareFactory(widths)
6299
+ });
6300
+ /**
6301
+ * Default provider registered with the default map.
6302
+ */
6303
+ const columnWidthMiddlewareProvider = createColumnWidthMiddlewareProvider(DEFAULT_COLUMN_WIDTHS);
6304
+ //#endregion
4873
6305
 
4874
6306
  function routesFacory() {
4875
6307
  const config = inject(AXP_ENTITY_CONFIG_TOKEN);
@@ -4903,6 +6335,14 @@ function routesFacory() {
4903
6335
  },
4904
6336
  data: { reuse: false },
4905
6337
  },
6338
+ {
6339
+ path: 'e/:entity/:id/new-view',
6340
+ resolve: { adapter: AXPLayoutDetailsViewRouteResolver },
6341
+ loadComponent: () => {
6342
+ return config.viewers.master.details();
6343
+ },
6344
+ data: { reuse: false },
6345
+ },
4906
6346
  {
4907
6347
  path: 'e/:entity/:id',
4908
6348
  redirectTo: 'e/:entity/:id/view',
@@ -4934,7 +6374,7 @@ class AXPEntityModule {
4934
6374
  });
4935
6375
  }
4936
6376
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, deps: [{ token: i1$4.AXPAppStartUpService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.NgModule }); }
4937
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, imports: [RouterModule, i2$2.AXPWorkflowModule, i6.AXPLayoutBuilderModule] }); }
6377
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, imports: [RouterModule, i2$2.AXPWorkflowModule, i2.AXPLayoutBuilderModule] }); }
4938
6378
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, providers: [
4939
6379
  {
4940
6380
  provide: ROUTES,
@@ -4951,6 +6391,11 @@ class AXPEntityModule {
4951
6391
  useClass: AXPEntityCommandSearchDefinitionProvider,
4952
6392
  multi: true,
4953
6393
  },
6394
+ {
6395
+ provide: AXP_ENTITY_MODIFIER,
6396
+ useValue: columnWidthMiddlewareProvider,
6397
+ multi: true,
6398
+ },
4954
6399
  ], imports: [RouterModule,
4955
6400
  AXPWorkflowModule.forChild({
4956
6401
  actions: {
@@ -4980,7 +6425,13 @@ class AXPEntityModule {
4980
6425
  functions: {},
4981
6426
  }),
4982
6427
  AXPLayoutBuilderModule.forChild({
4983
- widgets: [AXPLookupWidget, AXPWidgetSelectorWidget, AXPTagableBoxWidget, AXPEntityReferenceWidget],
6428
+ widgets: [
6429
+ AXPLookupWidget,
6430
+ AXPWidgetSelectorWidget,
6431
+ AXPTagableBoxWidget,
6432
+ AXPEntityListWidget,
6433
+ AXPEntityReferenceWidget,
6434
+ ],
4984
6435
  })] }); }
4985
6436
  }
4986
6437
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, decorators: [{
@@ -5016,7 +6467,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
5016
6467
  functions: {},
5017
6468
  }),
5018
6469
  AXPLayoutBuilderModule.forChild({
5019
- widgets: [AXPLookupWidget, AXPWidgetSelectorWidget, AXPTagableBoxWidget, AXPEntityReferenceWidget],
6470
+ widgets: [
6471
+ AXPLookupWidget,
6472
+ AXPWidgetSelectorWidget,
6473
+ AXPTagableBoxWidget,
6474
+ AXPEntityListWidget,
6475
+ AXPEntityReferenceWidget,
6476
+ ],
5020
6477
  }),
5021
6478
  ],
5022
6479
  exports: [],
@@ -5037,6 +6494,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
5037
6494
  useClass: AXPEntityCommandSearchDefinitionProvider,
5038
6495
  multi: true,
5039
6496
  },
6497
+ {
6498
+ provide: AXP_ENTITY_MODIFIER,
6499
+ useValue: columnWidthMiddlewareProvider,
6500
+ multi: true,
6501
+ },
5040
6502
  ],
5041
6503
  }]
5042
6504
  }], ctorParameters: () => [{ type: i1$4.AXPAppStartUpService }, { type: i0.Injector }] });
@@ -5067,6 +6529,7 @@ function entityMasterViewAction() {
5067
6529
  priority: 'secondary',
5068
6530
  type: 'view',
5069
6531
  scope: AXPEntityCommandScope.Individual,
6532
+ default: true,
5070
6533
  };
5071
6534
  }
5072
6535
  function entityMasterDeleteAction() {
@@ -5087,9 +6550,7 @@ function entityMasterCrudActions() {
5087
6550
  ];
5088
6551
  }
5089
6552
  function entityMasterRecordActions() {
5090
- return [
5091
- entityMasterDeleteAction(),
5092
- ];
6553
+ return [entityMasterDeleteAction()];
5093
6554
  }
5094
6555
  // #endregion
5095
6556
  // #region Details
@@ -5121,7 +6582,8 @@ function entityDetailsSimpleCondition(fk) {
5121
6582
  };
5122
6583
  }
5123
6584
  function entityDetailsReferenceCondition() {
5124
- return [{
6585
+ return [
6586
+ {
5125
6587
  name: 'reference.id',
5126
6588
  operator: { type: 'equal' },
5127
6589
  value: '{{context.eval("id")}}',
@@ -5130,7 +6592,7 @@ function entityDetailsReferenceCondition() {
5130
6592
  name: 'reference.type',
5131
6593
  operator: { type: 'equal' },
5132
6594
  value: '{{context.eval("entityName")}}',
5133
- }
6595
+ },
5134
6596
  ];
5135
6597
  }
5136
6598
  function entityDetailsEditAction() {
@@ -5153,11 +6615,7 @@ function entityOverrideDetailsViewAction() {
5153
6615
  };
5154
6616
  }
5155
6617
  function entityDetailsCrudActions(parentId) {
5156
- return [
5157
- entityDetailsCreateActions(parentId),
5158
- entityDetailsEditAction(),
5159
- entityOverrideDetailsViewAction(),
5160
- ];
6618
+ return [entityDetailsCreateActions(parentId), entityDetailsEditAction(), entityOverrideDetailsViewAction()];
5161
6619
  }
5162
6620
  function entityDetailsReferenceCreateActions() {
5163
6621
  return [
@@ -5170,10 +6628,10 @@ function entityDetailsReferenceCreateActions() {
5170
6628
  redirect: false,
5171
6629
  canCreateNewOne: true,
5172
6630
  data: {
5173
- 'reference': {
5174
- 'id': '{{context.eval("id")}}',
5175
- 'type': '{{context.eval("entityName")}}'
5176
- }
6631
+ reference: {
6632
+ id: '{{context.eval("id")}}',
6633
+ type: '{{context.eval("entityName")}}',
6634
+ },
5177
6635
  },
5178
6636
  },
5179
6637
  },
@@ -5186,11 +6644,65 @@ function entityDetailsReferenceCreateActions() {
5186
6644
  entityOverrideDetailsViewAction(),
5187
6645
  ];
5188
6646
  }
5189
- // #endregion
6647
+ /**
6648
+ * Computes a diff between two plain objects with array-aware semantics.
6649
+ * - For arrays of objects with an id field, computes added/removed by id.
6650
+ * - For arrays of primitives or objects without id, uses deep equality.
6651
+ * - For scalars/objects, reports oldValue/newValue when changed.
6652
+ */
6653
+ function detectEntityChanges(oldObj, newObj) {
6654
+ return transform(newObj, (result, value, key) => {
6655
+ if (!isEqual(value, oldObj[key])) {
6656
+ const oldValue = oldObj[key];
6657
+ if (Array.isArray(value) || Array.isArray(oldValue)) {
6658
+ const oldArray = Array.isArray(oldValue) ? oldValue : [];
6659
+ const newArray = Array.isArray(value) ? value : [];
6660
+ const hasId = newArray.length > 0 && typeof newArray[0] === 'object' && newArray[0] !== null && 'id' in newArray[0];
6661
+ if (hasId) {
6662
+ const added = newArray.filter((item) => !oldArray.some((oldItem) => oldItem.id === item.id));
6663
+ const removed = oldArray.filter((item) => !newArray.some((newItem) => newItem.id === item.id));
6664
+ result[key] = { oldValue, newValue: value, added, removed };
6665
+ }
6666
+ else {
6667
+ const added = newArray.filter((item) => !oldArray.some((oldItem) => isEqual(item, oldItem)));
6668
+ const removed = oldArray.filter((item) => !newArray.some((newItem) => isEqual(item, newItem)));
6669
+ result[key] = { oldValue, newValue: value, added, removed };
6670
+ }
6671
+ }
6672
+ else {
6673
+ result[key] = { oldValue, newValue: value };
6674
+ }
6675
+ }
6676
+ }, {});
6677
+ }
6678
+ //#endregion
6679
+
6680
+ const eventDispatchMiddleware = {
6681
+ target: { ops: ['create', 'update', 'delete'], order: 90 },
6682
+ execute: async (ctx, next) => {
6683
+ const dispatcher = inject(AXPEntityEventDispatcherService);
6684
+ await next();
6685
+ if (ctx.op === 'create') {
6686
+ const createdData = ctx.result ? { ...ctx.data, id: ctx.result } : ctx.data;
6687
+ await dispatcher.dispatchInserted(ctx.entityName, { refType: ctx.entityName, data: createdData });
6688
+ }
6689
+ else if (ctx.op === 'update') {
6690
+ await dispatcher.dispatchUpdated(ctx.entityName, {
6691
+ refType: ctx.entityName,
6692
+ data: ctx.result,
6693
+ changes: ctx.locals.get('changes'),
6694
+ });
6695
+ }
6696
+ else if (ctx.op === 'delete') {
6697
+ // For delete, prefer previous entity if available
6698
+ await dispatcher.dispatchDeleted(ctx.entityName, { refType: ctx.entityName, data: ctx.result ?? ctx.previous });
6699
+ }
6700
+ },
6701
+ };
5190
6702
 
5191
6703
  /**
5192
6704
  * Generated bundle index. Do not edit.
5193
6705
  */
5194
6706
 
5195
- export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntityApplyUpdatesAction, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityResolver, AXPEntityService, AXPEntityStorageExecutor, AXPEntityStorageRegistry, AXPEntityStorageService, AXPEntityStorageWithMiddlewareService, AXPModifyEntitySectionWorkflow, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_EXTENSION, AXP_ENTITY_STORAGE_MIDDLEWARE_SETUP, auditMiddleware, auditStorage, cachingMiddleware, composeEntityStorageMiddlewares, createModifierContext, dataSanitizationMiddleware, entityDetailsCreateActions, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, errorHandlingMiddleware, generateRequestId, loggingMiddleware, performanceMiddleware, provideEntitySpecificMiddleware, provideEntityStorageMiddleware, provideGlobalEntityStorageMiddleware, provideOperationSpecificMiddleware, userContextMiddleware, validationMiddleware };
6707
+ export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntityApplyUpdatesAction, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, DEFAULT_COLUMN_WIDTHS, actionExists, columnWidthMiddlewareFactory, columnWidthMiddlewareProvider, createColumnWidthMiddlewareProvider, createModifierContext, detectEntityChanges, ensureListActions, entityDetailsCreateActions, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware };
5196
6708
  //# sourceMappingURL=acorex-platform-layout-entity.mjs.map