@acorex/platform 20.2.4-next.9 → 20.3.0-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 (90) hide show
  1. package/common/index.d.ts +5 -119
  2. package/core/index.d.ts +67 -71
  3. package/fesm2022/acorex-platform-common.mjs +9 -19
  4. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-core.mjs +158 -113
  6. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-layout-builder.mjs +638 -1168
  8. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-layout-components.mjs +46 -1087
  10. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-layout-designer.mjs +137 -92
  12. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  13. package/fesm2022/acorex-platform-layout-entity.mjs +1064 -3100
  14. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  15. package/fesm2022/acorex-platform-layout-views.mjs +72 -332
  16. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  17. package/fesm2022/acorex-platform-themes-default-create-entity-view.component-SY0oMDoH.mjs +22 -0
  18. package/fesm2022/acorex-platform-themes-default-create-entity-view.component-SY0oMDoH.mjs.map +1 -0
  19. package/fesm2022/{acorex-platform-themes-default-entity-master-create-view.component-I7Eq8Nti.mjs → acorex-platform-themes-default-entity-master-create-view.component-hHXxHlFG.mjs} +3 -3
  20. package/fesm2022/{acorex-platform-themes-default-entity-master-create-view.component-I7Eq8Nti.mjs.map → acorex-platform-themes-default-entity-master-create-view.component-hHXxHlFG.mjs.map} +1 -1
  21. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-hf4QOz_4.mjs +665 -0
  22. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-hf4QOz_4.mjs.map +1 -0
  23. package/fesm2022/{acorex-platform-themes-default-entity-master-modify-view.component-16sdMBvH.mjs → acorex-platform-themes-default-entity-master-modify-view.component-DC3MrDtI.mjs} +10 -3
  24. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-DC3MrDtI.mjs.map +1 -0
  25. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Bb90PeHq.mjs +236 -0
  26. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Bb90PeHq.mjs.map +1 -0
  27. package/fesm2022/acorex-platform-themes-default.mjs +484 -39
  28. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  29. package/fesm2022/{acorex-platform-themes-shared-theme-color-chooser-column.component-DjKLg513.mjs → acorex-platform-themes-shared-color-chooser-column.component-DjKLg513.mjs} +1 -1
  30. package/fesm2022/acorex-platform-themes-shared-color-chooser-column.component-DjKLg513.mjs.map +1 -0
  31. package/fesm2022/{acorex-platform-themes-shared-theme-color-chooser-view.component-DE0wO98F.mjs → acorex-platform-themes-shared-color-chooser-view.component-DE0wO98F.mjs} +1 -1
  32. package/fesm2022/acorex-platform-themes-shared-color-chooser-view.component-DE0wO98F.mjs.map +1 -0
  33. package/fesm2022/acorex-platform-themes-shared.mjs +13 -11
  34. package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
  35. package/fesm2022/{acorex-platform-widgets-button-widget-designer.component-BJtkWusr.mjs → acorex-platform-widgets-button-widget-designer.component-lNF95FJv.mjs} +3 -3
  36. package/fesm2022/acorex-platform-widgets-button-widget-designer.component-lNF95FJv.mjs.map +1 -0
  37. package/fesm2022/{acorex-platform-widgets-checkbox-widget-column.component-DeKpl0uK.mjs → acorex-platform-widgets-checkbox-widget-column.component-BNBOATPB.mjs} +2 -1
  38. package/fesm2022/acorex-platform-widgets-checkbox-widget-column.component-BNBOATPB.mjs.map +1 -0
  39. package/fesm2022/{acorex-platform-widgets-checkbox-widget-designer.component-Cv7dEMCm.mjs → acorex-platform-widgets-checkbox-widget-designer.component-BI18uzNZ.mjs} +2 -2
  40. package/fesm2022/acorex-platform-widgets-checkbox-widget-designer.component-BI18uzNZ.mjs.map +1 -0
  41. package/fesm2022/{acorex-platform-widgets-color-box-widget-designer.component-CohkI1w1.mjs → acorex-platform-widgets-color-box-widget-designer.component-pYOQv5g8.mjs} +2 -2
  42. package/fesm2022/acorex-platform-widgets-color-box-widget-designer.component-pYOQv5g8.mjs.map +1 -0
  43. package/fesm2022/{acorex-platform-widgets-file-list-popup.component-BafU5Lfl.mjs → acorex-platform-widgets-file-list-popup.component-DFbPO0ud.mjs} +4 -69
  44. package/fesm2022/acorex-platform-widgets-file-list-popup.component-DFbPO0ud.mjs.map +1 -0
  45. package/fesm2022/{acorex-platform-widgets-page-widget-designer.component-Cw9WcZze.mjs → acorex-platform-widgets-page-widget-designer.component-DRsLkulH.mjs} +64 -74
  46. package/fesm2022/acorex-platform-widgets-page-widget-designer.component-DRsLkulH.mjs.map +1 -0
  47. package/fesm2022/{acorex-platform-widgets-tabular-data-edit-popup.component-BDQIfr0g.mjs → acorex-platform-widgets-tabular-data-edit-popup.component-nLZYiPnF.mjs} +5 -5
  48. package/fesm2022/{acorex-platform-widgets-tabular-data-edit-popup.component-BDQIfr0g.mjs.map → acorex-platform-widgets-tabular-data-edit-popup.component-nLZYiPnF.mjs.map} +1 -1
  49. package/fesm2022/{acorex-platform-widgets-tabular-data-view-popup.component-CmPqtt0G.mjs → acorex-platform-widgets-tabular-data-view-popup.component-D6kiasYM.mjs} +3 -3
  50. package/fesm2022/{acorex-platform-widgets-tabular-data-view-popup.component-CmPqtt0G.mjs.map → acorex-platform-widgets-tabular-data-view-popup.component-D6kiasYM.mjs.map} +1 -1
  51. package/fesm2022/{acorex-platform-widgets-text-block-widget-designer.component-DaR4Nkv4.mjs → acorex-platform-widgets-text-block-widget-designer.component-CCMQtH3e.mjs} +12 -8
  52. package/fesm2022/acorex-platform-widgets-text-block-widget-designer.component-CCMQtH3e.mjs.map +1 -0
  53. package/fesm2022/acorex-platform-widgets.mjs +1442 -2641
  54. package/fesm2022/acorex-platform-widgets.mjs.map +1 -1
  55. package/fesm2022/acorex-platform-workflow.mjs +0 -3
  56. package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
  57. package/layout/builder/index.d.ts +181 -367
  58. package/layout/components/index.d.ts +20 -217
  59. package/layout/designer/index.d.ts +47 -16
  60. package/layout/entity/index.d.ts +336 -196
  61. package/layout/views/index.d.ts +21 -118
  62. package/package.json +37 -23
  63. package/widgets/index.d.ts +224 -275
  64. package/workflow/index.d.ts +1 -3
  65. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-D3VUh8K8.mjs +0 -707
  66. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-D3VUh8K8.mjs.map +0 -1
  67. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-16sdMBvH.mjs.map +0 -1
  68. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-BMkhNfF4.mjs +0 -244
  69. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-BMkhNfF4.mjs.map +0 -1
  70. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-DjKLg513.mjs.map +0 -1
  71. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-DE0wO98F.mjs.map +0 -1
  72. package/fesm2022/acorex-platform-widgets-button-widget-designer.component-BJtkWusr.mjs.map +0 -1
  73. package/fesm2022/acorex-platform-widgets-checkbox-widget-column.component-DeKpl0uK.mjs.map +0 -1
  74. package/fesm2022/acorex-platform-widgets-checkbox-widget-designer.component-Cv7dEMCm.mjs.map +0 -1
  75. package/fesm2022/acorex-platform-widgets-color-box-widget-designer.component-CohkI1w1.mjs.map +0 -1
  76. package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-edit.component-B3SJUnGQ.mjs +0 -50
  77. package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-edit.component-B3SJUnGQ.mjs.map +0 -1
  78. package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-view.component-BLR0JkRt.mjs +0 -42
  79. package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-view.component-BLR0JkRt.mjs.map +0 -1
  80. package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-edit.component-hzR2FgOm.mjs +0 -55
  81. package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-edit.component-hzR2FgOm.mjs.map +0 -1
  82. package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-view.component-IDm6Clua.mjs +0 -50
  83. package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-view.component-IDm6Clua.mjs.map +0 -1
  84. package/fesm2022/acorex-platform-widgets-extra-properties-widget-edit.component-BRO9tYDa.mjs +0 -48
  85. package/fesm2022/acorex-platform-widgets-extra-properties-widget-edit.component-BRO9tYDa.mjs.map +0 -1
  86. package/fesm2022/acorex-platform-widgets-extra-properties-widget-view.component-CkpLimyW.mjs +0 -42
  87. package/fesm2022/acorex-platform-widgets-extra-properties-widget-view.component-CkpLimyW.mjs.map +0 -1
  88. package/fesm2022/acorex-platform-widgets-file-list-popup.component-BafU5Lfl.mjs.map +0 -1
  89. package/fesm2022/acorex-platform-widgets-page-widget-designer.component-Cw9WcZze.mjs.map +0 -1
  90. package/fesm2022/acorex-platform-widgets-text-block-widget-designer.component-DaR4Nkv4.mjs.map +0 -1
@@ -1,20 +1,19 @@
1
1
  import * as i0 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';
2
+ import { InjectionToken, inject, Injectable, computed, signal, Injector, EnvironmentInjector, runInInjectionContext, makeEnvironmentProviders, effect, HostBinding, ChangeDetectionStrategy, Component, viewChild, 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, AXPReloadEvent, AXPCleanNestedFilters, AXPWorkflowNavigateAction, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER } from '@acorex/platform/common';
7
+ import { resolveActionLook, AXPFilterOperatorMiddlewareService, AXPEntityCommandScope, getEntityInfo, AXPSettingService, AXPRefreshEvent, AXPLockService, 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, AXPDistributedEventListenerService, getChangedPaths, extractValue, setSmart } from '@acorex/platform/core';
9
+ import { AXPExpressionEvaluatorService, AXPPlatformScope, 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 i2 from '@acorex/platform/layout/builder';
13
- import { AXPPageStatus, AXPWidgetRegistryService, AXPWidgetsCatalog, AXPValueWidgetComponent, AXPWidgetRendererDirective, AXPLayoutBuilderModule, AXPWidgetGroupEnum, AXPLayoutBaseWidgetComponent, AXPColumnWidgetComponent, AXP_WIDGETS_EDITOR_CATEGORY } from '@acorex/platform/layout/builder';
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';
14
14
  import { AXPLayoutThemeService } from '@acorex/platform/themes/shared';
15
- import { Subject, takeUntil } from 'rxjs';
16
15
  import { AXPSessionService, AXPAuthGuard } from '@acorex/platform/auth';
17
- import { AXPCommandService } from '@acorex/platform/runtime';
16
+ import { Subject, takeUntil } from 'rxjs';
18
17
  import * as i8 from '@acorex/core/translation';
19
18
  import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
20
19
  import { AXDialogService } from '@acorex/components/dialog';
@@ -22,38 +21,35 @@ import { AXLoadingDialogService } from '@acorex/components/loading-dialog';
22
21
  import { AXPopupService } from '@acorex/components/popup';
23
22
  import { AXPlatform } from '@acorex/core/platform';
24
23
  import { RouterModule, ROUTES } from '@angular/router';
25
- import * as i3$1 from '@acorex/components/button';
26
- import { AXButtonModule } from '@acorex/components/button';
27
- import * as i3 from '@acorex/components/decorators';
28
- import { AXDecoratorModule } from '@acorex/components/decorators';
29
- import * as i4 from '@acorex/components/dropdown';
30
- import { AXDropdownModule } from '@acorex/components/dropdown';
31
- import * as i7 from '@angular/common';
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';
34
- import * as i1$3 from '@angular/forms';
35
- import { FormsModule } from '@angular/forms';
36
24
  import * as i1 from '@acorex/components/loading';
37
25
  import { AXLoadingModule } from '@acorex/components/loading';
38
26
  import * as i1$1 from '@acorex/components/badge';
39
27
  import { AXBadgeModule } from '@acorex/components/badge';
28
+ import * as i2 from '@acorex/components/button';
29
+ import { AXButtonModule } from '@acorex/components/button';
30
+ import * as i3 from '@acorex/components/decorators';
31
+ import { AXDecoratorModule } from '@acorex/components/decorators';
40
32
  import * as i5$1 from '@acorex/components/form';
41
33
  import { AXFormModule } from '@acorex/components/form';
42
- import * as i5 from '@acorex/components/search-box';
43
- import { AXSearchBoxModule, AXSearchBoxComponent } from '@acorex/components/search-box';
44
- import * as i7$1 from '@acorex/components/select-box';
45
- import { AXSelectBoxModule } from '@acorex/components/select-box';
46
- import * as i6 from '@acorex/components/tag-box';
34
+ import * as i6$1 from '@acorex/components/tag-box';
47
35
  import { AXTagBoxComponent, AXTagBoxModule } from '@acorex/components/tag-box';
48
36
  import { AXValidationModule } from '@acorex/core/validation';
49
- import * as i4$1 from '@acorex/components/data-table';
37
+ import * as i7 from '@angular/common';
38
+ import { CommonModule } from '@angular/common';
39
+ import * as i1$3 from '@angular/forms';
40
+ import { FormsModule } from '@angular/forms';
41
+ import * as i4 from '@acorex/components/data-table';
50
42
  import { AXDataTableModule } from '@acorex/components/data-table';
51
43
  import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
52
44
  import { AXBasePageComponent } from '@acorex/components/page';
45
+ import * as i5 from '@acorex/components/search-box';
46
+ import { AXSearchBoxModule, AXSearchBoxComponent } from '@acorex/components/search-box';
47
+ import * as i7$1 from '@acorex/components/select-box';
48
+ 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';
53
50
  import * as i2$1 from '@acorex/components/text-box';
54
51
  import { AXTextBoxModule, AXTextBoxComponent } from '@acorex/components/text-box';
55
- import { AXPWidgetPropertyViewerComponent } from '@acorex/platform/layout/components';
56
- import { transform, isEqual } from 'lodash';
52
+ import { AXPWidgetPropertyViewerComponent } from '@acorex/platform/layout/designer';
57
53
 
58
54
  const AXP_DATA_SEEDER_TOKEN = new InjectionToken('AXP_DATA_SEEDER_TOKEN');
59
55
  class AXPDataSeederService {
@@ -383,6 +379,7 @@ class AXPEntityDetailListViewModel {
383
379
  (a.scope == AXPEntityCommandScope.TypeLevel && !this.hasSelectedItems())))
384
380
  .map(async (a) => {
385
381
  const isHidden = await this.evaluateExpressions(a.hidden);
382
+ debugger;
386
383
  if (isHidden)
387
384
  return null;
388
385
  const disabled = await this.evaluateExpressions(a.disabled);
@@ -564,15 +561,6 @@ function createModifierContext(entity) {
564
561
  entity.interfaces.master = updater(entity.interfaces.master);
565
562
  return ctx;
566
563
  },
567
- list: {
568
- get: () => entity.interfaces?.master?.list,
569
- update: (updater) => {
570
- entity.interfaces ??= {};
571
- entity.interfaces.master ??= {};
572
- entity.interfaces.master.list = updater(entity.interfaces.master.list);
573
- return ctx;
574
- },
575
- },
576
564
  create: {
577
565
  get: () => entity.interfaces?.master?.create,
578
566
  update: (updater) => {
@@ -626,98 +614,25 @@ function createModifierContext(entity) {
626
614
 
627
615
  const AXP_ENTITY_MODIFIER = new InjectionToken('AXP_ENTITY_MODIFIER');
628
616
 
629
- function ensureListActions(ctx) {
630
- ctx.interfaces.update((i) => {
631
- const next = i ?? {};
632
- next.master = next.master ?? {};
633
- next.master.list = next.master.list ?? { actions: [], views: [] };
634
- next.master.list.actions = next.master.list.actions ?? [];
635
- return next;
636
- });
637
- }
638
- function actionExists(actions, commandName, name) {
639
- if (!actions)
640
- return false;
641
- return actions.some((a) => {
642
- const cmd = typeof a.command === 'object' ? a.command?.name : a.command;
643
- if (name && a.name) {
644
- return a.name === name;
645
- }
646
- return cmd === commandName;
647
- });
648
- }
649
-
650
- const AXP_ENTITY_ACTION_PLUGIN = new InjectionToken('AXP_ENTITY_ACTION_PLUGIN');
651
-
652
617
  class AXPEntityMiddleware {
653
- //#endregion
654
- //#region ---- Constructor ----
655
618
  constructor() {
656
- //#region ---- Fields ----
657
- this.exactModifiers = new Map();
658
- this.patternModifiers = [];
619
+ this.modifiers = new Map();
659
620
  this.providedModifiers = inject(AXP_ENTITY_MODIFIER, { optional: true }) || [];
660
- this.providedActionPlugins = inject(AXP_ENTITY_ACTION_PLUGIN, { optional: true }) || [];
661
- this.injector = inject(Injector);
662
621
  for (const { entityName, modifier } of this.providedModifiers) {
663
622
  this.register(entityName, modifier);
664
623
  }
665
624
  }
666
- //#endregion
667
- //#region ---- Registration Methods ----
668
625
  register(entityName, modifier) {
669
- if (entityName instanceof RegExp) {
670
- this.patternModifiers.push({ pattern: this.normalizeRegExp(entityName), modifier });
671
- return;
672
- }
673
- if (entityName.includes('*')) {
674
- const pattern = this.wildcardToRegExp(entityName);
675
- this.patternModifiers.push({ pattern, modifier });
676
- return;
677
- }
678
- this.exactModifiers.set(entityName, modifier);
626
+ this.modifiers.set(entityName, modifier);
679
627
  }
680
- //#endregion
681
- //#region ---- Processing ----
682
- async process(entity) {
683
- // First, expand action plugins if entity.plugins exists
628
+ process(entity) {
629
+ const modifier = this.modifiers.get(entity.name);
630
+ if (!modifier)
631
+ return entity;
684
632
  const context = createModifierContext(entity);
685
- const plugins = entity.plugins;
686
- if (plugins && plugins.length) {
687
- const sorted = [...this.providedActionPlugins].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
688
- for (const p of plugins) {
689
- const contrib = sorted.find((x) => x.name === p.name);
690
- if (contrib) {
691
- try {
692
- await runInInjectionContext(this.injector, () => contrib.apply(context, p.options));
693
- }
694
- catch (err) {
695
- console.error('[AXPEntityMiddleware] action plugin failed:', p.name, err);
696
- }
697
- }
698
- }
699
- }
700
- // Then apply entity-specific modifiers
701
- // Exact match first
702
- const exact = this.exactModifiers.get(entity.name);
703
- const modifier = exact ?? this.patternModifiers.find((x) => x.pattern.test(entity.name))?.modifier;
704
- if (!modifier) {
705
- return context.toEntity();
706
- }
707
633
  modifier(context);
708
634
  return context.toEntity();
709
635
  }
710
- //#endregion
711
- //#region ---- Helpers ----
712
- wildcardToRegExp(pattern) {
713
- const escaped = pattern.replace(/[.+?^${}()|\[\]\\]/g, '\\$&');
714
- const regexStr = `^${escaped.replace(/\*/g, '.*')}$`;
715
- return new RegExp(regexStr);
716
- }
717
- normalizeRegExp(rx) {
718
- const flags = rx.flags.replace('g', '');
719
- return new RegExp(rx.source, flags);
720
- }
721
636
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityMiddleware, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
722
637
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityMiddleware, providedIn: 'root' }); }
723
638
  }
@@ -731,15 +646,11 @@ class AXPEntityDefinitionRegistryService {
731
646
  this.providers = inject(AXP_ENTITY_DEFINITION_LOADER);
732
647
  this.resolver = inject(AXPEntityResolver);
733
648
  this.middleware = inject(AXPEntityMiddleware);
734
- this.onChanged = new Subject();
735
649
  // Stores AXPEntityConfig objects, keyed by a combination of module and entity name.
736
650
  this.entities = new Map();
737
651
  // Entity resolver service for dynamically loading entity configurations.
738
652
  this.entityResolver = inject(AXPEntityResolver); // Assuming AXPEntityLoader is the correct type
739
653
  }
740
- get onChanged$() {
741
- return this.onChanged.asObservable();
742
- }
743
654
  async preload() {
744
655
  const providers = Array.isArray(this.providers)
745
656
  ? this.providers
@@ -760,14 +671,14 @@ class AXPEntityDefinitionRegistryService {
760
671
  .catch(err => {
761
672
  console.error(`[AXPEntityDefinitionRegistryService] Failed to load entity ${item.module}.${item.entity}:`, err);
762
673
  return null;
763
- }), 10000, `${item.module}.${item.entity}`));
674
+ }), 3000, `${item.module}.${item.entity}`));
764
675
  });
765
676
  });
766
677
  const results = await Promise.allSettled(promises);
767
678
  const loadedEntities = [];
768
- results.forEach(async (result, idx) => {
679
+ results.forEach((result, idx) => {
769
680
  if (result.status === 'fulfilled' && result.value != null) {
770
- this.register(await this.middleware.process(result.value));
681
+ this.register(this.middleware.process(result.value));
771
682
  loadedEntities.push(result.value);
772
683
  }
773
684
  else if (result.status === 'rejected') {
@@ -776,43 +687,6 @@ class AXPEntityDefinitionRegistryService {
776
687
  });
777
688
  //console.log('[AXPEntityDefinitionRegistryService] Loaded entities:', loadedEntities);
778
689
  }
779
- async refresh(arg1, arg2) {
780
- // No parameters: refresh all currently registered entities
781
- if (typeof arg1 === 'undefined' && typeof arg2 === 'undefined') {
782
- const keys = Array.from(this.entities.keys());
783
- for (const key of keys) {
784
- const [m, e] = key.split('.');
785
- if (m && e) {
786
- await this.refreshOne(m, e);
787
- }
788
- }
789
- return;
790
- }
791
- // One parameter: treat as fully-qualified name
792
- if (typeof arg1 === 'string' && typeof arg2 === 'undefined') {
793
- const [moduleName, entityName] = arg1.split('.');
794
- if (!moduleName || !entityName) {
795
- throw new Error(`Invalid entity full name: ${arg1}`);
796
- }
797
- await this.refreshOne(moduleName, entityName);
798
- return;
799
- }
800
- // Two parameters: module + entity
801
- if (typeof arg1 === 'string' && typeof arg2 === 'string') {
802
- await this.refreshOne(arg1, arg2);
803
- return;
804
- }
805
- }
806
- /** Executes the actual refresh for a single entity */
807
- async refreshOne(moduleName, entityName) {
808
- const config = await this.entityResolver.get(moduleName, entityName);
809
- if (!config) {
810
- throw new Error(`Invalid entity name: ${moduleName}.${entityName}`);
811
- }
812
- const processedConfig = await this.middleware.process(config);
813
- this.register(processedConfig);
814
- }
815
- //#endregion
816
690
  /**
817
691
  * Registers a new entity configuration. Entities are identified uniquely by a combination
818
692
  * of their module and name.
@@ -822,7 +696,6 @@ class AXPEntityDefinitionRegistryService {
822
696
  register(config) {
823
697
  const key = this.createEntityKey(config.module, config.name);
824
698
  this.entities.set(key, config);
825
- this.onChanged.next({ name: key });
826
699
  }
827
700
  /**
828
701
  * Returns an array of all registered entity configurations.
@@ -849,7 +722,7 @@ class AXPEntityDefinitionRegistryService {
849
722
  try {
850
723
  config = await this.entityResolver.get(moduleName, entityName);
851
724
  if (config) {
852
- const processedConfig = await this.middleware.process(config);
725
+ const processedConfig = this.middleware.process(config);
853
726
  this.register(processedConfig);
854
727
  return processedConfig;
855
728
  }
@@ -943,7 +816,6 @@ class AXPEntityCreateViewElementViewModel {
943
816
  children: widget.children,
944
817
  formula: widget.formula,
945
818
  triggers: widget.triggers,
946
- defaultValue: schema.defaultValue,
947
819
  valueTransforms: widget.valueTransforms,
948
820
  options: merge(schema.interface?.options, {
949
821
  validations: this.property.validations?.map((c) => ({ rule: c.rule, message: c.message, options: c.options })),
@@ -971,7 +843,6 @@ class AXPEntityMasterCreateViewModel {
971
843
  const createProps = interfaces?.master?.create?.properties?.map(({ name }) => name) ?? [];
972
844
  const visibleProperties = properties.filter(({ groupId, schema, name }) => groupId && !schema.hidden && createProps.includes(name));
973
845
  const sections = interfaces?.master?.create?.sections?.filter(({ id }) => visibleProperties.some(({ groupId }) => groupId === id)) ?? [];
974
- console.log({ sections, visibleProperties });
975
846
  return sections.map((section) => new AXPEntityCreateViewSectionViewModel(this.entityDef, section));
976
847
  }, ...(ngDevMode ? [{ debugName: "sections" }] : []));
977
848
  if (!initialData)
@@ -987,6 +858,22 @@ class AXPEntityMasterCreateViewModel {
987
858
  },
988
859
  },
989
860
  };
861
+ const processDefault = async (value) => {
862
+ if (typeof value == 'function') {
863
+ return value();
864
+ }
865
+ else if (typeof value == 'string' && value.startsWith('{{')) {
866
+ return await this.expressionEvaluator.evaluate(value, scope);
867
+ }
868
+ return value;
869
+ };
870
+ this.config.properties
871
+ .filter((c) => !isNil(c.schema.defaultValue))
872
+ .forEach(async (p) => {
873
+ const value = await processDefault(p.schema.defaultValue);
874
+ set(initialData, p.name, value);
875
+ });
876
+ //
990
877
  this.context.set(initialData);
991
878
  this.options.set(commandOptions);
992
879
  //
@@ -1069,7 +956,7 @@ class AXPEntityMasterListViewModel {
1069
956
  this.applyViewColumns();
1070
957
  this.applyViewFilters();
1071
958
  // this.applyFilterAndSort();
1072
- await this.applySettings();
959
+ this.applySettings();
1073
960
  }
1074
961
  }
1075
962
  constructor(injector, config) {
@@ -1083,12 +970,9 @@ class AXPEntityMasterListViewModel {
1083
970
  this.settings = this.injector.get(AXPSettingService);
1084
971
  this.widgetResolver = this.injector.get(AXPWidgetRegistryService);
1085
972
  this.expressionEvaluator = this.injector.get(AXPExpressionEvaluatorService);
1086
- this.commandService = this.injector.get(AXPCommandService);
1087
973
  this.filterOperatorMiddleware = this.injector.get(AXPFilterOperatorMiddlewareService);
1088
974
  this.settingEntityKey = `${this.config.module}:${this.config.name}`;
1089
975
  this.destroyed = new Subject();
1090
- this.lastAppliedSortKey = null;
1091
- this.lastAppliedFilterKey = null;
1092
976
  this.events$ = new Subject();
1093
977
  //****************** Views ******************//
1094
978
  this.views = computed(() => {
@@ -1157,28 +1041,10 @@ class AXPEntityMasterListViewModel {
1157
1041
  const visibleProperties = properties.filter(({ schema }) => !schema?.hidden);
1158
1042
  const visiblePropNames = new Set(visibleProperties.map(({ name }) => name));
1159
1043
  return columns
1160
- .filter(({ name, showAs }) => visiblePropNames.has(name) || showAs)
1044
+ .filter(({ name }) => visiblePropNames.has(name))
1161
1045
  .map((column) => {
1162
- if (column.showAs) {
1163
- const widgetConfig = this.widgetResolver.resolve(column.showAs.type);
1164
- const property = {
1165
- ...widgetConfig,
1166
- name: column.name,
1167
- title: column.title ?? '',
1168
- schema: {
1169
- dataType: 'string',
1170
- interface: {
1171
- type: column.showAs.type,
1172
- options: column.showAs.options,
1173
- },
1174
- },
1175
- };
1176
- return new AXPEntityListViewColumnViewModel(property, column);
1177
- }
1178
- else {
1179
- const property = visibleProperties.find(({ name }) => name === column.name);
1180
- return new AXPEntityListViewColumnViewModel(property, column);
1181
- }
1046
+ const property = visibleProperties.find(({ name }) => name === column.name);
1047
+ return new AXPEntityListViewColumnViewModel(property, column);
1182
1048
  });
1183
1049
  };
1184
1050
  this.visibleColumnCount = () => {
@@ -1220,7 +1086,7 @@ class AXPEntityMasterListViewModel {
1220
1086
  return await this.expressionEvaluator.evaluate(options, scope);
1221
1087
  };
1222
1088
  this.workflow.events$
1223
- .pipe(ofType(AXPRefreshEvent, AXPReloadEvent))
1089
+ .pipe(ofType(AXPRefreshEvent))
1224
1090
  .pipe(takeUntil(this.destroyed))
1225
1091
  .subscribe((event) => {
1226
1092
  if (event.payload.entity == getEntityInfo(this.entityDef).source) {
@@ -1234,37 +1100,19 @@ class AXPEntityMasterListViewModel {
1234
1100
  this.saveSettings('view');
1235
1101
  const listViewSetting = await this.settings.get(this.settingEntityKey);
1236
1102
  if (listViewSetting) {
1237
- const columns = listViewSetting.list?.views?.[this.view().name]?.columns;
1238
- const pageSize = listViewSetting.list?.views?.[this.view().name]?.pageSize;
1239
- const sorts = listViewSetting.list?.views?.[this.view().name]?.sorts;
1240
- const filters = listViewSetting.list?.views?.[this.view().name]?.filters;
1241
- let columnVisibilityMap;
1242
- let columnWidthsMap;
1243
- if (columns) {
1244
- columnVisibilityMap = new Map(columns.map((col) => [col.name, col.visible]));
1245
- columnWidthsMap = new Map(columns.map((col) => [col.name, col.width]));
1246
- }
1247
- // Do not set pageSize here to avoid triggering an extra load
1248
- if (columns && columnVisibilityMap && columnWidthsMap) {
1249
- this.columns.update((prev) => prev
1250
- .map((c) => {
1251
- return {
1252
- ...c,
1253
- width: columnWidthsMap.get(c.name),
1254
- visible: columnVisibilityMap.get(c.name) ?? c.visible,
1255
- };
1256
- }) // Update visibility
1257
- .sort((a, b) => columns.findIndex((col) => col.name === a.name) -
1258
- columns.findIndex((col) => col.name === b.name)));
1259
- }
1260
- if (Array.isArray(sorts)) {
1261
- // sorts are AXPSortQuery[]; ensure we map by name
1262
- const sortsMap = new Map(sorts.map((s) => [s.name, s.dir]));
1263
- this.sortedFields.update((prev) => prev.map((sf) => ({ ...sf, dir: sortsMap.get(sf.name) || sf.dir })));
1264
- }
1265
- if (Array.isArray(filters)) {
1266
- this.filterQueries.set(filters);
1267
- }
1103
+ const columns = listViewSetting.list.views[this.view().name].columns;
1104
+ const pageSize = listViewSetting.list.views[this.view().name].pageSize;
1105
+ const columnVisibilityMap = new Map(columns.map((col) => [col.name, col.visible]));
1106
+ const columnWidthsMap = new Map(columns.map((col) => [col.name, col.width]));
1107
+ // if (pageSize) {
1108
+ // this.dataSource.setPageSize(pageSize);
1109
+ // }
1110
+ this.columns.update((prev) => prev
1111
+ .map((c) => {
1112
+ return { ...c, width: columnWidthsMap.get(c.name), visible: columnVisibilityMap.get(c.name) ?? c.visible };
1113
+ }) // Update visibility
1114
+ .sort((a, b) => columns.findIndex((col) => col.name === a.name) -
1115
+ columns.findIndex((col) => col.name === b.name)));
1268
1116
  }
1269
1117
  }
1270
1118
  async saveSettings(changesType, data) {
@@ -1318,36 +1166,6 @@ class AXPEntityMasterListViewModel {
1318
1166
  },
1319
1167
  }));
1320
1168
  break;
1321
- case 'filters':
1322
- updateSettings((prev) => ({
1323
- ...prev,
1324
- list: {
1325
- ...prev?.list,
1326
- views: {
1327
- ...prev?.list?.views,
1328
- [this.view().name]: {
1329
- ...prev?.list?.views?.[this.view().name],
1330
- filters: data,
1331
- },
1332
- },
1333
- },
1334
- }));
1335
- break;
1336
- case 'sorts':
1337
- updateSettings((prev) => ({
1338
- ...prev,
1339
- list: {
1340
- ...prev?.list,
1341
- views: {
1342
- ...prev?.list?.views,
1343
- [this.view().name]: {
1344
- ...prev?.list?.views?.[this.view().name],
1345
- sorts: data,
1346
- },
1347
- },
1348
- },
1349
- }));
1350
- break;
1351
1169
  default:
1352
1170
  break;
1353
1171
  }
@@ -1440,30 +1258,21 @@ class AXPEntityMasterListViewModel {
1440
1258
  operator: f.operator,
1441
1259
  value: f.value,
1442
1260
  }));
1443
- this.filterQueries.set(viewFilters);
1261
+ this.filterQueries.update((prev) => ({ ...prev, filters: viewFilters }));
1444
1262
  }
1445
1263
  resetFilters() {
1446
1264
  this.applyViewFilters();
1447
1265
  }
1448
1266
  async applyFilterAndSort() {
1449
- const sorts = this.sortedFields()
1450
- .filter((sf) => sf.dir)
1451
- .map((s) => ({ name: s.name, dir: s.dir }));
1452
- const filters = this.filterQueries();
1453
- const sortKey = JSON.stringify(sorts);
1454
- const filterKey = JSON.stringify(filters);
1455
- if (sortKey === this.lastAppliedSortKey && filterKey === this.lastAppliedFilterKey) {
1456
- return; // No effective change; avoid redundant refresh
1457
- }
1458
- this.lastAppliedSortKey = sortKey;
1459
- this.lastAppliedFilterKey = filterKey;
1460
1267
  this.dataSource.clearFilter();
1461
- this.dataSource.sort(...sorts.map((s) => ({ dir: s.dir, field: s.name })));
1268
+ this.dataSource.sort(...this.sortedFields()
1269
+ .filter((sf) => sf.dir)
1270
+ .map((s) => ({ dir: s.dir, field: s.name })));
1462
1271
  this.dataSource.filter(this.filterOperatorMiddleware.transformFilter({
1463
1272
  field: null,
1464
1273
  logic: 'and',
1465
1274
  operator: null,
1466
- filters: filters,
1275
+ filters: this.filterQueries(),
1467
1276
  }));
1468
1277
  this.dataSource.refresh();
1469
1278
  }
@@ -1477,7 +1286,8 @@ class AXPEntityMasterListViewModel {
1477
1286
  const cols = this.view().columns;
1478
1287
  const cloned = this.allAvailableColumns().map((c) => {
1479
1288
  const column = this.entityDef.columns?.find((cc) => cc.name == c.name);
1480
- const col = new AXPEntityListViewColumnViewModel(c.property, column);
1289
+ const prop = this.entityDef.properties.find((p) => p.name == c.name);
1290
+ const col = new AXPEntityListViewColumnViewModel(prop, column);
1481
1291
  col.visible = !cols.some((c) => c == col.name) && col.visible != false;
1482
1292
  return col;
1483
1293
  });
@@ -1510,24 +1320,19 @@ class AXPEntityMasterListViewModel {
1510
1320
  });
1511
1321
  const command = commandName.split('&')[0];
1512
1322
  const options = await this.evaluateExpressions(action?.options, data);
1513
- if (this.workflow.exists(command)) {
1514
- await this.workflow.execute(command, {
1515
- entity: getEntityInfo(this.entityDef).source,
1516
- entityInfo: {
1517
- name: this.entityDef.name,
1518
- module: this.entityDef.module,
1519
- title: this.entityDef.title,
1520
- parentKey: this.entityDef.parentKey,
1521
- source: this.entityDef.source,
1522
- },
1523
- data: action?.scope == AXPEntityCommandScope.Selected ? this.selectedItems() : data,
1524
- options: options,
1525
- metadata: action?.metadata,
1526
- });
1527
- }
1528
- else {
1529
- this.commandService.execute(command, options);
1530
- }
1323
+ await this.workflow.execute(command, {
1324
+ entity: getEntityInfo(this.entityDef).source,
1325
+ entityInfo: {
1326
+ name: this.entityDef.name,
1327
+ module: this.entityDef.module,
1328
+ title: this.entityDef.title,
1329
+ parentKey: this.entityDef.parentKey,
1330
+ source: this.entityDef.source,
1331
+ },
1332
+ data: action?.scope == AXPEntityCommandScope.Selected ? this.selectedItems() : data,
1333
+ options: options,
1334
+ metadata: action?.metadata,
1335
+ });
1531
1336
  }
1532
1337
  async execute(command) {
1533
1338
  switch (command?.name) {
@@ -1829,6 +1634,7 @@ class AXPEntityMasterUpdateViewModel {
1829
1634
  this.props = props;
1830
1635
  this.entityDef = cloneDeep(this.config);
1831
1636
  this.workflow = this.injector.get(AXPWorkflowService);
1637
+ this.lockService = this.injector.get(AXPLockService);
1832
1638
  this.sessionService = this.injector.get(AXPSessionService);
1833
1639
  this.isInProgress = signal(false, ...(ngDevMode ? [{ debugName: "isInProgress" }] : []));
1834
1640
  this.context = signal(cloneDeep(this.entityData), ...(ngDevMode ? [{ debugName: "context" }] : []));
@@ -1838,6 +1644,19 @@ class AXPEntityMasterUpdateViewModel {
1838
1644
  return new AXPEntityMasterUpdateElementViewModel(this.entityDef, e);
1839
1645
  });
1840
1646
  }, ...(ngDevMode ? [{ debugName: "elements" }] : []));
1647
+ // Lock the record on creation
1648
+ if (this.entityId) {
1649
+ this.lockService.lock({
1650
+ refId: this.entityId,
1651
+ refType: `${this.moduleName}.${this.entityName}`,
1652
+ type: 'user',
1653
+ date: new Date().toISOString(),
1654
+ lockedBy: {
1655
+ id: this.sessionService.user?.id ?? 'system',
1656
+ type: 'oidc.users',
1657
+ },
1658
+ });
1659
+ }
1841
1660
  }
1842
1661
  async save() {
1843
1662
  this.isInProgress.set(true);
@@ -1862,6 +1681,15 @@ class AXPEntityMasterUpdateViewModel {
1862
1681
  reset() {
1863
1682
  this.context.set(cloneDeep(this.entityData));
1864
1683
  }
1684
+ async unlock() {
1685
+ if (this.entityId) {
1686
+ await this.lockService.unlock({
1687
+ refId: this.entityId,
1688
+ refType: `${this.moduleName}.${this.entityName}`,
1689
+ type: 'user',
1690
+ });
1691
+ }
1692
+ }
1865
1693
  }
1866
1694
  class AXPEntityMasterUpdateViewModelFactory {
1867
1695
  constructor() {
@@ -1993,6 +1821,7 @@ class AXPEntityMasterSingleViewGroupViewModel {
1993
1821
  this.group = this.entity.groups?.find((c) => c.id == this.section.id);
1994
1822
  this.name = signal(this.group.id, ...(ngDevMode ? [{ debugName: "name" }] : []));
1995
1823
  this.isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
1824
+ this.type = signal(this.section.type ?? 'section', ...(ngDevMode ? [{ debugName: "type" }] : []));
1996
1825
  this.title = computed(() => {
1997
1826
  return this.group.title ?? this.group.id;
1998
1827
  }, ...(ngDevMode ? [{ debugName: "title" }] : []));
@@ -2065,14 +1894,10 @@ class AXPEntityMasterSingleViewModel {
2065
1894
  this.session = this.injector.get(AXPSessionService);
2066
1895
  this.formatService = this.injector.get(AXFormatService);
2067
1896
  this.workflow = this.injector.get(AXPWorkflowService);
2068
- this.commandService = this.injector.get(AXPCommandService);
2069
1897
  this.destroyed = new Subject();
2070
1898
  this.translateService = this.injector.get(AXTranslationService);
2071
1899
  this.entityService = this.injector.get(AXPEntityService);
2072
1900
  this.expressionEvaluator = this.injector.get(AXPExpressionEvaluatorService);
2073
- this.entityDefinitionRegistryService = this.injector.get(AXPEntityDefinitionRegistryService);
2074
- this._updateTrigger = signal(1, ...(ngDevMode ? [{ debugName: "_updateTrigger" }] : []));
2075
- this.updateTrigger = this._updateTrigger.asReadonly();
2076
1901
  this.context = signal(cloneDeep(this.entityData), ...(ngDevMode ? [{ debugName: "context" }] : []));
2077
1902
  this.actions = computed(() => {
2078
1903
  return (this.entityDef.interfaces?.master?.single?.actions?.map((tr) => new AXPEntityCommandTriggerViewModel(this.entityDef, tr)) ?? []);
@@ -2156,13 +1981,6 @@ class AXPEntityMasterSingleViewModel {
2156
1981
  this.context.set(event.payload.values);
2157
1982
  }
2158
1983
  });
2159
- this.entityDefinitionRegistryService.onChanged$
2160
- .pipe(takeUntil(this.destroyed))
2161
- .subscribe((event) => {
2162
- if (event.name == getEntityInfo(this.entityDef).source) {
2163
- this._updateTrigger.set(this._updateTrigger() + 1);
2164
- }
2165
- });
2166
1984
  }
2167
1985
  navigateToUp() {
2168
1986
  this.workflow.execute('navigate', {
@@ -2172,7 +1990,7 @@ class AXPEntityMasterSingleViewModel {
2172
1990
  });
2173
1991
  }
2174
1992
  async executeCommand(commandName, data = null) {
2175
- //TODO: syntax for workflow
1993
+ //TODO: syntact for workflow
2176
1994
  const command = commandName.split('&')[0];
2177
1995
  switch (command) {
2178
1996
  case 'modify-entity-section': {
@@ -2188,17 +2006,11 @@ class AXPEntityMasterSingleViewModel {
2188
2006
  default: {
2189
2007
  const action = this.actions().find((c) => c.name == commandName);
2190
2008
  const options = await this.evaluateExpressions(action?.options, this.context());
2191
- //
2192
- if (this.workflow.exists(command)) {
2193
- this.workflow.execute(command, {
2194
- entity: getEntityInfo(this.entityDef).source,
2195
- data: this.context(),
2196
- options,
2197
- });
2198
- }
2199
- else {
2200
- this.commandService.execute(command, data);
2201
- }
2009
+ this.workflow.execute(command, {
2010
+ entity: getEntityInfo(this.entityDef).source,
2011
+ data: this.context(),
2012
+ options,
2013
+ });
2202
2014
  }
2203
2015
  }
2204
2016
  }
@@ -2256,9 +2068,6 @@ const AXPEntityDetailViewModelResolver = (route, state, service = inject(AXPEnti
2256
2068
  return service.create(moduleName, entityName, id);
2257
2069
  };
2258
2070
 
2259
- const AXP_ENTITY_STORAGE_BACKEND = new InjectionToken('AXP_ENTITY_STORAGE_BACKEND');
2260
- const AXP_ENTITY_STORAGE_MIDDLEWARE = new InjectionToken('AXP_ENTITY_STORAGE_MIDDLEWARE');
2261
-
2262
2071
  class AXPEntityStorageService {
2263
2072
  }
2264
2073
  class AXPEntityDataProvider {
@@ -2382,2573 +2191,776 @@ class AXMEntityCrudServiceImpl {
2382
2191
  }
2383
2192
  }
2384
2193
 
2385
- class AXPMiddlewareEntityStorageService extends AXPEntityStorageService {
2386
- constructor() {
2387
- super(...arguments);
2388
- this.backend = inject(AXP_ENTITY_STORAGE_BACKEND);
2389
- this.allMiddlewares = (inject(AXP_ENTITY_STORAGE_MIDDLEWARE, { optional: true }) || []).slice();
2390
- this.injector = inject(EnvironmentInjector);
2391
- }
2392
- get dbName() {
2393
- return this.backend.dbName;
2394
- }
2395
- filterMiddlewares(ctx) {
2396
- return this.allMiddlewares
2397
- .filter((mw) => {
2398
- const t = mw.target;
2399
- if (!t)
2400
- return true;
2401
- if (t.ops && !t.ops.includes(ctx.op))
2402
- return false;
2403
- if (t.entity) {
2404
- if (typeof t.entity === 'string' && t.entity !== ctx.entityName)
2405
- return false;
2406
- if (t.entity instanceof RegExp && !t.entity.test(ctx.entityName))
2407
- return false;
2408
- }
2409
- if (t.predicate && !t.predicate(ctx))
2410
- return false;
2411
- return true;
2412
- })
2413
- .sort((a, b) => (a.target?.order ?? 0) - (b.target?.order ?? 0));
2414
- }
2415
- compose(mws, leaf, ctx) {
2416
- return mws
2417
- .slice()
2418
- .reverse()
2419
- .reduce((next, mw) => {
2420
- return async () => runInInjectionContext(this.injector, () => mw.execute(ctx, next));
2421
- }, leaf);
2422
- }
2423
- async run(ctx, delegate) {
2424
- const chain = this.compose(this.filterMiddlewares(ctx), async () => {
2425
- ctx.result = await delegate();
2426
- }, ctx);
2427
- await chain();
2428
- return ctx.result;
2429
- }
2430
- createCtx(op, entityName, init) {
2431
- return {
2432
- op,
2433
- entityName,
2434
- locals: new Map(),
2435
- backend: {
2436
- getOneRaw: (name, id) => this.backend.getOne(name, id),
2437
- insertOneRaw: (name, e) => this.backend.insertOne(name, e),
2438
- },
2439
- ...init,
2440
- };
2441
- }
2442
- async initial(entityName, collection, options) {
2443
- const ctx = this.createCtx('initial', entityName, { data: collection });
2444
- return this.run(ctx, () => this.backend.initial(entityName, ctx.data, options));
2445
- }
2446
- async getOne(entityName, id) {
2447
- const ctx = this.createCtx('getOne', entityName, { id });
2448
- return this.run(ctx, () => this.backend.getOne(entityName, id));
2449
- }
2450
- async updateOne(entityName, id, keyValues) {
2451
- const ctx = this.createCtx('update', entityName, { id, data: keyValues });
2452
- return this.run(ctx, () => this.backend.updateOne(entityName, id, ctx.data));
2453
- }
2454
- async deleteOne(entityName, id) {
2455
- const ctx = this.createCtx('delete', entityName, { id });
2456
- return this.run(ctx, () => this.backend.deleteOne(entityName, id));
2457
- }
2458
- async insertOne(entityName, entity) {
2459
- const ctx = this.createCtx('create', entityName, { data: entity });
2460
- return this.run(ctx, () => this.backend.insertOne(entityName, ctx.data));
2461
- }
2462
- async getAll(entityName) {
2463
- const ctx = this.createCtx('getAll', entityName);
2464
- return this.run(ctx, () => this.backend.getAll(entityName));
2465
- }
2466
- async query(entityName, request) {
2467
- const ctx = this.createCtx('query', entityName, { request });
2468
- return this.run(ctx, () => this.backend.query(entityName, request));
2469
- }
2470
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMiddlewareEntityStorageService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
2471
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMiddlewareEntityStorageService }); }
2194
+ /**
2195
+ * Compose entity storage middlewares into a pipeline
2196
+ */
2197
+ function composeEntityStorageMiddlewares(middlewares) {
2198
+ return (handler) => {
2199
+ let composed = handler;
2200
+ // Reverse order composition for proper middleware chain
2201
+ for (let i = middlewares.length - 1; i >= 0; i--) {
2202
+ const mw = middlewares[i];
2203
+ const next = composed;
2204
+ composed = (context) => mw(context, next);
2205
+ }
2206
+ return composed;
2207
+ };
2208
+ }
2209
+ /**
2210
+ * Helper function to generate unique request ID
2211
+ */
2212
+ function generateRequestId() {
2213
+ return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
2472
2214
  }
2473
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMiddlewareEntityStorageService, decorators: [{
2474
- type: Injectable
2475
- }] });
2476
2215
 
2477
2216
  /**
2478
- * Entity Event Dispatcher - A wrapper for entity-specific events
2479
- * Handles pattern-based dispatching for entity operations with wildcard support
2217
+ * Registry for managing entity storage middlewares
2480
2218
  */
2481
- class AXPEntityEventDispatcherService {
2219
+ class AXPEntityStorageRegistry {
2482
2220
  constructor() {
2483
- this.eventService = inject(AXPDistributedEventListenerService);
2221
+ this.globalMiddlewares = [];
2222
+ this.entitySpecificMiddlewares = new Map();
2223
+ this.operationSpecificMiddlewares = new Map();
2484
2224
  }
2485
- async dispatchEntityEvent(operation, entityName, data) {
2486
- const enhancedData = {
2487
- ...data,
2488
- entityName,
2489
- operation,
2490
- timestamp: new Date(),
2491
- source: 'entity-dispatcher',
2492
- };
2493
- const eventKeysToDispatch = await this.getAllMatchingEventKeys(operation, entityName);
2494
- const dispatchPromises = eventKeysToDispatch.map((key) => this.eventService.dispatch(key, enhancedData));
2495
- await Promise.all(dispatchPromises);
2496
- }
2497
- async getAllMatchingEventKeys(operation, entityName) {
2498
- const eventKeys = new Set();
2499
- const exactKeys = this.generateEventKeys(operation, entityName);
2500
- exactKeys.forEach((key) => eventKeys.add(key));
2501
- const wildcardKeys = await this.findMatchingWildcardKeys(operation, entityName);
2502
- wildcardKeys.forEach((key) => eventKeys.add(key));
2503
- return Array.from(eventKeys);
2504
- }
2505
- async findMatchingWildcardKeys(operation, entityName) {
2506
- const matchingKeys = [];
2507
- const allListenerKeys = await this.eventService.getRegisteredKeys();
2508
- const actualEventKey = `entity.${operation}.${entityName}`;
2509
- for (const listenerKey of allListenerKeys) {
2510
- if (listenerKey.includes('*') && this.matchesEntityPattern(actualEventKey, listenerKey)) {
2511
- matchingKeys.push(listenerKey);
2512
- }
2225
+ /**
2226
+ * Add a global middleware that applies to all operations
2227
+ */
2228
+ useGlobal(middleware) {
2229
+ this.globalMiddlewares.push(middleware);
2230
+ }
2231
+ /**
2232
+ * Add middleware for specific entity
2233
+ */
2234
+ useForEntity(entityName, middleware) {
2235
+ if (!this.entitySpecificMiddlewares.has(entityName)) {
2236
+ this.entitySpecificMiddlewares.set(entityName, []);
2513
2237
  }
2514
- return matchingKeys;
2238
+ this.entitySpecificMiddlewares.get(entityName).push(middleware);
2515
2239
  }
2516
- matchesEntityPattern(eventKey, pattern) {
2517
- if (!pattern.startsWith('entity.') || !pattern.includes('*')) {
2518
- return false;
2240
+ /**
2241
+ * Add middleware for specific operation (getOne, insertOne, etc.)
2242
+ */
2243
+ useForOperation(operation, middleware) {
2244
+ if (!this.operationSpecificMiddlewares.has(operation)) {
2245
+ this.operationSpecificMiddlewares.set(operation, []);
2519
2246
  }
2520
- const regexPattern = pattern.replace(/\./g, '\\.').replace(/\*/g, '.*');
2521
- const regex = new RegExp(`^${regexPattern}$`);
2522
- return regex.test(eventKey);
2523
- }
2524
- generateEventKeys(operation, entityName) {
2525
- const keys = [];
2526
- keys.push(`entity.${operation}`);
2527
- keys.push(`entity.${operation}.${entityName}`);
2528
- const entityParts = entityName.split('.');
2529
- if (entityParts.length > 1) {
2530
- const moduleName = entityParts[0];
2531
- keys.push(`entity.${operation}.${moduleName}`);
2247
+ this.operationSpecificMiddlewares.get(operation).push(middleware);
2248
+ }
2249
+ /**
2250
+ * Get all applicable middlewares for a given context
2251
+ */
2252
+ getMiddlewares(entityName, operation) {
2253
+ const middlewares = [];
2254
+ // Add global middlewares
2255
+ middlewares.push(...this.globalMiddlewares);
2256
+ // Add entity-specific middlewares
2257
+ const entityMiddlewares = this.entitySpecificMiddlewares.get(entityName);
2258
+ if (entityMiddlewares) {
2259
+ middlewares.push(...entityMiddlewares);
2260
+ }
2261
+ // Add operation-specific middlewares
2262
+ const operationMiddlewares = this.operationSpecificMiddlewares.get(operation);
2263
+ if (operationMiddlewares) {
2264
+ middlewares.push(...operationMiddlewares);
2265
+ }
2266
+ return middlewares;
2267
+ }
2268
+ /**
2269
+ * Get all global middlewares
2270
+ */
2271
+ getGlobalMiddlewares() {
2272
+ return [...this.globalMiddlewares];
2273
+ }
2274
+ /**
2275
+ * Remove middleware from global middlewares
2276
+ */
2277
+ removeGlobalMiddleware(middleware) {
2278
+ const index = this.globalMiddlewares.indexOf(middleware);
2279
+ if (index > -1) {
2280
+ this.globalMiddlewares.splice(index, 1);
2281
+ return true;
2532
2282
  }
2533
- return keys;
2283
+ return false;
2534
2284
  }
2535
- async dispatchInserted(entityName, data) {
2536
- await this.dispatchEntityEvent('inserted', entityName, data);
2285
+ /**
2286
+ * Clear all middlewares
2287
+ */
2288
+ clear() {
2289
+ this.globalMiddlewares.length = 0;
2290
+ this.entitySpecificMiddlewares.clear();
2291
+ this.operationSpecificMiddlewares.clear();
2537
2292
  }
2538
- async dispatchUpdated(entityName, data) {
2539
- await this.dispatchEntityEvent('updated', entityName, data);
2293
+ /**
2294
+ * Get registered entity names that have specific middlewares
2295
+ */
2296
+ getRegisteredEntityNames() {
2297
+ return Array.from(this.entitySpecificMiddlewares.keys());
2540
2298
  }
2541
- async dispatchDeleted(entityName, data) {
2542
- await this.dispatchEntityEvent('deleted', entityName, data);
2299
+ /**
2300
+ * Get registered operation names that have specific middlewares
2301
+ */
2302
+ getRegisteredOperations() {
2303
+ return Array.from(this.operationSpecificMiddlewares.keys());
2543
2304
  }
2544
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityEventDispatcherService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2545
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityEventDispatcherService, providedIn: 'root' }); }
2305
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2306
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageRegistry, providedIn: 'root' }); }
2546
2307
  }
2547
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityEventDispatcherService, decorators: [{
2308
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageRegistry, decorators: [{
2548
2309
  type: Injectable,
2549
- args: [{
2550
- providedIn: 'root',
2551
- }]
2310
+ args: [{ providedIn: 'root' }]
2552
2311
  }] });
2553
2312
 
2554
- class AXPLayoutAdapterBuilder {
2555
- constructor() {
2556
- this.adapter = {};
2557
- }
2558
- setEntity(entity, rootContext) {
2559
- this.entity = entity;
2560
- this.rootContext = rootContext;
2561
- return this;
2562
- }
2563
- setDependencies(dependencies) {
2564
- this.dependencies = dependencies;
2565
- return this;
2566
- }
2567
- setMainPage(mainPage) {
2568
- this.adapter.pages = [mainPage];
2569
- return this;
2570
- }
2571
- setRelatedPages(relatedPages) {
2572
- this.adapter.pages = [...(this.adapter.pages || []), ...relatedPages];
2573
- return this;
2574
- }
2575
- setPages(pages) {
2576
- this.adapter.pages = pages;
2577
- return this;
2313
+ /**
2314
+ * Executor that wraps entity storage operations with middleware pipeline
2315
+ */
2316
+ class AXPEntityStorageExecutor {
2317
+ constructor(storageService) {
2318
+ this.storageService = storageService;
2319
+ this.injector = inject(EnvironmentInjector);
2320
+ this.registry = inject(AXPEntityStorageRegistry);
2578
2321
  }
2579
- build() {
2580
- return {
2581
- name: `${this.entity?.module}.${this.entity?.name}`,
2582
- title: `${this.entity?.interfaces?.master?.single?.title}`,
2583
- label: this.entity?.formats.plural,
2584
- actions: [],
2585
- breadcrumbs: this.createBreadcrumbs(),
2586
- execute: this.createExecuteFunction(),
2587
- load: this.createLoadFunction(),
2588
- pages: this.adapter.pages || [],
2322
+ /**
2323
+ * Execute getOne operation with middleware pipeline
2324
+ */
2325
+ async getOne(entityName, id) {
2326
+ const context = {
2327
+ operation: 'getOne',
2328
+ entityName,
2329
+ dbName: this.storageService.dbName,
2330
+ input: { id },
2331
+ metadata: {
2332
+ startTime: Date.now(),
2333
+ requestId: generateRequestId(),
2334
+ },
2589
2335
  };
2336
+ const handler = async (ctx) => {
2337
+ return this.storageService.getOne(ctx.entityName, ctx.input.id);
2338
+ };
2339
+ return this.executeWithMiddleware(context, handler);
2590
2340
  }
2591
- createBreadcrumbs() {
2592
- const session = this.dependencies.session;
2593
- const moduleName = this.entity?.module;
2594
- const entityName = this.entity?.name;
2595
- return [
2596
- {
2597
- title: this.entity?.formats.plural ?? '',
2598
- command: {
2599
- name: 'navigate',
2600
- options: {
2601
- path: `/${session.application?.name}/m/${moduleName}/e/${entityName}/list`,
2602
- },
2603
- },
2604
- },
2605
- {
2606
- title: this.entity?.interfaces?.master?.single?.title ?? '',
2607
- command: {
2608
- name: 'navigate',
2609
- options: {
2610
- path: `/${session.application?.name}/m/${moduleName}/e/${entityName}/${this.rootContext.id}/new-view`,
2611
- },
2612
- },
2341
+ /**
2342
+ * Execute getAll operation with middleware pipeline
2343
+ */
2344
+ async getAll(entityName) {
2345
+ const context = {
2346
+ operation: 'getAll',
2347
+ entityName,
2348
+ dbName: this.storageService.dbName,
2349
+ input: {},
2350
+ metadata: {
2351
+ startTime: Date.now(),
2352
+ requestId: generateRequestId(),
2613
2353
  },
2614
- ];
2615
- }
2616
- createExecuteFunction() {
2617
- return (command, context) => {
2618
- console.log('layout execute', command, context);
2619
- return Promise.resolve({ success: true });
2620
2354
  };
2355
+ const handler = async (ctx) => {
2356
+ return this.storageService.getAll(ctx.entityName);
2357
+ };
2358
+ return this.executeWithMiddleware(context, handler);
2621
2359
  }
2622
- createLoadFunction() {
2623
- return async () => {
2624
- return {
2625
- success: true,
2626
- result: this.rootContext,
2627
- };
2360
+ /**
2361
+ * Execute insertOne operation with middleware pipeline
2362
+ */
2363
+ async insertOne(entityName, entity) {
2364
+ const context = {
2365
+ operation: 'insertOne',
2366
+ entityName,
2367
+ dbName: this.storageService.dbName,
2368
+ input: { entity },
2369
+ metadata: {
2370
+ startTime: Date.now(),
2371
+ requestId: generateRequestId(),
2372
+ },
2373
+ };
2374
+ const handler = async (ctx) => {
2375
+ return this.storageService.insertOne(ctx.entityName, ctx.input.entity);
2628
2376
  };
2629
- }
2630
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterBuilder, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2631
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterBuilder, providedIn: 'root' }); }
2632
- }
2633
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterBuilder, decorators: [{
2634
- type: Injectable,
2635
- args: [{
2636
- providedIn: 'root',
2637
- }]
2638
- }] });
2639
-
2640
- class AXPBaseRelatedEntityConverter {
2641
- async getEntityDefinition(relatedEntity, entityResolver) {
2642
- const [moduleName, entityName] = relatedEntity.entity.split('.');
2643
- const entityDef = await entityResolver.resolve(moduleName, entityName);
2644
- if (!entityDef) {
2645
- throw new Error(`Entity ${relatedEntity.entity} not found`);
2646
- }
2647
- return { entityDef, moduleName, entityName };
2648
- }
2649
- createExpressionEvaluator(context, expressionEvaluator) {
2650
- return async (actionData) => {
2651
- const scope = {
2652
- context: {
2653
- eval: (path) => get(context, path),
2654
- },
2655
- };
2656
- return await expressionEvaluator.evaluate(actionData, scope);
2657
- };
2658
- }
2659
- async createFilters(relatedEntity, evaluateExpressions) {
2660
- return (relatedEntity.conditions?.map(async (c) => {
2661
- const value = await evaluateExpressions(c.value);
2662
- return {
2663
- field: c.name,
2664
- operator: c.operator,
2665
- value: value,
2666
- };
2667
- }) ?? []);
2668
- }
2669
- createEntityHelpers(entityDef) {
2670
- const groups = entityDef?.groups ?? [];
2671
- const singleInterface = entityDef?.interfaces?.master?.single;
2672
- return {
2673
- getGroupById: (id) => groups.find((s) => s.id === id),
2674
- getPropertyByGroupId: (groupId) => entityDef?.properties.filter((p) => p.groupId === groupId) ?? [],
2675
- getPropertyLayout: (name) => singleInterface?.properties?.find((p) => p.name === name)?.layout,
2676
- singleInterface,
2677
- groups,
2678
- };
2679
- }
2680
- async createGridLayoutStructure(singleInterface, helpers, evaluateExpressions) {
2681
- return await this.createGridLayoutStructureInternal(singleInterface, helpers, evaluateExpressions);
2682
- }
2683
- //#region ---- Hidden Evaluation Helpers ----
2684
- async getVisiblePropertiesByGroupId(sectionId, helpers, evaluateExpressions) {
2685
- const properties = helpers.getPropertyByGroupId(sectionId) ?? [];
2686
- const evaluated = await Promise.all(properties.map(async (property) => {
2687
- let hidden = property?.schema?.hidden;
2688
- if (typeof hidden === 'string' && evaluateExpressions) {
2689
- try {
2690
- const result = await evaluateExpressions({ hidden });
2691
- hidden = result.hidden;
2692
- }
2693
- catch {
2694
- hidden = false;
2695
- }
2696
- }
2697
- return { property, hidden: !!hidden };
2698
- }));
2699
- return evaluated.filter((x) => !x.hidden).map((x) => x.property);
2700
- }
2701
- async createPropertyGrid(sectionId, helpers, evaluateExpressions) {
2702
- const visibleProperties = await this.getVisiblePropertiesByGroupId(sectionId, helpers, evaluateExpressions);
2703
- return {
2704
- type: 'grid-layout',
2705
- mode: 'edit',
2706
- options: {
2707
- grid: {
2708
- default: {
2709
- columns: 'repeat(12, 1fr)',
2710
- rows: 'repeat(1, 1fr)',
2711
- gap: '20px',
2712
- },
2713
- },
2714
- },
2715
- children: visibleProperties.map((p) => {
2716
- const layout = helpers.getPropertyLayout(p.name);
2717
- return {
2718
- type: 'grid-item-layout',
2719
- name: p.name,
2720
- options: {
2721
- colSpan: layout?.positions?.lg?.colSpan ?? 12,
2722
- colStart: layout?.positions?.lg?.colStart,
2723
- colEnd: layout?.positions?.lg?.colEnd,
2724
- },
2725
- children: [
2726
- {
2727
- type: 'form-field',
2728
- options: {
2729
- label: p.title,
2730
- showLabel: layout?.label?.visible ?? true,
2731
- },
2732
- children: [
2733
- {
2734
- type: p.schema.interface?.type ?? '',
2735
- path: p.name,
2736
- name: p.name,
2737
- defaultValue: p.schema.defaultValue,
2738
- children: p.schema.interface?.children,
2739
- options: p.schema.interface?.options,
2740
- triggers: p.schema.interface?.triggers,
2741
- valueTransforms: p.schema.interface?.valueTransforms,
2742
- },
2743
- ],
2744
- },
2745
- ],
2746
- };
2747
- }),
2748
- };
2749
- }
2750
- async createGridLayoutStructureInternal(singleInterface, helpers, evaluateExpressions) {
2751
- return {
2752
- type: 'grid-layout',
2753
- options: {
2754
- grid: {
2755
- default: {
2756
- columns: 'repeat(12, 1fr)',
2757
- rows: 'repeat(1, 1fr)',
2758
- gap: '20px',
2759
- },
2760
- },
2761
- },
2762
- children: await Promise.all(singleInterface?.sections.map(async (s) => ({
2763
- type: 'grid-item-layout',
2764
- name: s.id,
2765
- options: {
2766
- colSpan: s.layout?.positions?.lg?.colSpan ?? 12,
2767
- colStart: s.layout?.positions?.lg?.colStart,
2768
- colEnd: s.layout?.positions?.lg?.colEnd,
2769
- },
2770
- children: [
2771
- {
2772
- type: 'fieldset-layout',
2773
- options: {
2774
- title: helpers.getGroupById(s.id)?.title ?? '',
2775
- collapsible: true,
2776
- },
2777
- children: [await this.createPropertyGrid(s.id, helpers, evaluateExpressions)],
2778
- },
2779
- ],
2780
- }))),
2781
- };
2782
- }
2783
- }
2784
-
2785
- class AXPPageDetailsConverter extends AXPBaseRelatedEntityConverter {
2786
- async convert(relatedEntity, context) {
2787
- const { entityDef } = await this.getEntityDefinition(relatedEntity, context.entityResolver);
2788
- const baseHelpers = this.createEntityHelpers(entityDef);
2789
- // If referenced strategy with mapping and detail type, exclude mapped properties from UI
2790
- const p = relatedEntity?.persistence || {};
2791
- const strategy = p.strategy || 'embedded';
2792
- const mappedTargets = Object.keys(p.map || {}).map((k) => (k || '').split('.')[0]);
2793
- const helpers = {
2794
- ...baseHelpers,
2795
- getPropertyByGroupId: (groupId) => {
2796
- const props = baseHelpers.getPropertyByGroupId(groupId) ?? [];
2797
- if (strategy !== 'referenced' || mappedTargets.length === 0)
2798
- return props;
2799
- return props.filter((prop) => !mappedTargets.includes(prop?.name));
2800
- },
2801
- };
2802
- const evaluateExpressions = async (actionData) => {
2803
- const scope = {
2804
- context: {
2805
- eval: (path) => {
2806
- return get(context.context, path);
2807
- },
2808
- },
2809
- };
2810
- return await context.expressionEvaluator.evaluate(actionData, scope);
2811
- };
2812
- // Build related tabs for the related entity page (mirrors main-entity tab building)
2813
- const tabDetailEntities = entityDef?.relatedEntities?.filter((re) => !re.hidden && re.layout?.type === 'tab-detail');
2814
- const tabListEntities = entityDef?.relatedEntities?.filter((re) => !re.hidden && (!re.layout?.type || re.layout?.type === 'tab-list'));
2815
- const factory = new AXPRelatedEntityConverterFactory();
2816
- const tabDetailTabs = await this.buildTabDetails(factory, tabDetailEntities ?? [], context);
2817
- const tabListTabs = await this.buildTabLists(factory, tabListEntities ?? [], context);
2818
- return {
2819
- id: entityDef?.name ?? '',
2820
- title: `${context.rootTitle}`,
2821
- label: relatedEntity.title ?? entityDef?.formats.displayName ?? '',
2822
- icon: relatedEntity.icon || entityDef.icon,
2823
- settings: this.createPageSettings(),
2824
- load: this.createLoadFunction(entityDef, relatedEntity, evaluateExpressions),
2825
- execute: this.createExecuteFunction(entityDef),
2826
- // tabs: [...tabDetailTabs, ...tabListTabs],
2827
- content: [await this.createGridLayoutStructure(helpers.singleInterface, helpers, evaluateExpressions)],
2828
- };
2829
- }
2830
- //#region ---- Utility Methods ----
2831
- createPageSettings() {
2832
- return {
2833
- commands: {
2834
- reject: {
2835
- title: 't("discard")',
2836
- color: 'default',
2837
- visible: '{{context.isDirty()}}',
2838
- command: { name: 'discard' },
2839
- },
2840
- accept: {
2841
- title: 't("confirm")',
2842
- color: 'secondary',
2843
- visible: '{{context.isDirty()}}',
2844
- command: { name: 'update-entity' },
2845
- },
2846
- },
2847
- };
2848
- }
2849
- createLoadFunction(entityDef, relatedEntity, evaluateExpressions) {
2850
- return async (context) => {
2851
- const fn = entityDef?.queries.byKey?.execute;
2852
- const conditionValues = relatedEntity.conditions?.map((c) => c.value) ?? [];
2853
- const evaluatedConditionValues = await Promise.all(conditionValues.map((c) => evaluateExpressions(c)));
2854
- const id = evaluatedConditionValues[0];
2855
- const result = await fn(id);
2856
- return { success: true, result };
2857
- };
2858
- }
2859
- createExecuteFunction(entityDef) {
2860
- return async (e, context) => {
2861
- if (e.name === 'update-entity') {
2862
- const fn = entityDef?.commands?.update?.execute;
2863
- const result = await fn(context);
2864
- return { success: true, result };
2865
- }
2866
- else {
2867
- return {
2868
- success: false,
2869
- error: { code: 'invalid_command', message: 'Invalid command' },
2870
- };
2871
- }
2872
- };
2873
- }
2874
- //#endregion
2875
- //#region ---- Tab Builders ----
2876
- /**
2877
- * Builds tab-detail items for a related entity page using the shared converters.
2878
- */
2879
- async buildTabDetails(factory, tabDetailEntities, ctx) {
2880
- if (!ctx?.entityResolver || !tabDetailEntities?.length) {
2881
- return [];
2882
- }
2883
- const tabs = [];
2884
- for (const re of tabDetailEntities) {
2885
- const converter = factory.createTabDetailsConverter();
2886
- tabs.push(await converter.convert(re, {
2887
- entityResolver: ctx.entityResolver,
2888
- }));
2889
- }
2890
- return tabs;
2891
- }
2892
- /**
2893
- * Builds tab-list items for a related entity page using the shared converters with context-aware filters/actions.
2894
- */
2895
- async buildTabLists(factory, tabListEntities, ctx) {
2896
- if (!ctx?.entityResolver || !tabListEntities?.length) {
2897
- return [];
2898
- }
2899
- const tabs = [];
2900
- for (const re of tabListEntities) {
2901
- const converter = factory.createTabListConverter();
2902
- tabs.push(await converter.convert(re, {
2903
- entityResolver: ctx.entityResolver,
2904
- expressionEvaluator: ctx.expressionEvaluator,
2905
- context: ctx.context,
2906
- }));
2907
- }
2908
- return tabs;
2909
- }
2910
- }
2911
-
2912
- class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
2913
- async convert(relatedEntity, context) {
2914
- const { entityDef } = await this.getEntityDefinition(relatedEntity, context.entityResolver);
2915
- const evaluateExpressions = async (actionData) => {
2916
- const scope = {
2917
- context: {
2918
- eval: (path) => {
2919
- return get(context.context, path);
2920
- },
2921
- },
2922
- };
2923
- return await context.expressionEvaluator.evaluate(actionData, scope);
2924
- };
2925
- const evaluatedActions = await evaluateExpressions(relatedEntity?.actions);
2926
- const filters = relatedEntity.conditions?.map(async (c) => {
2927
- const value = await evaluateExpressions(c.value);
2928
- return {
2929
- field: c.name,
2930
- operator: c.operator,
2931
- value: value,
2932
- hidden: true,
2933
- };
2934
- }) ?? [];
2935
- return {
2936
- id: entityDef?.name ?? '',
2937
- title: `${context.rootTitle}`,
2938
- label: relatedEntity.title,
2939
- icon: relatedEntity.icon || entityDef.icon,
2940
- actions: this.mergeActions(entityDef, evaluatedActions)
2941
- ?.filter((a) => a.priority === 'primary')
2942
- ?.map((a) => {
2943
- return {
2944
- ...a,
2945
- zone: 'header',
2946
- visible: !a.hidden,
2947
- priority: 'primary',
2948
- name: a.name,
2949
- title: a.title,
2950
- scope: a.scope,
2951
- icon: a.icon,
2952
- color: a.color,
2953
- disabled: a.disabled,
2954
- command: {
2955
- name: a.name,
2956
- options: a.options,
2957
- metadata: a.metadata,
2958
- },
2959
- };
2960
- }),
2961
- execute: async (command, executeContext) => {
2962
- try {
2963
- const commandName = command.name.split('&')[0];
2964
- const mergedActions = this.mergeActions(entityDef, evaluatedActions);
2965
- const action = mergedActions.find((a) => {
2966
- return a.name === commandName || a.name.split('&')[0] === commandName;
2967
- });
2968
- if (!action) {
2969
- console.warn(`Action ${commandName} not found in entity definition`);
2970
- return {
2971
- success: false,
2972
- error: {
2973
- code: 'ACTION_NOT_FOUND',
2974
- message: `Action ${commandName} not found`,
2975
- details: command,
2976
- },
2977
- };
2978
- }
2979
- await context.workflowService.execute(commandName, {
2980
- entity: getEntityInfo(entityDef).source,
2981
- entityInfo: {
2982
- name: entityDef.name,
2983
- module: entityDef.module,
2984
- title: entityDef.title,
2985
- parentKey: entityDef.parentKey,
2986
- source: entityDef.source,
2987
- },
2988
- data: action.scope == AXPEntityCommandScope.Selected
2989
- ? executeContext
2990
- : action.options?.['process']?.data || null,
2991
- options: action.options,
2992
- metadata: action.metadata,
2993
- });
2994
- return { success: true };
2995
- }
2996
- catch (error) {
2997
- console.error('Error executing command:', error);
2998
- return {
2999
- success: false,
3000
- error: {
3001
- code: 'EXECUTION_ERROR',
3002
- message: error instanceof Error ? error.message : 'Unknown error occurred',
3003
- details: error,
3004
- },
3005
- };
3006
- }
3007
- },
3008
- content: [
3009
- {
3010
- type: AXPWidgetsCatalog.entityList,
3011
- name: 'page-list',
3012
- defaultValue: {
3013
- toolbar: {
3014
- filters: await Promise.all(filters),
3015
- },
3016
- },
3017
- options: {
3018
- entity: relatedEntity.entity,
3019
- showEntityActions: false,
3020
- actions: evaluatedActions,
3021
- },
3022
- },
3023
- ],
3024
- };
3025
- }
3026
- mergeActions(entityDef, relatedEntityActions) {
3027
- const originalList = entityDef?.interfaces?.master?.list?.actions ?? [];
3028
- const relatedEntityActionList = relatedEntityActions ?? [];
3029
- // Create a map to track which actions from relatedEntityActionList have been used
3030
- const usedOverrideActions = new Set();
3031
- // Start with original actions, applying overrides where they exist
3032
- const mergedActions = originalList.map((originalAction) => {
3033
- const originalCommandName = typeof originalAction.command === 'string' ? originalAction.command : originalAction.command.name;
3034
- const overrideAction = relatedEntityActionList.find((action) => {
3035
- const actionCommandName = typeof action.command === 'string' ? action.command : action.command.name;
3036
- return actionCommandName === originalCommandName && action.name === originalAction.name;
3037
- });
3038
- if (overrideAction) {
3039
- // Mark this override action as used
3040
- const overrideKey = `${typeof overrideAction.command === 'string' ? overrideAction.command : overrideAction.command.name}_${overrideAction.name}`;
3041
- usedOverrideActions.add(overrideKey);
3042
- return new AXPEntityCommandTriggerViewModel(entityDef, overrideAction);
3043
- }
3044
- return new AXPEntityCommandTriggerViewModel(entityDef, originalAction);
3045
- });
3046
- // Add any remaining actions from relatedEntityActionList that weren't used as overrides
3047
- const additionalActions = relatedEntityActionList
3048
- .filter((action) => {
3049
- const actionKey = `${typeof action.command === 'string' ? action.command : action.command.name}_${action.name}`;
3050
- return !usedOverrideActions.has(actionKey);
3051
- })
3052
- .map((action) => new AXPEntityCommandTriggerViewModel(entityDef, action));
3053
- return [...additionalActions, ...mergedActions].filter((a) => !a.hidden);
3054
- }
3055
- }
3056
-
3057
- class AXPTabDetailsConverter extends AXPBaseRelatedEntityConverter {
3058
- async convert(relatedEntity, context) {
3059
- const { entityDef } = await this.getEntityDefinition(relatedEntity, context.entityResolver);
3060
- const baseHelpers = this.createEntityHelpers(entityDef);
3061
- // If referenced strategy with mapping and detail type, exclude mapped properties from UI
3062
- const p = relatedEntity?.persistence || {};
3063
- const strategy = p.strategy || 'embedded';
3064
- const mappedTargets = Object.keys(p.map || {}).map((k) => (k || '').split('.')[0]);
3065
- const helpers = {
3066
- ...baseHelpers,
3067
- getPropertyByGroupId: (groupId) => {
3068
- const props = baseHelpers.getPropertyByGroupId(groupId) ?? [];
3069
- if (strategy !== 'referenced' || mappedTargets.length === 0)
3070
- return props;
3071
- return props.filter((prop) => !mappedTargets.includes(prop?.name));
3072
- },
3073
- };
3074
- return {
3075
- id: entityDef?.name ?? '',
3076
- title: relatedEntity.title ?? entityDef?.title ?? '',
3077
- icon: relatedEntity.icon || entityDef.icon,
3078
- content: [await this.createGridLayoutStructure(helpers.singleInterface, helpers)],
3079
- };
3080
- }
3081
- }
3082
-
3083
- class AXPTabListConverter extends AXPBaseRelatedEntityConverter {
3084
- async convert(relatedEntity, context) {
3085
- const { entityDef } = await this.getEntityDefinition(relatedEntity, context.entityResolver);
3086
- const evaluateExpressions = async (actionData) => {
3087
- const scope = {
3088
- context: {
3089
- eval: (path) => {
3090
- return get(context.context, path);
3091
- },
3092
- },
3093
- };
3094
- return await context.expressionEvaluator.evaluate(actionData, scope);
3095
- };
3096
- // console.log({ relatedEntity });
3097
- const filters = relatedEntity.conditions?.map(async (c) => {
3098
- const value = await evaluateExpressions(c.value);
3099
- return {
3100
- field: c.name,
3101
- operator: c.operator,
3102
- value: value,
3103
- hidden: true,
3104
- };
3105
- }) ?? [];
3106
- const actions = await evaluateExpressions(relatedEntity.actions);
3107
- return {
3108
- id: entityDef?.name ?? '',
3109
- title: relatedEntity.title ?? entityDef?.title ?? '',
3110
- icon: relatedEntity.icon || entityDef.icon,
3111
- content: [
3112
- {
3113
- type: AXPWidgetsCatalog.entityList,
3114
- name: `${relatedEntity.entity}-tab-list`,
3115
- defaultValue: {
3116
- toolbar: {
3117
- filters: await Promise.all(filters),
3118
- },
3119
- },
3120
- options: {
3121
- entity: relatedEntity.entity,
3122
- showEntityActions: true,
3123
- showToolbar: false,
3124
- actions: actions,
3125
- },
3126
- },
3127
- ],
3128
- };
3129
- }
3130
- }
3131
-
3132
- class AXPRelatedEntityConverterFactory {
3133
- createConverter(type) {
3134
- switch (type) {
3135
- case 'page-detail':
3136
- return new AXPPageDetailsConverter();
3137
- case 'page-list':
3138
- return new AXPPageListConverter();
3139
- case 'tab-detail':
3140
- return new AXPTabDetailsConverter();
3141
- case 'tab-list':
3142
- return new AXPTabListConverter();
3143
- default:
3144
- throw new Error(`Unsupported converter type: ${type}`);
3145
- }
3146
- }
3147
- createPageDetailsConverter() {
3148
- return this.createConverter('page-detail');
3149
- }
3150
- createPageListConverter() {
3151
- return this.createConverter('page-list');
3152
- }
3153
- createTabDetailsConverter() {
3154
- return this.createConverter('tab-detail');
3155
- }
3156
- createTabListConverter() {
3157
- return this.createConverter('tab-list');
3158
- }
3159
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPRelatedEntityConverterFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3160
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPRelatedEntityConverterFactory, providedIn: 'root' }); }
3161
- }
3162
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPRelatedEntityConverterFactory, decorators: [{
3163
- type: Injectable,
3164
- args: [{
3165
- providedIn: 'root',
3166
- }]
3167
- }] });
3168
-
3169
- class AXPMainEntityContentBuilder {
3170
- constructor(relatedEntityConverterFactory) {
3171
- this.relatedEntityConverterFactory = relatedEntityConverterFactory;
3172
- this.workflowService = inject(AXPWorkflowService);
3173
- this.commandService = inject(AXPCommandService);
3174
- }
3175
- async build(entity, rootContext, dependencies, rootTitle) {
3176
- const groups = entity?.groups ?? [];
3177
- const singleInterface = entity?.interfaces?.master?.single;
3178
- // Accumulate groups from main and merge-detail related entities for validation/title lookup
3179
- const allGroups = [...groups];
3180
- // Prepare merge-details structures (sections and properties per section)
3181
- const mergeDetailEntities = entity?.relatedEntities?.filter((re) => !re.hidden && re.layout?.type === 'merge-detail');
3182
- const mainPropsByGroup = (entity?.properties ?? []).reduce((acc, p) => {
3183
- if (!acc[p.groupId])
3184
- acc[p.groupId] = [];
3185
- acc[p.groupId].push(p);
3186
- return acc;
3187
- }, {});
3188
- // Will hold merged properties per group (section)
3189
- const mergedPropsByGroup = { ...mainPropsByGroup };
3190
- // Collect sections from main interface (validated later) and related ones for ordering
3191
- const mainSections = singleInterface?.sections ?? [];
3192
- // Track extra sections with entity-level ordering context
3193
- const beforeExtraSections = [];
3194
- const middleExtraSections = [];
3195
- const afterExtraSections = [];
3196
- const beforeExtraIds = new Set();
3197
- const middleExtraIds = new Set();
3198
- const afterExtraIds = new Set();
3199
- // Effective order overrides for main sections when merged with BEFORE related entities
3200
- let beforeOverrideSectionOrders = {};
3201
- // Collect tab-list tabs from merge-detail related entities to merge with main tabs
3202
- const nestedTabListTabs = [];
3203
- // Helper to append related-only sections into before/after buckets
3204
- const queueRelatedSection = (section, position, entityOrder) => {
3205
- if (!section)
3206
- return;
3207
- if (position === 'before') {
3208
- if (!beforeExtraIds.has(section.id)) {
3209
- beforeExtraIds.add(section.id);
3210
- beforeExtraSections.push({ section, entityOrder });
3211
- }
3212
- }
3213
- else if (position === 'middle') {
3214
- if (!middleExtraIds.has(section.id)) {
3215
- middleExtraIds.add(section.id);
3216
- middleExtraSections.push({ section });
3217
- }
3218
- }
3219
- else {
3220
- if (!afterExtraIds.has(section.id)) {
3221
- afterExtraIds.add(section.id);
3222
- afterExtraSections.push({ section, entityOrder });
3223
- }
3224
- }
3225
- };
3226
- // Resolve and merge merge-detail entities
3227
- // Sort related entities by position group then by layout.order
3228
- if (mergeDetailEntities?.length && dependencies?.entityResolver) {
3229
- const beforeEntities = (mergeDetailEntities || [])
3230
- .filter((re) => (re.layout?.position ?? 'middle') === 'before')
3231
- .sort((a, b) => (a.layout?.order ?? Number.MAX_SAFE_INTEGER) - (b.layout?.order ?? Number.MAX_SAFE_INTEGER));
3232
- const middleEntities = (mergeDetailEntities || []).filter((re) => (re.layout?.position ?? 'middle') === 'middle');
3233
- const afterEntities = (mergeDetailEntities || [])
3234
- .filter((re) => (re.layout?.position ?? 'middle') === 'after')
3235
- .sort((a, b) => (a.layout?.order ?? Number.MAX_SAFE_INTEGER) - (b.layout?.order ?? Number.MAX_SAFE_INTEGER));
3236
- const processRelated = async (relatedEntity) => {
3237
- try {
3238
- const [moduleName, entityName] = relatedEntity.entity.split('.');
3239
- const entityDef = await dependencies.entityResolver.resolve(moduleName, entityName);
3240
- if (!entityDef) {
3241
- return;
3242
- }
3243
- const relSingle = entityDef?.interfaces?.master?.single;
3244
- const relGroups = entityDef?.groups ?? [];
3245
- // Merge related groups into allGroups (avoid duplicates by id)
3246
- for (const rg of relGroups) {
3247
- if (!allGroups.some((g) => g.id === rg.id)) {
3248
- allGroups.push(rg);
3249
- }
3250
- }
3251
- // Collect nested tab-list related entities from this merge-detail entity and convert to tabs
3252
- try {
3253
- const nestedTabListEntities = entityDef?.relatedEntities?.filter((re) => !re.hidden && (!re.layout?.type || re.layout?.type === 'tab-list'));
3254
- if (nestedTabListEntities?.length) {
3255
- const converter = this.relatedEntityConverterFactory.createTabListConverter();
3256
- const nestedDataPath = relatedEntity?.persistence?.dataPath || entityName;
3257
- const nestedContext = get(rootContext, nestedDataPath) ?? rootContext;
3258
- for (const nre of nestedTabListEntities) {
3259
- try {
3260
- const tab = await converter.convert(nre, {
3261
- entityResolver: dependencies.entityResolver,
3262
- expressionEvaluator: dependencies.expressionEvaluator,
3263
- // Evaluate conditions relative to the merge-detail entity's dataPath
3264
- context: nestedContext,
3265
- });
3266
- nestedTabListTabs.push(tab);
3267
- }
3268
- catch { }
3269
- }
3270
- }
3271
- }
3272
- catch { }
3273
- // Build related props map per group with metadata: __dataPath and __layout
3274
- // If referenced strategy with mapping, exclude mapped target property names from UI props
3275
- const p = relatedEntity?.persistence || {};
3276
- const strategy = p.strategy || 'embedded';
3277
- const mappedTargets = Object.keys(p.map || {}).map((k) => (k || '').split('.')[0]);
3278
- const relPropsByGroup = (entityDef?.properties ?? []).reduce((acc, p) => {
3279
- if (strategy === 'referenced' &&
3280
- (relatedEntity?.layout?.type === 'merge-detail' ||
3281
- relatedEntity?.layout?.type === 'page-detail' ||
3282
- relatedEntity?.layout?.type === 'tab-detail') &&
3283
- mappedTargets.includes(p.name)) {
3284
- return acc; // skip mapped properties
3285
- }
3286
- if (!acc[p.groupId])
3287
- acc[p.groupId] = [];
3288
- // Clone shallow to not mutate original definitions
3289
- const propClone = { ...p };
3290
- propClone.__dataPath = relatedEntity?.persistence?.dataPath || entityName;
3291
- propClone.__layout = relSingle?.properties?.find((x) => x.name === p.name)?.layout;
3292
- acc[p.groupId].push(propClone);
3293
- return acc;
3294
- }, {});
3295
- // Merge properties by section id
3296
- const position = relatedEntity.layout?.position ?? 'middle';
3297
- const entityOrder = relatedEntity.layout?.order ?? Number.MAX_SAFE_INTEGER;
3298
- const relSections = (relSingle?.sections ?? []).filter((s) => relGroups.some((g) => g.id === s.id));
3299
- for (const rs of relSections) {
3300
- const sectionId = rs.id;
3301
- const mainHasSection = !!mainSections?.some((s) => s.id === sectionId);
3302
- const relProps = relPropsByGroup[sectionId] ?? [];
3303
- if (mainHasSection) {
3304
- const current = mergedPropsByGroup[sectionId] ?? [];
3305
- mergedPropsByGroup[sectionId] =
3306
- position === 'before' ? [...relProps, ...current] : [...current, ...relProps];
3307
- // Capture override order for main section when position is 'before'
3308
- if (position === 'before') {
3309
- const order = rs?.order ?? 0;
3310
- const prev = beforeOverrideSectionOrders[sectionId] ?? Number.MAX_SAFE_INTEGER;
3311
- beforeOverrideSectionOrders[sectionId] = Math.min(prev, order);
3312
- }
3313
- }
3314
- else {
3315
- // Section isn't in main; queue section for rendering and set its props
3316
- if (!mergedPropsByGroup[sectionId]) {
3317
- mergedPropsByGroup[sectionId] = [];
3318
- }
3319
- mergedPropsByGroup[sectionId] =
3320
- position === 'before'
3321
- ? [...(relProps ?? []), ...(mergedPropsByGroup[sectionId] ?? [])]
3322
- : [...(mergedPropsByGroup[sectionId] ?? []), ...(relProps ?? [])];
3323
- queueRelatedSection(rs, position, entityOrder);
3324
- }
3325
- }
3326
- }
3327
- catch {
3328
- // Silently ignore failures to resolve or merge
3329
- }
3330
- };
3331
- // Process BEFORE entities first (sorted), then AFTER entities
3332
- for (const re of beforeEntities) {
3333
- await processRelated(re);
3334
- }
3335
- for (const re of middleEntities) {
3336
- await processRelated(re);
3337
- }
3338
- for (const re of afterEntities) {
3339
- await processRelated(re);
3340
- }
3341
- }
3342
- const getGroupById = (id) => {
3343
- return groups.find((s) => s.id === id);
3344
- };
3345
- const filterValidSections = (sections) => {
3346
- return (sections?.filter((section) => {
3347
- return allGroups.some((group) => group.id === section.id);
3348
- }) ?? []);
3349
- };
3350
- // Utility: sort related-only sections by entity order then section order
3351
- const sortRelatedSections = (sections) => [...(sections ?? [])]
3352
- .filter((e) => !!e?.section)
3353
- .sort((a, b) => {
3354
- const ae = a.entityOrder ?? Number.MAX_SAFE_INTEGER;
3355
- const be = b.entityOrder ?? Number.MAX_SAFE_INTEGER;
3356
- if (ae !== be)
3357
- return ae - be;
3358
- const ao = a.section?.order ?? 0;
3359
- const bo = b.section?.order ?? 0;
3360
- return ao - bo;
3361
- })
3362
- .map((e) => e.section);
3363
- // Determine effective order for main sections: if any BEFORE related merged that section, use its order; otherwise keep main order
3364
- const computeEffectiveMainOrder = (s) => {
3365
- const defaultOrder = s?.order ?? 0;
3366
- const beforeOverride = beforeOverrideSectionOrders?.[s?.id ?? ''];
3367
- return beforeOverride != null ? beforeOverride : defaultOrder;
3368
- };
3369
- // Build combined section list:
3370
- // 1) related-before (entity-sorted)
3371
- // 2) middle block: main sections + related-middle-only sections sorted by their section.order (with effective order for main)
3372
- // 3) related-after (entity-sorted)
3373
- const beforeSections = sortRelatedSections(beforeExtraSections);
3374
- const mainSectionsList = [...filterValidSections(mainSections)];
3375
- const middleOnlySections = middleExtraSections.map((e) => e.section);
3376
- const middleBlock = [...mainSectionsList, ...middleOnlySections].sort((a, b) => {
3377
- const ao = computeEffectiveMainOrder(a);
3378
- const bo = computeEffectiveMainOrder(b);
3379
- return ao - bo;
3380
- });
3381
- const afterSections = sortRelatedSections(afterExtraSections);
3382
- const combinedSections = [...beforeSections, ...middleBlock, ...afterSections];
3383
- // Debug: Log final sorted sections for verification
3384
- try {
3385
- const beforeEntityOrderMap = new Map(beforeExtraSections.map((e) => [e.section?.id, e.entityOrder ?? Number.MAX_SAFE_INTEGER]));
3386
- const afterEntityOrderMap = new Map(afterExtraSections.map((e) => [e.section?.id, e.entityOrder ?? Number.MAX_SAFE_INTEGER]));
3387
- const debugSections = [
3388
- ...beforeSections.map((s) => ({
3389
- bucket: 'before',
3390
- id: s?.id,
3391
- sectionOrder: s?.order ?? 0,
3392
- entityOrder: beforeEntityOrderMap.get(s?.id) ?? Number.MAX_SAFE_INTEGER,
3393
- })),
3394
- ...middleBlock.map((s) => ({
3395
- bucket: 'middle',
3396
- id: s?.id,
3397
- sectionOrder: s?.order ?? 0,
3398
- effectiveOrder: computeEffectiveMainOrder(s),
3399
- })),
3400
- ...afterSections.map((s) => ({
3401
- bucket: 'after',
3402
- id: s?.id,
3403
- sectionOrder: s?.order ?? 0,
3404
- entityOrder: afterEntityOrderMap.get(s?.id) ?? Number.MAX_SAFE_INTEGER,
3405
- })),
3406
- ];
3407
- // eslint-disable-next-line no-console
3408
- console.debug('[AXP] merge-details sorted sections', debugSections);
3409
- }
3410
- catch { }
3411
- // Create expression evaluator for actions
3412
- const evaluateExpressions = dependencies?.expressionEvaluator
3413
- ? this.createExpressionEvaluator(rootContext, dependencies.expressionEvaluator)
3414
- : null;
3415
- const getVisiblePropertyByGroupId = async (groupId) => {
3416
- return (mergedPropsByGroup[groupId] ?? []);
3417
- };
3418
- const getPropertyLayout = (name, prop) => {
3419
- // Prefer per-property layout (for merged related props), fallback to main entity layout
3420
- return prop?.__layout ?? singleInterface?.properties?.find((p) => p.name === name)?.layout;
3421
- };
3422
- // Get related entities for tabs
3423
- const tabDetailEntities = entity?.relatedEntities?.filter((re) => !re.hidden && re.layout?.type === 'tab-detail');
3424
- const tabListEntities = entity?.relatedEntities?.filter((re) => !re.hidden && (!re.layout?.type || re.layout?.type === 'tab-list'));
3425
- // Build related tabs if dependencies are provided
3426
- const tabDetailTabs = await this.buildTabDetails(tabDetailEntities ?? [], dependencies);
3427
- const tabListTabs = await this.buildTabLists(tabListEntities ?? [], rootContext, dependencies);
3428
- // Build actions from single interface
3429
- const actions = this.buildActions(entity, singleInterface);
3430
- console.log({ rootContext, dependencies });
3431
- return {
3432
- id: entity?.name ?? '',
3433
- // title: singleInterface?.title ?? entity?.formats.individual ?? '',
3434
- title: rootTitle ?? entity?.formats.individual,
3435
- label: entity?.formats.displayName ?? singleInterface?.title ?? '',
3436
- icon: entity?.icon,
3437
- actions: await this.buildEvaluatedActions(actions, evaluateExpressions),
3438
- isPrimary: true,
3439
- settings: {
3440
- commands: {
3441
- reject: {
3442
- title: 't("discard")',
3443
- color: 'default',
3444
- visible: '{{context.isDirty()}}',
3445
- command: {
3446
- name: 'discard',
3447
- },
3448
- },
3449
- accept: {
3450
- title: 't("confirm")',
3451
- color: 'secondary',
3452
- visible: '{{context.isDirty()}}',
3453
- command: {
3454
- name: 'update-entity',
3455
- },
3456
- },
3457
- },
3458
- },
3459
- load: async () => {
3460
- return {
3461
- success: true,
3462
- result: rootContext,
3463
- };
3464
- },
3465
- execute: async (e, context) => {
3466
- if (e.name == 'update-entity') {
3467
- const fn = entity?.commands?.update?.execute;
3468
- const result = await fn(context);
3469
- return {
3470
- success: true,
3471
- result: result,
3472
- };
3473
- }
3474
- else {
3475
- // Find action in single interface actions
3476
- const action = actions.find((a) => a.name === e.name);
3477
- if (action && dependencies?.workflowService) {
3478
- // Evaluate action options with current context
3479
- let evaluatedOptions = action.options;
3480
- if (evaluateExpressions && action.options) {
3481
- try {
3482
- evaluatedOptions = await evaluateExpressions(action.options);
3483
- }
3484
- catch {
3485
- // Keep original options if evaluation fails
3486
- }
3487
- }
3488
- const commandName = e.name.split('&')[0];
3489
- if (this.workflowService.exists(commandName)) {
3490
- await this.workflowService.execute(commandName, {
3491
- entity: getEntityInfo(entity).source,
3492
- data: context,
3493
- entityInfo: {
3494
- name: entity.name,
3495
- module: entity.module,
3496
- title: entity.title,
3497
- parentKey: entity.parentKey,
3498
- source: entity.source,
3499
- },
3500
- options: evaluatedOptions,
3501
- metadata: action.metadata,
3502
- });
3503
- return {
3504
- success: true,
3505
- };
3506
- }
3507
- if (this.commandService.exists(commandName)) {
3508
- // check options for evaluation
3509
- await this.commandService.execute(commandName, e.options);
3510
- }
3511
- }
3512
- return {
3513
- success: false,
3514
- error: {
3515
- code: 'invalid_command',
3516
- message: 'Invalid command',
3517
- },
3518
- };
3519
- }
3520
- },
3521
- tabs: [...tabDetailTabs, ...tabListTabs, ...nestedTabListTabs],
3522
- content: [
3523
- {
3524
- type: 'grid-layout',
3525
- mode: 'edit',
3526
- options: {
3527
- grid: {
3528
- default: {
3529
- columns: 12,
3530
- rows: 1,
3531
- gap: '20px',
3532
- },
3533
- },
3534
- },
3535
- children: await Promise.all(combinedSections.map(async (s) => ({
3536
- type: 'grid-item-layout',
3537
- name: s.id,
3538
- options: {
3539
- colSpan: s.layout?.positions?.lg?.colSpan ?? 12,
3540
- colStart: s.layout?.positions?.lg?.colStart ?? 1,
3541
- colEnd: s.layout?.positions?.lg?.colEnd ?? 13,
3542
- },
3543
- children: [
3544
- {
3545
- type: 'fieldset-layout',
3546
- options: {
3547
- title: allGroups.find((g) => g.id === s.id)?.title ?? '',
3548
- collapsible: true,
3549
- isOpen: !s.collapsed,
3550
- look: 'card'
3551
- },
3552
- children: [
3553
- {
3554
- type: 'grid-layout',
3555
- options: {
3556
- grid: {
3557
- default: {
3558
- columns: 12,
3559
- rows: 1,
3560
- gap: '20px',
3561
- },
3562
- },
3563
- },
3564
- children: (await getVisiblePropertyByGroupId(s.id)).map((p) => {
3565
- const layout = getPropertyLayout(p.name, p);
3566
- const prefixed = p.__dataPath ? `${p.__dataPath}.${p.name}` : p.name;
3567
- return {
3568
- type: 'grid-item-layout',
3569
- name: prefixed,
3570
- options: {
3571
- colSpan: layout?.positions?.lg?.colSpan,
3572
- colStart: layout?.positions?.lg?.colStart,
3573
- colEnd: layout?.positions?.lg?.colEnd,
3574
- hidden: p.schema.hidden,
3575
- },
3576
- children: [
3577
- {
3578
- type: 'form-field',
3579
- options: {
3580
- label: p.title,
3581
- showLabel: layout?.label?.visible ?? true,
3582
- },
3583
- children: [
3584
- {
3585
- type: p.schema.interface?.type ?? '',
3586
- path: prefixed,
3587
- name: prefixed,
3588
- defaultValue: p.schema.defaultValue,
3589
- children: p.schema.interface?.children,
3590
- triggers: p.schema.interface?.triggers,
3591
- valueTransforms: p.schema.interface?.valueTransforms,
3592
- options: merge(p.schema.interface?.options, {
3593
- validations: p.validations?.map((c) => ({
3594
- rule: c.rule,
3595
- message: c.message,
3596
- options: c.options,
3597
- })),
3598
- // Attach dataPath for merged properties to be available in widgets/options if needed
3599
- dataPath: p.__dataPath,
3600
- }),
3601
- },
3602
- ],
3603
- },
3604
- ],
3605
- };
3606
- }),
3607
- },
3608
- ],
3609
- },
3610
- ],
3611
- }))),
3612
- },
3613
- ],
3614
- };
3615
- }
3616
- buildActions(entity, singleInterface) {
3617
- const actions = singleInterface?.actions ?? [];
3618
- return actions.map((action) => new AXPEntityCommandTriggerViewModel(entity, action));
3619
- }
3620
- createExpressionEvaluator(context, expressionEvaluator) {
3621
- return async (actionData) => {
3622
- const scope = {
3623
- context: {
3624
- eval: (path) => {
3625
- const value = get(context, path);
3626
- return value;
3627
- },
3628
- },
3629
- };
3630
- return await expressionEvaluator.evaluate(actionData, scope);
3631
- };
3632
- }
3633
- async buildEvaluatedActions(actions, evaluateExpressions) {
3634
- const evaluatedActions = [];
3635
- for (const action of actions) {
3636
- // Evaluate disabled condition
3637
- let disabled = action.disabled;
3638
- if (disabled && typeof disabled === 'string' && evaluateExpressions) {
3639
- try {
3640
- const result = await evaluateExpressions({ disabled: disabled });
3641
- disabled = result.disabled;
3642
- }
3643
- catch {
3644
- disabled = false;
3645
- }
3646
- }
3647
- // Evaluate hidden condition
3648
- let hidden = action.hidden;
3649
- if (hidden && typeof hidden === 'string' && evaluateExpressions) {
3650
- try {
3651
- const result = await evaluateExpressions({ hidden: hidden });
3652
- hidden = result.hidden;
3653
- }
3654
- catch {
3655
- hidden = false;
3656
- }
3657
- }
3658
- // Skip if hidden
3659
- if (hidden)
3660
- continue;
3661
- // Evaluate options
3662
- let options = action.options;
3663
- if (options && evaluateExpressions) {
3664
- try {
3665
- options = await evaluateExpressions(options);
3666
- }
3667
- catch {
3668
- // Keep original options if evaluation fails
3669
- }
3670
- }
3671
- evaluatedActions.push({
3672
- name: action.name,
3673
- title: action.title,
3674
- icon: action.icon,
3675
- color: action.color,
3676
- disabled: disabled || false,
3677
- zone: 'header',
3678
- priority: action.priority,
3679
- command: {
3680
- name: action.name,
3681
- options: options,
3682
- metadata: action.metadata,
3683
- },
3684
- });
3685
- }
3686
- return evaluatedActions;
3687
- }
3688
- async buildTabDetails(tabDetailEntities, dependencies) {
3689
- if (!dependencies?.entityResolver || !tabDetailEntities?.length) {
3690
- return [];
3691
- }
3692
- const tabs = [];
3693
- for (const relatedEntity of tabDetailEntities) {
3694
- const converter = this.relatedEntityConverterFactory.createTabDetailsConverter();
3695
- tabs.push(await converter.convert(relatedEntity, {
3696
- entityResolver: dependencies.entityResolver,
3697
- }));
3698
- }
3699
- return tabs;
3700
- }
3701
- async buildTabLists(tabListEntities, rootContext, dependencies) {
3702
- if (!dependencies?.entityResolver || !tabListEntities?.length) {
3703
- return [];
3704
- }
3705
- const tabs = [];
3706
- for (const relatedEntity of tabListEntities) {
3707
- const converter = this.relatedEntityConverterFactory.createTabListConverter();
3708
- tabs.push(await converter.convert(relatedEntity, {
3709
- entityResolver: dependencies.entityResolver,
3710
- expressionEvaluator: dependencies.expressionEvaluator,
3711
- context: rootContext,
3712
- }));
3713
- }
3714
- return tabs;
3715
- }
3716
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMainEntityContentBuilder, deps: [{ token: AXPRelatedEntityConverterFactory }], target: i0.ɵɵFactoryTarget.Injectable }); }
3717
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMainEntityContentBuilder, providedIn: 'root' }); }
3718
- }
3719
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMainEntityContentBuilder, decorators: [{
3720
- type: Injectable,
3721
- args: [{
3722
- providedIn: 'root',
3723
- }]
3724
- }], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }] });
3725
-
3726
- class AXPLayoutAdapterFactory {
3727
- constructor(relatedEntityConverterFactory, mainEntityContentBuilder, layoutAdapterBuilder) {
3728
- this.relatedEntityConverterFactory = relatedEntityConverterFactory;
3729
- this.mainEntityContentBuilder = mainEntityContentBuilder;
3730
- this.layoutAdapterBuilder = layoutAdapterBuilder;
3731
- }
3732
- async createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies) {
3733
- const entity = await entityResolver.resolve(moduleName, entityName);
3734
- if (!entity) {
3735
- throw new Error(`Entity ${moduleName}.${entityName} not found`);
3736
- }
3737
- const rootContext = await this.loadRootContext(entity, id);
3738
- // Build main and related pages
3739
- const mainPage = await this.buildMainPage(entity, rootContext, dependencies);
3740
- const relatedPages = await this.buildRelatedPages(entity, rootContext, dependencies);
3741
- // Compose ordered pages around the primary page
3742
- const orderedPages = this.composePagesWithPositions(mainPage, relatedPages, entity);
3743
- return this.layoutAdapterBuilder
3744
- .setEntity(entity, rootContext)
3745
- .setDependencies(dependencies)
3746
- .setPages(orderedPages)
3747
- .build();
3748
- }
3749
- async loadRootContext(entity, id) {
3750
- const fn = entity?.queries.byKey?.execute;
3751
- return await fn(id);
3752
- }
3753
- async buildMainPage(entity, rootContext, dependencies) {
3754
- return this.mainEntityContentBuilder.build(entity, rootContext, dependencies, await this.getRootTitle(entity, rootContext, dependencies));
3755
- }
3756
- async buildRelatedPages(entity, rootContext, dependencies) {
3757
- const pages = [];
3758
- const rootTitle = await this.getRootTitle(entity, rootContext, dependencies);
3759
- // Page Details
3760
- const pageDetailEntities = entity?.relatedEntities?.filter((re) => !re.hidden && re.layout?.type === 'page-detail');
3761
- for (const relatedEntity of pageDetailEntities || []) {
3762
- const converter = this.relatedEntityConverterFactory.createPageDetailsConverter();
3763
- pages.push(await converter.convert(relatedEntity, {
3764
- ...dependencies,
3765
- context: rootContext,
3766
- rootTitle: rootTitle,
3767
- }));
3768
- }
3769
- // Page Lists
3770
- const pageListEntities = entity?.relatedEntities?.filter((re) => !re.hidden && re.layout?.type === 'page-list');
3771
- for (const relatedEntity of pageListEntities || []) {
3772
- const converter = this.relatedEntityConverterFactory.createPageListConverter();
3773
- pages.push(await converter.convert(relatedEntity, {
3774
- ...dependencies,
3775
- context: rootContext,
3776
- rootTitle: rootTitle,
3777
- }));
3778
- }
3779
- // Include nested page-related entities from merge-detail related entities
3780
- const mergeDetailEntities = entity?.relatedEntities?.filter((re) => !re.hidden && re.layout?.type === 'merge-detail');
3781
- for (const mergeRelated of mergeDetailEntities || []) {
3782
- try {
3783
- const [moduleName, childEntityName] = (mergeRelated.entity || '').split('.');
3784
- const childEntity = await dependencies.entityResolver.resolve(moduleName, childEntityName);
3785
- if (!childEntity) {
3786
- continue;
3787
- }
3788
- const nestedDataPath = mergeRelated?.persistence?.dataPath || childEntityName;
3789
- const nestedContext = get(rootContext, nestedDataPath) ?? rootContext;
3790
- const nestedPageDetailEntities = childEntity?.relatedEntities?.filter((re) => !re.hidden && re.layout?.type === 'page-detail');
3791
- for (const nestedRelated of nestedPageDetailEntities || []) {
3792
- const converter = this.relatedEntityConverterFactory.createPageDetailsConverter();
3793
- pages.push(await converter.convert(nestedRelated, {
3794
- ...dependencies,
3795
- context: nestedContext,
3796
- rootTitle: rootTitle,
3797
- }));
3798
- }
3799
- const nestedPageListEntities = childEntity?.relatedEntities?.filter((re) => !re.hidden && re.layout?.type === 'page-list');
3800
- for (const nestedRelated of nestedPageListEntities || []) {
3801
- const converter = this.relatedEntityConverterFactory.createPageListConverter();
3802
- pages.push(await converter.convert(nestedRelated, {
3803
- ...dependencies,
3804
- context: nestedContext,
3805
- rootTitle: rootTitle,
3806
- }));
3807
- }
3808
- }
3809
- catch {
3810
- // Silently ignore failures for nested page inclusions
3811
- }
3812
- }
3813
- return pages;
3814
- }
3815
- composePagesWithPositions(mainPage, relatedPages, entity) {
3816
- // Only consider related entities with layout types page-detail or page-list
3817
- const pageEntities = (entity?.relatedEntities || []).filter((re) => !re.hidden && (re.layout?.type === 'page-detail' || re.layout?.type === 'page-list'));
3818
- // Build a map from entity name to its layout config (order/position)
3819
- const layoutConfigByEntity = {};
3820
- for (const re of pageEntities) {
3821
- const [, entityName] = (re.entity || '').split('.');
3822
- const key = entityName || re.entity;
3823
- layoutConfigByEntity[key] = { order: re.layout?.order, position: re.layout?.position };
3824
- }
3825
- // Split related pages into before/after buckets based on their relatedEntity layout
3826
- const before = [];
3827
- const after = [];
3828
- for (const page of relatedPages) {
3829
- const conf = layoutConfigByEntity[page.id];
3830
- const position = conf?.position ?? 'after';
3831
- if (position === 'before') {
3832
- before.push(page);
3833
- }
3834
- else {
3835
- after.push(page);
3836
- }
3837
- }
3838
- // Sort by order within each bucket (undefined orders go last)
3839
- const sortByOrder = (a, b) => {
3840
- const ao = layoutConfigByEntity[a.id]?.order ?? Number.POSITIVE_INFINITY;
3841
- const bo = layoutConfigByEntity[b.id]?.order ?? Number.POSITIVE_INFINITY;
3842
- return ao - bo;
3843
- };
3844
- before.sort(sortByOrder);
3845
- after.sort(sortByOrder);
3846
- // Ensure the main page is primary
3847
- mainPage.isPrimary = true;
3848
- // Compose final pages: before -> main -> after
3849
- return [...before, mainPage, ...after];
3850
- }
3851
- async getRootTitle(entity, rootContext, dependencies) {
3852
- // Logic for getting root title
3853
- const title = await dependencies.expressionEvaluator.evaluate(entity.interfaces?.master?.single?.title, rootContext);
3854
- return title;
3855
- }
3856
- 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 }); }
3857
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterFactory, providedIn: 'root' }); }
3858
- }
3859
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterFactory, decorators: [{
3860
- type: Injectable,
3861
- args: [{
3862
- providedIn: 'root',
3863
- }]
3864
- }], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }, { type: AXPMainEntityContentBuilder }, { type: AXPLayoutAdapterBuilder }] });
3865
-
3866
- const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver = inject(AXPEntityDefinitionRegistryService), expressionEvaluator = inject(AXPExpressionEvaluatorService), session = inject(AXPSessionService), formatService = inject(AXFormatService), workflowService = inject(AXPWorkflowService), layoutAdapterFactory = inject(AXPLayoutAdapterFactory)) => {
3867
- const moduleName = route.parent?.paramMap.get('module');
3868
- const entityName = route.paramMap.get('entity');
3869
- const id = route.paramMap.get('id');
3870
- const dependencies = {
3871
- entityResolver,
3872
- expressionEvaluator,
3873
- session,
3874
- formatService,
3875
- workflowService,
3876
- };
3877
- return await layoutAdapterFactory.createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies);
3878
- };
3879
-
3880
- class AXPEntityCommandSearchDefinitionProvider {
3881
- async provide(context) {
3882
- context.addDefinition('command', 'Commands', 'command', 'fa-solid fa-command', 1, {
3883
- format: {
3884
- id: '{{id}}',
3885
- },
3886
- actions: [
3887
- {
3888
- name: 'open-entity',
3889
- type: 'view',
3890
- priority: 'primary',
3891
- },
3892
- ],
3893
- });
3894
- }
3895
- }
3896
-
3897
- class AXPEntitySearchDefinitionProvider {
3898
- constructor() {
3899
- this.entityRegister = inject(AXPEntityDefinitionRegistryService);
3900
- }
3901
- async provide(context) {
3902
- console.log("AXPEntitySearchDefinitionProvider", this.entityRegister.getAll());
3903
- this.entityRegister.getAll().forEach((entity) => {
3904
- context.addDefinition(`Module.${entity.module}.${entity.name}`, entity.formats.searchResult?.description ?? entity.module, `Module.${entity.module}`, 'fa-solid fa-objects-column', 4, {
3905
- actions: [
3906
- {
3907
- name: 'open-entity',
3908
- type: 'view',
3909
- priority: 'primary',
3910
- },
3911
- ],
3912
- format: {
3913
- title: entity.formats.searchResult?.title,
3914
- description: (entity.formats.searchResult?.description ?? entity.module) + ' / ' + entity.title,
3915
- id: '{{data.id}}',
3916
- },
3917
- });
3918
- });
3919
- }
3920
- }
3921
-
3922
- //#region ---- Column Mapping Helpers ----
3923
- /**
3924
- * Maps an entity property to a list widget column configuration.
3925
- * Preserves readonly behavior and leverages the property's interface options when available.
3926
- */
3927
- function mapPropertyToWidgetColumn(property) {
3928
- return {
3929
- name: property.name,
3930
- title: property.title,
3931
- visible: true,
3932
- widget: property.schema?.interface
3933
- ? {
3934
- type: property.schema.interface.type || 'text-editor',
3935
- path: property.name,
3936
- options: {
3937
- readonly: true,
3938
- ...property.schema.interface.options,
3939
- },
3940
- }
3941
- : {
3942
- type: 'text-editor',
3943
- path: property.name,
3944
- options: { readonly: true },
3945
- },
3946
- };
3947
- }
3948
- /**
3949
- * Maps an entity column metadata (and its related property) to a list widget column configuration.
3950
- */
3951
- function mapEntityColumnToWidgetColumn(entity, column) {
3952
- const property = entity.properties.find((p) => p.name === column.name);
3953
- return {
3954
- name: column.name,
3955
- title: column.title || property?.title || column.name,
3956
- width: column.options?.width,
3957
- visible: column.options?.visible !== false,
3958
- widget: property?.schema?.interface
3959
- ? {
3960
- type: property.schema.interface.type || 'text-editor',
3961
- path: column.options?.dataPath || column.name,
3962
- options: {
3963
- readonly: true,
3964
- ...property.schema.interface.options,
3965
- },
3966
- }
3967
- : {
3968
- type: 'text-editor',
3969
- path: column.options?.dataPath || column.name,
3970
- options: { readonly: true },
3971
- },
3972
- };
3973
- }
3974
- //#endregion
3975
- //#region ---- Include/Exclude Utilities ----
3976
- /**
3977
- * Applies include and exclude filters to a named collection while preserving order.
3978
- */
3979
- function applyIncludeExclude(items, include = [], exclude = []) {
3980
- let result = items;
3981
- if (include.length > 0) {
3982
- result = result.filter((i) => include.includes(i.name));
3983
- }
3984
- if (exclude.length > 0) {
3985
- result = result.filter((i) => !exclude.includes(i.name));
3986
- }
3987
- return result;
3988
- }
3989
- /**
3990
- * Returns only visible (non-hidden) properties of an entity.
3991
- */
3992
- function getVisibleProperties(entity) {
3993
- return entity.properties.filter((prop) => !prop.schema?.hidden);
3994
- }
3995
- //#endregion
3996
-
3997
- class AXPEntityListTableService {
3998
- constructor() {
3999
- //#region ---- Services & Dependencies ----
4000
- this.entityResolver = inject(AXPEntityResolver);
4001
- this.workflow = inject(AXPWorkflowService);
4002
- this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
4003
- this.evaluateExpressions = async (options, data) => {
4004
- if (!options) {
4005
- return {};
4006
- }
4007
- const scope = {
4008
- context: {
4009
- eval: (path) => {
4010
- return get(data, path);
4011
- },
4012
- },
4013
- };
4014
- return await this.expressionEvaluator.evaluate(options, scope);
4015
- };
4016
- }
4017
- //#endregion
4018
- //#region ---- Public Methods ----
4019
- /**
4020
- * Convert Entity to List Widget Options
4021
- */
4022
- async convertEntityToListOptions(entity, options, allActions) {
4023
- const listOptions = {
4024
- // 📊 Data Source
4025
- dataSource: this.createDataSource(entity),
4026
- // 📋 Columns from Properties
4027
- columns: this.createColumnsFromProperties(entity, options),
4028
- // 🎯 Row Commands from Actions
4029
- primaryCommands: this.createRowCommands(allActions, 'primary'),
4030
- secondaryCommands: this.createRowCommands(allActions, 'secondary'),
4031
- // ⚙️ Table Features
4032
- showIndex: entity.interfaces?.master?.list?.views?.[0]?.indexCol ?? false,
4033
- allowSelection: this.hasSelectedScopeActions(entity),
4034
- paging: true,
4035
- showHeader: true,
4036
- showFooter: false,
4037
- // 🔗 Entity Configuration
4038
- parentField: entity.parentKey,
4039
- fetchDataMode: 'manual',
4040
- minHeight: 250,
4041
- // 🎪 Events
4042
- ...this.createDefaultEvents(entity, allActions),
4043
- };
4044
- return listOptions;
4045
- }
4046
- //#endregion
4047
- //#region ---- Private Methods ----
4048
- /**
4049
- * Create DataSource for Entity
4050
- */
4051
- createDataSource(entity) {
4052
- return new AXDataSource({
4053
- byKey: (key) => {
4054
- const func = entity.queries.byKey.execute;
4055
- return func(key);
4056
- },
4057
- load: (e) => {
4058
- const func = entity.queries.list?.execute;
4059
- if (!func) {
4060
- throw new Error(`Entity ${entity.name} does not have a list query`);
4061
- }
4062
- return func(e);
4063
- },
4064
- pageSize: entity.interfaces?.master?.list?.views?.[0]?.pageSize || 10,
4065
- key: 'id',
4066
- });
4067
- }
4068
- /**
4069
- * Convert Properties to Columns
4070
- */
4071
- createColumnsFromProperties(entity, options) {
4072
- const excludeColumns = options?.excludeColumns || [];
4073
- const includeColumns = options?.includeColumns || [];
4074
- // If columns are defined, use them; otherwise use visible properties
4075
- const baseColumns = entity.columns && entity.columns.length > 0
4076
- ? entity.columns.map((col) => this.mapEntityColumnToWidgetColumn(entity, col))
4077
- : getVisibleProperties(entity).map((prop) => mapPropertyToWidgetColumn(prop));
4078
- return applyIncludeExclude(baseColumns, includeColumns, excludeColumns);
2377
+ return this.executeWithMiddleware(context, handler);
4079
2378
  }
4080
2379
  /**
4081
- * Map EntityTableColumn to ListWidgetColumn
2380
+ * Execute updateOne operation with middleware pipeline
4082
2381
  */
4083
- mapEntityColumnToWidgetColumn(entity, column) {
4084
- return mapEntityColumnToWidgetColumn(entity, column);
2382
+ async updateOne(entityName, id, keyValues) {
2383
+ const context = {
2384
+ operation: 'updateOne',
2385
+ entityName,
2386
+ dbName: this.storageService.dbName,
2387
+ input: { id, keyValues },
2388
+ metadata: {
2389
+ startTime: Date.now(),
2390
+ requestId: generateRequestId(),
2391
+ },
2392
+ };
2393
+ const handler = async (ctx) => {
2394
+ return this.storageService.updateOne(ctx.entityName, ctx.input.id, ctx.input.keyValues);
2395
+ };
2396
+ return this.executeWithMiddleware(context, handler);
4085
2397
  }
4086
2398
  /**
4087
- * Convert Entity Actions to Row Commands
2399
+ * Execute deleteOne operation with middleware pipeline
4088
2400
  */
4089
- createRowCommands(actions, priority) {
4090
- return actions
4091
- .filter((action) => action.scope === AXPEntityCommandScope.Individual && // Only individual actions
4092
- action.priority === priority && // Matching priority
4093
- !action.hidden)
4094
- .map((action) => ({
4095
- name: action.name,
4096
- text: action.title,
4097
- icon: action.icon,
4098
- color: action.color,
4099
- look: 'outline',
4100
- visible: !action.hidden,
4101
- disabled: action.disabled,
4102
- }));
2401
+ async deleteOne(entityName, id) {
2402
+ const context = {
2403
+ operation: 'deleteOne',
2404
+ entityName,
2405
+ dbName: this.storageService.dbName,
2406
+ input: { id },
2407
+ metadata: {
2408
+ startTime: Date.now(),
2409
+ requestId: generateRequestId(),
2410
+ },
2411
+ };
2412
+ const handler = async (ctx) => {
2413
+ return this.storageService.deleteOne(ctx.entityName, ctx.input.id);
2414
+ };
2415
+ return this.executeWithMiddleware(context, handler);
4103
2416
  }
4104
2417
  /**
4105
- * Check if entity has Selected Scope Actions
2418
+ * Execute query operation with middleware pipeline
4106
2419
  */
4107
- hasSelectedScopeActions(entity) {
4108
- const actions = entity.interfaces?.master?.list?.actions || [];
4109
- return actions.some((action) => action.scope === AXPEntityCommandScope.Selected);
2420
+ async query(entityName, request) {
2421
+ const context = {
2422
+ operation: 'query',
2423
+ entityName,
2424
+ dbName: this.storageService.dbName,
2425
+ input: { request },
2426
+ metadata: {
2427
+ startTime: Date.now(),
2428
+ requestId: generateRequestId(),
2429
+ },
2430
+ };
2431
+ const handler = async (ctx) => {
2432
+ return this.storageService.query(ctx.entityName, ctx.input.request);
2433
+ };
2434
+ return this.executeWithMiddleware(context, handler);
4110
2435
  }
4111
2436
  /**
4112
- * Handle execution of a row command (shared by double-click and command handlers)
2437
+ * Execute initial operation with middleware pipeline
4113
2438
  */
4114
- async handleRowCommand(e, selectedRows, entity, allActions) {
4115
- const data = e.data;
4116
- const commandName = e.name;
4117
- const action = allActions.find((c) => {
4118
- return (c.name == e.name &&
4119
- ((selectedRows?.length
4120
- ? c.scope == AXPEntityCommandScope.Selected
4121
- : c.scope == AXPEntityCommandScope.Individual) ||
4122
- c.scope == AXPEntityCommandScope.TypeLevel));
4123
- });
4124
- const command = commandName.split('&')[0];
4125
- const options = await this.evaluateExpressions(action?.options, data);
4126
- await this.workflow.execute(command, {
4127
- entity: getEntityInfo(entity).source,
4128
- entityInfo: {
4129
- name: entity.name,
4130
- module: entity.module,
4131
- title: entity.title,
4132
- parentKey: entity.parentKey,
4133
- source: entity.source,
2439
+ async initial(entityName, collection, options) {
2440
+ const context = {
2441
+ operation: 'initial',
2442
+ entityName,
2443
+ dbName: this.storageService.dbName,
2444
+ input: { collection, options },
2445
+ metadata: {
2446
+ startTime: Date.now(),
2447
+ requestId: generateRequestId(),
4134
2448
  },
4135
- data: action?.scope == AXPEntityCommandScope.Selected ? selectedRows : data,
4136
- options: options,
4137
- metadata: action?.metadata,
4138
- });
4139
- console.log('Entity List - Row command:', e.name, e.data);
2449
+ };
2450
+ const handler = async (ctx) => {
2451
+ return this.storageService.initial(ctx.entityName, ctx.input.collection, ctx.input.options);
2452
+ };
2453
+ return this.executeWithMiddleware(context, handler);
4140
2454
  }
4141
2455
  /**
4142
- * Create default events
2456
+ * Execute operation with middleware pipeline
4143
2457
  */
4144
- createDefaultEvents(entity, allActions) {
4145
- return {
4146
- onRowClick: (row) => {
4147
- console.log('Entity List - Row clicked:', row);
4148
- },
4149
- onRowDoubleClick: (e) => {
4150
- console.log('Entity List - Row double clicked:', e);
4151
- const defaultAction = allActions.find((c) => {
4152
- const commandName = c.name.split('&')[0];
4153
- return (c.default || commandName === 'open-entity') && !c.hidden;
4154
- });
4155
- if (!defaultAction) {
4156
- return;
4157
- }
4158
- const d = {
4159
- component: e.component,
4160
- name: defaultAction.name,
4161
- data: e.data,
4162
- };
4163
- this.handleRowCommand(d, undefined, entity, allActions);
4164
- },
4165
- onSelectionChange: (selectedRows) => {
4166
- console.log('Entity List - Selection changed:', selectedRows);
4167
- },
4168
- onRowCommand: async (e, selectedRows) => {
4169
- await this.handleRowCommand(e, selectedRows, entity, allActions);
4170
- },
4171
- };
2458
+ async executeWithMiddleware(context, handler) {
2459
+ const middlewares = this.registry.getMiddlewares(context.entityName, context.operation);
2460
+ // Wrap middlewares with injection context
2461
+ const wrappedMiddlewares = middlewares.map(middleware => {
2462
+ return (ctx, next) => runInInjectionContext(this.injector, () => middleware(ctx, next));
2463
+ });
2464
+ const composed = composeEntityStorageMiddlewares(wrappedMiddlewares)(handler);
2465
+ return composed(context);
4172
2466
  }
4173
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListTableService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4174
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListTableService }); }
2467
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageExecutor, deps: [{ token: AXPEntityStorageService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2468
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageExecutor, providedIn: 'root' }); }
4175
2469
  }
4176
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListTableService, decorators: [{
4177
- type: Injectable
4178
- }] });
2470
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageExecutor, decorators: [{
2471
+ type: Injectable,
2472
+ args: [{ providedIn: 'root' }]
2473
+ }], ctorParameters: () => [{ type: AXPEntityStorageService }] });
4179
2474
 
4180
- class AXPEntityListToolbarService {
4181
- constructor() {
4182
- //#region ---- Services & Dependencies ----
4183
- this.widgetResolver = inject(AXPWidgetRegistryService);
2475
+ /**
2476
+ * Entity Storage Service with middleware support
2477
+ *
2478
+ * This service wraps the original AXPEntityStorageService and adds middleware pipeline support.
2479
+ * It delegates all operations to the middleware executor which applies the middleware chain.
2480
+ */
2481
+ class AXPEntityStorageWithMiddlewareService extends AXPEntityStorageService {
2482
+ constructor(originalStorageService, registry) {
2483
+ super();
2484
+ this.originalStorageService = originalStorageService;
2485
+ this.registry = registry;
2486
+ this.executor = new AXPEntityStorageExecutor(originalStorageService);
4184
2487
  }
4185
- //#endregion
4186
- //#region ---- Public Methods ----
4187
- /**
4188
- * Convert Entity to Toolbar Options
4189
- */
4190
- async convertEntityToolbarOptions(entity, options) {
4191
- const toolbarOptions = {
4192
- filterDefinitions: this.createFilterDefinitions(entity),
4193
- columnDefinitions: this.createColumnDefinitions(entity, options),
4194
- sortDefinitions: this.createSortDefinitions(entity),
4195
- };
4196
- return toolbarOptions;
2488
+ get dbName() {
2489
+ return this.originalStorageService.dbName;
4197
2490
  }
4198
- //#endregion
4199
- //#region ---- Private Methods ----
2491
+ // Middleware Management Methods
4200
2492
  /**
4201
- * Create Filter Definitions for Toolbar
2493
+ * Add a global middleware that applies to all operations
4202
2494
  */
4203
- createFilterDefinitions(entity) {
4204
- const props = entity.properties.filter((c) => c.options?.filter?.advance?.enabled || c.options?.filter?.inline?.enabled);
4205
- return props.map((e) => {
4206
- const widgetConfig = this.widgetResolver.resolve(e.schema.interface?.type);
4207
- const type = (e.options?.filter?.advance?.widgetType ||
4208
- widgetConfig?.defaultFilterWidgetName ||
4209
- e.schema.interface?.type);
4210
- return {
4211
- title: e.title,
4212
- field: e.name,
4213
- operator: {
4214
- type: 'contains',
4215
- },
4216
- widget: { ...e.schema.interface, path: e.name, type },
4217
- filters: [],
4218
- isParametric: false,
4219
- icon: widgetConfig?.icon,
4220
- filterType: {
4221
- advance: e.options?.filter?.advance?.enabled ?? false,
4222
- inline: e.options?.filter?.inline?.enabled ?? false,
4223
- },
4224
- };
4225
- });
2495
+ useGlobal(middleware) {
2496
+ this.registry.useGlobal(middleware);
4226
2497
  }
4227
2498
  /**
4228
- * Create Column Definitions for Toolbar
2499
+ * Add middleware for specific entity
4229
2500
  */
4230
- createColumnDefinitions(entity, options) {
4231
- const { columns = [] } = entity;
4232
- const excludeColumns = options?.excludeColumns || [];
4233
- const includeColumns = options?.includeColumns || [];
4234
- const visibleProperties = getVisibleProperties(entity);
4235
- const visiblePropNames = new Set(visibleProperties.map(({ name }) => name));
4236
- // Prefer explicit entity.columns if present; fallback to visible properties
4237
- const baseColumns = columns.length > 0
4238
- ? columns
4239
- .filter(({ name }) => visiblePropNames.has(name))
4240
- .map((column) => {
4241
- const property = visibleProperties.find(({ name }) => name === column.name);
4242
- return {
4243
- name: column.name,
4244
- title: property?.title,
4245
- visible: column?.options?.visible ?? true,
4246
- };
4247
- })
4248
- : visibleProperties.map((property) => ({
4249
- name: property.name,
4250
- title: property.title,
4251
- visible: true,
4252
- }));
4253
- return applyIncludeExclude(baseColumns, includeColumns, excludeColumns);
2501
+ useForEntity(entityName, middleware) {
2502
+ this.registry.useForEntity(entityName, middleware);
4254
2503
  }
4255
2504
  /**
4256
- * Create Sort Definitions for Toolbar
2505
+ * Add middleware for specific operation
4257
2506
  */
4258
- createSortDefinitions(entity) {
4259
- const props = entity.properties.filter((c) => c.options?.sort?.enabled);
4260
- return props.map((e) => {
4261
- return {
4262
- name: e.name,
4263
- title: e.title,
4264
- };
4265
- });
2507
+ useForOperation(operation, middleware) {
2508
+ this.registry.useForOperation(operation, middleware);
2509
+ }
2510
+ // Storage Operations with Middleware Pipeline
2511
+ async initial(entityName, collection, options) {
2512
+ return this.executor.initial(entityName, collection, options);
2513
+ }
2514
+ async getOne(entityName, id) {
2515
+ return this.executor.getOne(entityName, id);
2516
+ }
2517
+ async updateOne(entityName, id, keyValues) {
2518
+ return this.executor.updateOne(entityName, id, keyValues);
2519
+ }
2520
+ async deleteOne(entityName, id) {
2521
+ return this.executor.deleteOne(entityName, id);
2522
+ }
2523
+ async insertOne(entityName, entity) {
2524
+ return this.executor.insertOne(entityName, entity);
2525
+ }
2526
+ async getAll(entityName) {
2527
+ return this.executor.getAll(entityName);
2528
+ }
2529
+ async query(entityName, request) {
2530
+ return this.executor.query(entityName, request);
2531
+ }
2532
+ // Direct access to original service (bypass middleware)
2533
+ get originalService() {
2534
+ return this.originalStorageService;
4266
2535
  }
4267
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListToolbarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4268
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListToolbarService }); }
2536
+ // Access to registry for advanced middleware management
2537
+ get middlewareRegistry() {
2538
+ return this.registry;
2539
+ }
2540
+ 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 }); }
2541
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageWithMiddlewareService }); }
4269
2542
  }
4270
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListToolbarService, decorators: [{
2543
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageWithMiddlewareService, decorators: [{
4271
2544
  type: Injectable
4272
- }] });
2545
+ }], ctorParameters: () => [{ type: AXPEntityStorageService }, { type: AXPEntityStorageRegistry }] });
4273
2546
 
4274
- class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
4275
- constructor() {
4276
- super(...arguments);
4277
- this.entityResolver = inject(AXPEntityResolver);
4278
- this.workflow = inject(AXPWorkflowService);
4279
- this.entityListTableService = inject(AXPEntityListTableService);
4280
- this.entityListToolbarService = inject(AXPEntityListToolbarService);
4281
- this.layoutThemeService = inject(AXPLayoutThemeService);
4282
- this.isMounted = signal(false, ...(ngDevMode ? [{ debugName: "isMounted" }] : []));
4283
- this.entity = signal(null, ...(ngDevMode ? [{ debugName: "entity" }] : []));
4284
- this.listNode = signal(null, ...(ngDevMode ? [{ debugName: "listNode" }] : []));
4285
- this.list = viewChild('list', ...(ngDevMode ? [{ debugName: "list" }] : []));
4286
- this.allWidgets = viewChildren(AXPWidgetRendererDirective, ...(ngDevMode ? [{ debugName: "allWidgets" }] : []));
4287
- this.listWidget = linkedSignal(() => this.allWidgets().find((widget) => widget.node()?.type === AXPWidgetsCatalog.list));
4288
- this.toolbarWidget = computed(() => this.allWidgets().find((widget) => widget.node()?.type === AXPWidgetsCatalog.listToolbar), ...(ngDevMode ? [{ debugName: "toolbarWidget" }] : []));
4289
- this.selectedItems = signal([], ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
4290
- this.toolbarNode = signal(null, ...(ngDevMode ? [{ debugName: "toolbarNode" }] : []));
4291
- this.destroyed = new Subject();
4292
- //options
4293
- this.entitySource = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entitySource" }] : []));
4294
- this.excludeColumns = computed(() => this.options()['excludeColumns'], ...(ngDevMode ? [{ debugName: "excludeColumns" }] : []));
4295
- this.includeColumns = computed(() => this.options()['includeColumns'], ...(ngDevMode ? [{ debugName: "includeColumns" }] : []));
4296
- this.externalActions = computed(() => this.options()['actions'], ...(ngDevMode ? [{ debugName: "externalActions" }] : []));
4297
- this.showEntityActions = computed(() => this.options()['showEntityActions'] ?? true, ...(ngDevMode ? [{ debugName: "showEntityActions" }] : []));
4298
- this.showToolbar = computed(() => this.options()['showToolbar'] ?? true, ...(ngDevMode ? [{ debugName: "showToolbar" }] : []));
4299
- //actions
4300
- this.allActions = computed(() => {
4301
- const originalList = this.entity()?.interfaces?.master?.list?.actions ?? [];
4302
- const externalActionList = this.externalActions() ?? [];
4303
- const usedOverrideActions = new Set();
4304
- const mergedActions = originalList.map((originalAction) => {
4305
- const originalCommandName = typeof originalAction.command === 'string' ? originalAction.command : originalAction.command?.name;
4306
- const overrideAction = externalActionList.find((action) => {
4307
- const actionCommandName = typeof action?.command === 'string' ? action.command : action?.command?.name;
4308
- return actionCommandName === originalCommandName;
4309
- });
4310
- if (overrideAction) {
4311
- const overrideKey = `${typeof overrideAction.command === 'string' ? overrideAction.command : overrideAction.command?.name}`;
4312
- usedOverrideActions.add(overrideKey);
4313
- return new AXPEntityCommandTriggerViewModel(this.entity(), overrideAction);
2547
+ /**
2548
+ * Injection token for entity storage middleware setup
2549
+ */
2550
+ const AXP_ENTITY_STORAGE_MIDDLEWARE_SETUP = new InjectionToken('AXP_ENTITY_STORAGE_MIDDLEWARE_SETUP');
2551
+ /**
2552
+ * Injection token for entity storage middleware extensions
2553
+ */
2554
+ const AXP_ENTITY_STORAGE_EXTENSION = new InjectionToken('AXP_ENTITY_STORAGE_EXTENSION');
2555
+ /**
2556
+ * Provide entity storage middleware configuration
2557
+ */
2558
+ function provideEntityStorageMiddleware(config) {
2559
+ const providers = [];
2560
+ // Register extension middlewares
2561
+ if (config.extensions) {
2562
+ providers.push(...config.extensions.map(ext => ({
2563
+ provide: AXP_ENTITY_STORAGE_EXTENSION,
2564
+ useValue: ext,
2565
+ multi: true,
2566
+ })));
2567
+ }
2568
+ // Main setup provider
2569
+ providers.push({
2570
+ provide: AXP_ENTITY_STORAGE_MIDDLEWARE_SETUP,
2571
+ useFactory: () => {
2572
+ const registry = inject(AXPEntityStorageRegistry);
2573
+ // Register global middlewares
2574
+ if (config.global) {
2575
+ for (const middleware of config.global) {
2576
+ registry.useGlobal(middleware);
4314
2577
  }
4315
- return new AXPEntityCommandTriggerViewModel(this.entity(), originalAction);
4316
- });
4317
- const additionalActions = externalActionList
4318
- .filter((action) => {
4319
- const actionKey = `${typeof action?.command === 'string' ? action.command : action?.command?.name}`;
4320
- return !usedOverrideActions.has(actionKey);
4321
- })
4322
- .map((action) => new AXPEntityCommandTriggerViewModel(this.entity(), action));
4323
- return [...additionalActions, ...mergedActions];
4324
- }, ...(ngDevMode ? [{ debugName: "allActions" }] : []));
4325
- this.primaryActions = computed(() => {
4326
- const actions = this.allActions()
4327
- .filter((a) => a.priority == 'primary' &&
4328
- ((a.scope == AXPEntityCommandScope.Selected && this.selectedItems().length) ||
4329
- (a.scope == AXPEntityCommandScope.TypeLevel && !this.selectedItems().length)))
4330
- .map((tr) => ({
4331
- name: tr.name,
4332
- title: tr.title,
4333
- icon: tr.icon,
4334
- color: tr.color,
4335
- disabled: tr.disabled,
4336
- command: {
4337
- name: tr.name,
4338
- options: tr.options,
4339
- metadata: tr.metadata,
4340
- },
4341
- }));
4342
- return actions;
4343
- }, ...(ngDevMode ? [{ debugName: "primaryActions" }] : []));
4344
- this.secondaryActions = computed(() => {
4345
- const actions = this.allActions()
4346
- .filter((a) => a.priority == 'secondary' && a.scope == AXPEntityCommandScope.TypeLevel)
4347
- .map((tr) => ({
4348
- name: tr.name,
4349
- title: tr.title,
4350
- icon: tr.icon,
4351
- color: tr.color,
4352
- disabled: tr.disabled,
4353
- separated: tr.separated,
4354
- command: {
4355
- name: tr.name,
4356
- options: tr.options,
4357
- metadata: tr.metadata,
4358
- },
4359
- }));
4360
- return actions;
4361
- }, ...(ngDevMode ? [{ debugName: "secondaryActions" }] : []));
4362
- //#region ---- Query Change Handler ----
4363
- this.#effect = effect(() => {
4364
- const queries = this.getValue()?.toolbar;
4365
- const listInstance = this.listWidget()?.instance;
4366
- const dataSource = this.listWidget()?.options()['dataSource'];
4367
- const isMounted = this.isMounted();
4368
- if (!this.hasRequiredDependencies(dataSource, queries, listInstance)) {
4369
- return;
4370
2578
  }
4371
- untracked(() => {
4372
- this.handleQueryChanges(queries, dataSource, listInstance, isMounted);
4373
- });
4374
- }, ...(ngDevMode ? [{ debugName: "#effect" }] : []));
4375
- //#endregion
4376
- this.context = {};
4377
- this.previousQueries = null;
4378
- }
4379
- handleActionClick(item) {
4380
- if (item.command && (item.items?.length ?? 0) == 0) {
4381
- this.execute(item.command.name, null);
4382
- }
4383
- }
4384
- handleSecondaryActionClick(item) {
4385
- if (item.command) {
4386
- this.execute(item.command.name, null);
4387
- }
4388
- }
4389
- // ngDoCheck(): void {
4390
- // console.log(this.listWidget()?.instance.output('selectedRows'));
4391
- // }
4392
- async execute(commandName, data) {
4393
- const action = this.allActions().find((c) => {
4394
- return (c.name == commandName &&
4395
- ((this.selectedItems().length
4396
- ? c.scope == AXPEntityCommandScope.Selected
4397
- : c.scope == AXPEntityCommandScope.Individual) ||
4398
- c.scope == AXPEntityCommandScope.TypeLevel));
4399
- });
4400
- const command = commandName.split('&')[0];
4401
- // const options = await this.evaluateExpressions(action?.options, data);
4402
- await this.workflow.execute(command, {
4403
- entity: this.entitySource(),
4404
- entityInfo: {
4405
- name: this.entity()?.name,
4406
- module: this.entity()?.module,
4407
- title: this.entity()?.title,
4408
- parentKey: this.entity()?.parentKey,
4409
- source: this.entity()?.source,
4410
- },
4411
- data: action?.scope == AXPEntityCommandScope.Selected
4412
- ? this.selectedItems()
4413
- : action?.options?.['process']?.data || null,
4414
- options: action?.options,
4415
- metadata: action?.metadata,
4416
- });
4417
- }
4418
- //#region ---- Query Change Handler ----
4419
- #effect;
4420
- /**
4421
- * Validates that all required dependencies are available
4422
- */
4423
- hasRequiredDependencies(dataSource, queries, listInstance) {
4424
- return !!(dataSource && queries && listInstance);
2579
+ // Register entity-specific middlewares
2580
+ if (config.entities) {
2581
+ for (const [entityName, middlewares] of Object.entries(config.entities)) {
2582
+ for (const middleware of middlewares) {
2583
+ registry.useForEntity(entityName, middleware);
2584
+ }
2585
+ }
2586
+ }
2587
+ // Register operation-specific middlewares
2588
+ if (config.operations) {
2589
+ for (const [operation, middlewares] of Object.entries(config.operations)) {
2590
+ for (const middleware of middlewares) {
2591
+ registry.useForOperation(operation, middleware);
2592
+ }
2593
+ }
2594
+ }
2595
+ return true;
2596
+ },
2597
+ multi: true,
2598
+ });
2599
+ return makeEnvironmentProviders(providers);
2600
+ }
2601
+ /**
2602
+ * Simplified provider for global middleware only
2603
+ */
2604
+ function provideGlobalEntityStorageMiddleware(middlewares) {
2605
+ return provideEntityStorageMiddleware({ global: middlewares });
2606
+ }
2607
+ /**
2608
+ * Provider for entity-specific middlewares
2609
+ */
2610
+ function provideEntitySpecificMiddleware(entityName, middlewares) {
2611
+ return provideEntityStorageMiddleware({
2612
+ entities: { [entityName]: middlewares }
2613
+ });
2614
+ }
2615
+ /**
2616
+ * Provider for operation-specific middlewares
2617
+ */
2618
+ function provideOperationSpecificMiddleware(operation, middlewares) {
2619
+ return provideEntityStorageMiddleware({
2620
+ operations: { [operation]: middlewares }
2621
+ });
2622
+ }
2623
+
2624
+ /**
2625
+ * Logging middleware for entity storage operations
2626
+ */
2627
+ const loggingMiddleware = async (context, next) => {
2628
+ const startTime = Date.now();
2629
+ console.group(`🔄 Entity Storage Operation: ${context.operation}`);
2630
+ console.log('📋 Entity:', context.entityName);
2631
+ console.log('🗄️ Database:', context.dbName);
2632
+ console.log('📨 Input:', context.input);
2633
+ console.log('🆔 Request ID:', context.metadata.requestId);
2634
+ try {
2635
+ const result = await next(context);
2636
+ const duration = Date.now() - startTime;
2637
+ console.log('✅ Success');
2638
+ console.log('⏱️ Duration:', `${duration}ms`);
2639
+ console.log('📤 Result:', result);
2640
+ console.groupEnd();
2641
+ return result;
4425
2642
  }
4426
- /**
4427
- * Handles all query-related changes (filters, sorts, columns)
4428
- */
4429
- handleQueryChanges(queries, dataSource, listInstance, isMounted) {
4430
- const changeTracker = this.analyzeChanges(queries);
4431
- this.previousQueries = queries;
4432
- this.applyDataSourceChanges(dataSource, queries, changeTracker);
4433
- this.handleListRefresh(listInstance, changeTracker, isMounted);
4434
- this.handleColumnChanges(changeTracker);
2643
+ catch (error) {
2644
+ const duration = Date.now() - startTime;
2645
+ console.error('❌ Error');
2646
+ console.error('⏱️ Duration:', `${duration}ms`);
2647
+ console.error('💥 Error:', error);
2648
+ console.groupEnd();
2649
+ throw error;
4435
2650
  }
4436
- /**
4437
- * Analyzes what has changed between current and previous queries
4438
- */
4439
- analyzeChanges(queries) {
4440
- const changes = getChangedPaths(queries, this.previousQueries);
4441
- return {
4442
- isFilterChanged: changes.includes('filters'),
4443
- isSortChanged: changes.includes('sorts'),
4444
- isColumnsChanged: changes.includes('columns'),
4445
- hasAnyChange: changes.length > 0,
2651
+ };
2652
+ /**
2653
+ * Performance monitoring middleware
2654
+ */
2655
+ const performanceMiddleware = async (context, next) => {
2656
+ const startTime = performance.now();
2657
+ try {
2658
+ const result = await next(context);
2659
+ const duration = performance.now() - startTime;
2660
+ // Log slow operations (> 1000ms)
2661
+ if (duration > 1000) {
2662
+ console.warn(`⚠️ Slow operation detected: ${context.operation} on ${context.entityName} took ${duration.toFixed(2)}ms`);
2663
+ }
2664
+ // Add performance metrics to context
2665
+ context.metadata['performanceMetrics'] = {
2666
+ duration,
2667
+ operation: context.operation,
2668
+ entityName: context.entityName,
4446
2669
  };
2670
+ return result;
4447
2671
  }
4448
- /**
4449
- * Applies filter and sort changes to the data source
4450
- */
4451
- applyDataSourceChanges(dataSource, queries, changeTracker) {
4452
- if (changeTracker.isFilterChanged) {
4453
- dataSource.filter({
4454
- filters: queries?.filters,
4455
- });
4456
- }
4457
- if (changeTracker.isSortChanged) {
4458
- dataSource.sort(...(queries.sorts || []));
4459
- }
2672
+ catch (error) {
2673
+ const duration = performance.now() - startTime;
2674
+ console.error(`❌ Failed operation: ${context.operation} on ${context.entityName} failed after ${duration.toFixed(2)}ms`);
2675
+ throw error;
4460
2676
  }
4461
- /**
4462
- * Handles list refresh logic based on changes and mount status
4463
- */
4464
- handleListRefresh(listInstance, changeTracker, isMounted) {
4465
- const shouldRefresh = changeTracker.isFilterChanged || changeTracker.isSortChanged || !isMounted;
4466
- if (shouldRefresh) {
4467
- listInstance.call('refresh');
4468
- // Set mounted flag only on initial load (not when filters/sorts change)
4469
- if (!changeTracker.isFilterChanged && !changeTracker.isSortChanged) {
4470
- this.isMounted.set(true);
2677
+ };
2678
+ /**
2679
+ * Error handling middleware with retry logic
2680
+ */
2681
+ const errorHandlingMiddleware = async (context, next) => {
2682
+ const maxRetries = 3;
2683
+ let attempt = 0;
2684
+ while (attempt < maxRetries) {
2685
+ try {
2686
+ const result = await next(context);
2687
+ if (attempt > 0) {
2688
+ console.log(`✅ Operation succeeded on retry ${attempt}/${maxRetries}`);
4471
2689
  }
2690
+ return result;
4472
2691
  }
4473
- }
4474
- /**
4475
- * Handles column-related changes
4476
- * TODO: Implement column change logic
4477
- */
4478
- handleColumnChanges(changeTracker) {
4479
- if (!changeTracker.isColumnsChanged) {
4480
- return;
4481
- }
4482
- const listInstance = this.listWidget()?.instance;
4483
- const toolbarState = this.getValue()?.toolbar;
4484
- if (!listInstance || !toolbarState?.columns) {
4485
- return;
4486
- }
4487
- // Current columns from list options
4488
- const currentColumns = (listInstance.options()['columns'] || []);
4489
- const columnByName = new Map(currentColumns.map((c) => [c.name, c]));
4490
- // Build new ordered columns array based on toolbar order/visibility
4491
- const updatedColumns = toolbarState.columns
4492
- .map((q) => {
4493
- const base = columnByName.get(q.name);
4494
- if (!base) {
4495
- return null;
2692
+ catch (error) {
2693
+ attempt++;
2694
+ // Don't retry for certain operations or error types
2695
+ if (context.operation === 'deleteOne' ||
2696
+ error?.code === 'VALIDATION_ERROR' ||
2697
+ attempt >= maxRetries) {
2698
+ console.error(`❌ Operation failed after ${attempt} attempts:`, error);
2699
+ throw error;
4496
2700
  }
4497
- // Preserve all existing column config but update visibility
4498
- return { ...base, visible: q.visible };
4499
- })
4500
- .filter((c) => c != null);
4501
- // Apply updated columns to the list widget and refresh
4502
- listInstance.setOptions({ columns: updatedColumns });
4503
- }
4504
- async ngOnInit() {
4505
- super.ngOnInit();
4506
- const [moduleName, entityName] = this.entitySource().split('.');
4507
- if (!moduleName || !entityName) {
4508
- throw new Error('Invalid entity source');
2701
+ console.warn(`⚠️ Attempt ${attempt}/${maxRetries} failed, retrying...`, error.message);
2702
+ // Wait before retry (exponential backoff)
2703
+ await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
4509
2704
  }
4510
- // Resolve entity and set it in the signal
4511
- const resolvedEntity = await this.entityResolver.get(moduleName, entityName);
4512
- if (!resolvedEntity) {
4513
- throw new Error(`Entity not found: ${this.entitySource()}`);
4514
- }
4515
- this.entity.set(resolvedEntity);
4516
- const options = {
4517
- excludeColumns: this.excludeColumns(),
4518
- includeColumns: this.includeColumns(),
4519
- };
4520
- const listOptions = await this.entityListTableService.convertEntityToListOptions(resolvedEntity, options, this.allActions());
4521
- const toolbarOptions = await this.entityListToolbarService.convertEntityToolbarOptions(resolvedEntity, options);
4522
- this.listNode.set({
4523
- type: AXPWidgetsCatalog.list,
4524
- options: listOptions,
4525
- path: `table`,
4526
- name: 'table',
4527
- mode: 'view',
4528
- defaultValue: this.getValue()?.table,
4529
- });
4530
- this.toolbarNode.set({
4531
- type: AXPWidgetsCatalog.listToolbar,
4532
- path: `toolbar`,
4533
- options: toolbarOptions,
4534
- mode: 'view',
4535
- defaultValue: {
4536
- filters: this.getValue()?.toolbar?.filters,
4537
- sorts: this.getValue()?.toolbar?.sorts,
4538
- columns: this.getValue()?.toolbar?.columns,
4539
- },
4540
- });
4541
2705
  }
4542
- async ngAfterViewInit() {
4543
- this.workflow.events$
4544
- .pipe(ofType(AXPRefreshEvent))
4545
- .pipe(takeUntil(this.destroyed))
4546
- .subscribe((event) => {
4547
- if (event.payload.entity == this.entitySource()) {
4548
- this.listWidget()?.instance.call('refresh');
2706
+ throw new Error('Max retries exceeded');
2707
+ };
2708
+ /**
2709
+ * Validation middleware
2710
+ */
2711
+ const validationMiddleware = async (context, next) => {
2712
+ // Validate input based on operation
2713
+ switch (context.operation) {
2714
+ case 'insertOne':
2715
+ if (!context.input.entity) {
2716
+ throw new Error('Entity is required for insertOne operation');
4549
2717
  }
4550
- });
4551
- const listWidget = (await this.layoutService.waitForWidget(`${this.entitySource()}-tab-list_table`, 500));
4552
- if (listWidget?.api && typeof listWidget.api === 'function') {
4553
- const onSelectionChange = listWidget.api()['onSelectionChange'];
4554
- if (onSelectionChange) {
4555
- onSelectionChange.pipe(takeUntil(this.destroyed)).subscribe((e) => {
4556
- this.selectedItems.set(e);
4557
- });
2718
+ break;
2719
+ case 'updateOne':
2720
+ if (!context.input.id) {
2721
+ throw new Error('ID is required for updateOne operation');
2722
+ }
2723
+ if (!context.input.keyValues) {
2724
+ throw new Error('Key values are required for updateOne operation');
2725
+ }
2726
+ break;
2727
+ case 'deleteOne':
2728
+ case 'getOne':
2729
+ if (!context.input.id) {
2730
+ throw new Error(`ID is required for ${context.operation} operation`);
4558
2731
  }
2732
+ break;
2733
+ case 'query':
2734
+ if (!context.input.request) {
2735
+ throw new Error('Request is required for query operation');
2736
+ }
2737
+ break;
2738
+ case 'initial':
2739
+ if (!context.input.collection || !Array.isArray(context.input.collection)) {
2740
+ throw new Error('Collection array is required for initial operation');
2741
+ }
2742
+ break;
2743
+ }
2744
+ return next(context);
2745
+ };
2746
+ /**
2747
+ * Caching middleware (simple in-memory cache)
2748
+ */
2749
+ const cachingMiddleware = (() => {
2750
+ const cache = new Map();
2751
+ const DEFAULT_TTL = 5 * 60 * 1000; // 5 minutes
2752
+ return async (context, next) => {
2753
+ // Only cache read operations
2754
+ if (!['getOne', 'getAll', 'query'].includes(context.operation)) {
2755
+ // Clear cache for write operations on the same entity
2756
+ const keysToDelete = Array.from(cache.keys()).filter(key => key.includes(`${context.entityName}:`));
2757
+ keysToDelete.forEach(key => cache.delete(key));
2758
+ return next(context);
2759
+ }
2760
+ // Generate cache key
2761
+ const cacheKey = `${context.entityName}:${context.operation}:${JSON.stringify(context.input)}`;
2762
+ // Check cache
2763
+ const cached = cache.get(cacheKey);
2764
+ if (cached && Date.now() - cached.timestamp < cached.ttl) {
2765
+ console.log(`💾 Cache hit for ${cacheKey}`);
2766
+ return cached.data;
2767
+ }
2768
+ // Execute and cache result
2769
+ const result = await next(context);
2770
+ cache.set(cacheKey, {
2771
+ data: result,
2772
+ timestamp: Date.now(),
2773
+ ttl: DEFAULT_TTL,
2774
+ });
2775
+ console.log(`💾 Cached result for ${cacheKey}`);
2776
+ return result;
2777
+ };
2778
+ })();
2779
+
2780
+ /**
2781
+ * Simple in-memory audit storage (for demo purposes)
2782
+ */
2783
+ class InMemoryAuditStorage {
2784
+ constructor() {
2785
+ this.entries = [];
2786
+ }
2787
+ async save(entry) {
2788
+ this.entries.push(entry);
2789
+ console.log('📋 Audit entry saved:', entry);
2790
+ }
2791
+ getEntries() {
2792
+ return [...this.entries];
2793
+ }
2794
+ getEntriesForEntity(entityName) {
2795
+ return this.entries.filter(entry => entry.entityName === entityName);
2796
+ }
2797
+ clear() {
2798
+ this.entries.length = 0;
2799
+ }
2800
+ }
2801
+ // Global audit storage instance
2802
+ const auditStorage = new InMemoryAuditStorage();
2803
+ /**
2804
+ * Audit middleware that tracks all entity operations
2805
+ */
2806
+ const auditMiddleware = async (context, next) => {
2807
+ const auditEntry = {
2808
+ id: `audit_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
2809
+ entityName: context.entityName,
2810
+ operation: context.operation,
2811
+ user: context.metadata.user?.id || 'system',
2812
+ timestamp: new Date(),
2813
+ requestId: context.metadata.requestId,
2814
+ };
2815
+ // Add operation-specific data
2816
+ switch (context.operation) {
2817
+ case 'insertOne':
2818
+ auditEntry.changes = { created: context.input.entity };
2819
+ break;
2820
+ case 'updateOne':
2821
+ auditEntry.entityId = context.input.id;
2822
+ auditEntry.changes = { updated: context.input.keyValues };
2823
+ break;
2824
+ case 'deleteOne':
2825
+ auditEntry.entityId = context.input.id;
2826
+ auditEntry.changes = { deleted: true };
2827
+ break;
2828
+ case 'getOne':
2829
+ auditEntry.entityId = context.input.id;
2830
+ break;
2831
+ case 'query':
2832
+ auditEntry.metadata = { queryRequest: context.input.request };
2833
+ break;
2834
+ case 'initial':
2835
+ auditEntry.metadata = {
2836
+ collectionSize: context.input.collection?.length,
2837
+ options: context.input.options
2838
+ };
2839
+ break;
2840
+ }
2841
+ try {
2842
+ const result = await next(context);
2843
+ // For insert operations, capture the generated ID
2844
+ if (context.operation === 'insertOne' && result) {
2845
+ auditEntry.entityId = result;
4559
2846
  }
2847
+ // Save audit entry
2848
+ await auditStorage.save(auditEntry);
2849
+ return result;
4560
2850
  }
4561
- ngOnDestroy() {
4562
- this.listWidget.set(undefined);
4563
- this.destroyed.next();
4564
- this.destroyed.complete();
2851
+ catch (error) {
2852
+ // Save audit entry even for failed operations
2853
+ auditEntry.metadata = {
2854
+ ...auditEntry.metadata,
2855
+ error: error instanceof Error ? error.message : 'Unknown error'
2856
+ };
2857
+ await auditStorage.save(auditEntry);
2858
+ throw error;
4565
2859
  }
4566
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4567
- 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: "list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "allWidgets", predicate: AXPWidgetRendererDirective, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
4568
- @if (showEntityActions()) {
4569
- <div class="ax-flex ax-gap-2 ax-justify-end ax-mb-4">
4570
- @for (action of primaryActions(); track $index) {
4571
- @if (action.visible != false) {
4572
- <ax-button
4573
- [class.ax-sm]="layoutThemeService.isSmall()"
4574
- [iconOnly]="layoutThemeService.isSmall()"
4575
- [disabled]="action.disabled"
4576
- [text]="action.title"
4577
- [look]="'solid'"
4578
- [color]="action.color"
4579
- (onClick)="handleActionClick(action)"
4580
- >
4581
- <ax-prefix>
4582
- <i class="{{ action.icon }}"></i>
4583
- </ax-prefix>
4584
- @if (action?.items) {
4585
- <ax-dropdown-panel #panel>
4586
- <ax-button-item-list>
4587
- @for (sub of action?.items; track $index) {
4588
- @if (sub.visible != false) {
4589
- <ax-button-item
4590
- [text]="sub.title"
4591
- [color]="sub.color"
4592
- [disabled]="sub.disabled"
4593
- (onClick)="handleActionClick(sub)"
4594
- >
4595
- <ax-prefix>
4596
- <ax-icon icon="fa-light {{ sub.icon }}"></ax-icon>
4597
- </ax-prefix>
4598
- </ax-button-item>
4599
- @if (sub.break) {
4600
- <ax-divider></ax-divider>
4601
- }
4602
- }
4603
- }
4604
- </ax-button-item-list>
4605
- </ax-dropdown-panel>
4606
- }
4607
- </ax-button>
4608
- }
2860
+ };
2861
+ /**
2862
+ * User context middleware - adds user information to context
2863
+ */
2864
+ const userContextMiddleware = async (context, next) => {
2865
+ // In a real application, you would inject your auth service here
2866
+ // const authService = inject(AuthService);
2867
+ // const user = authService.getCurrentUser();
2868
+ // For demo purposes, we'll use a mock user
2869
+ const mockUser = {
2870
+ id: 'user123',
2871
+ name: 'John Doe',
2872
+ role: 'admin',
2873
+ };
2874
+ context.metadata.user = mockUser;
2875
+ return next(context);
2876
+ };
2877
+ /**
2878
+ * Data sanitization middleware - removes sensitive data from logs
2879
+ */
2880
+ const dataSanitizationMiddleware = async (context, next) => {
2881
+ const sensitiveFields = ['password', 'ssn', 'creditCard', 'apiKey', 'token'];
2882
+ // Sanitize input data
2883
+ if (context.input.entity) {
2884
+ context.input.entity = sanitizeObject(context.input.entity, sensitiveFields);
2885
+ }
2886
+ if (context.input.keyValues) {
2887
+ context.input.keyValues = sanitizeObject(context.input.keyValues, sensitiveFields);
2888
+ }
2889
+ const result = await next(context);
2890
+ // Sanitize result data if needed
2891
+ if (result && typeof result === 'object') {
2892
+ return sanitizeObject(result, sensitiveFields);
2893
+ }
2894
+ return result;
2895
+ };
2896
+ /**
2897
+ * Helper function to sanitize objects by removing sensitive fields
2898
+ */
2899
+ function sanitizeObject(obj, sensitiveFields) {
2900
+ if (!obj || typeof obj !== 'object') {
2901
+ return obj;
2902
+ }
2903
+ if (Array.isArray(obj)) {
2904
+ return obj.map(item => sanitizeObject(item, sensitiveFields));
2905
+ }
2906
+ const sanitized = { ...obj };
2907
+ for (const field of sensitiveFields) {
2908
+ if (field in sanitized) {
2909
+ sanitized[field] = '[REDACTED]';
4609
2910
  }
4610
- @if (secondaryActions().length) {
4611
- <ax-button
4612
- [class.ax-sm]="layoutThemeService.isSmall()"
4613
- [iconOnly]="layoutThemeService.isSmall()"
4614
- [text]="'actions'"
4615
- [look]="layoutThemeService.isSmall() ? 'blank' : 'solid'"
4616
- [color]="'default'"
4617
- >
4618
- <ax-prefix>
4619
- <i class="fa-solid fa-ellipsis-vertical"></i>
4620
- </ax-prefix>
4621
- <ax-dropdown-panel #panel>
4622
- <ax-button-item-list>
4623
- @for (item of secondaryActions(); track $index) {
4624
- @if (item.visible != false) {
4625
- <ax-button-item
4626
- [text]="item.title"
4627
- [color]="item.color"
4628
- [disabled]="item.disabled"
4629
- (onClick)="handleSecondaryActionClick(item)"
4630
- >
4631
- <ax-prefix>
4632
- <ax-icon icon="fa-light {{ item.icon }}"></ax-icon>
4633
- </ax-prefix>
4634
- </ax-button-item>
4635
- @if (item.break) {
4636
- <ax-divider></ax-divider>
4637
- }
4638
- }
4639
- }
4640
- </ax-button-item-list>
4641
- </ax-dropdown-panel>
4642
- </ax-button>
2911
+ }
2912
+ // Recursively sanitize nested objects
2913
+ for (const [key, value] of Object.entries(sanitized)) {
2914
+ if (value && typeof value === 'object') {
2915
+ sanitized[key] = sanitizeObject(value, sensitiveFields);
4643
2916
  }
4644
- </div>
4645
- }
4646
- <div class="ax-flex ax-flex-col ax-gap-2 ax-h-full">
4647
- @if (toolbarNode() != null && showToolbar()) {
4648
- <ng-container
4649
- #toolbar
4650
- axp-widget-renderer
4651
- [node]="toolbarNode()!"
4652
- [parentNode]="this"
4653
- [index]="index"
4654
- [mode]="this.mode"
4655
- ></ng-container>
4656
- }
4657
- @if (listNode() != null) {
4658
- <ng-container
4659
- #list
4660
- axp-widget-renderer
4661
- [node]="listNode()!"
4662
- [parentNode]="this"
4663
- [index]="index"
4664
- [mode]="this.mode"
4665
- ></ng-container>
4666
- }
4667
- </div>
4668
- `, 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 }); }
2917
+ }
2918
+ return sanitized;
4669
2919
  }
4670
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListWidgetViewComponent, decorators: [{
4671
- type: Component,
4672
- args: [{
4673
- template: `
4674
- @if (showEntityActions()) {
4675
- <div class="ax-flex ax-gap-2 ax-justify-end ax-mb-4">
4676
- @for (action of primaryActions(); track $index) {
4677
- @if (action.visible != false) {
4678
- <ax-button
4679
- [class.ax-sm]="layoutThemeService.isSmall()"
4680
- [iconOnly]="layoutThemeService.isSmall()"
4681
- [disabled]="action.disabled"
4682
- [text]="action.title"
4683
- [look]="'solid'"
4684
- [color]="action.color"
4685
- (onClick)="handleActionClick(action)"
4686
- >
4687
- <ax-prefix>
4688
- <i class="{{ action.icon }}"></i>
4689
- </ax-prefix>
4690
- @if (action?.items) {
4691
- <ax-dropdown-panel #panel>
4692
- <ax-button-item-list>
4693
- @for (sub of action?.items; track $index) {
4694
- @if (sub.visible != false) {
4695
- <ax-button-item
4696
- [text]="sub.title"
4697
- [color]="sub.color"
4698
- [disabled]="sub.disabled"
4699
- (onClick)="handleActionClick(sub)"
4700
- >
4701
- <ax-prefix>
4702
- <ax-icon icon="fa-light {{ sub.icon }}"></ax-icon>
4703
- </ax-prefix>
4704
- </ax-button-item>
4705
- @if (sub.break) {
4706
- <ax-divider></ax-divider>
4707
- }
4708
- }
4709
- }
4710
- </ax-button-item-list>
4711
- </ax-dropdown-panel>
4712
- }
4713
- </ax-button>
4714
- }
4715
- }
4716
- @if (secondaryActions().length) {
4717
- <ax-button
4718
- [class.ax-sm]="layoutThemeService.isSmall()"
4719
- [iconOnly]="layoutThemeService.isSmall()"
4720
- [text]="'actions'"
4721
- [look]="layoutThemeService.isSmall() ? 'blank' : 'solid'"
4722
- [color]="'default'"
4723
- >
4724
- <ax-prefix>
4725
- <i class="fa-solid fa-ellipsis-vertical"></i>
4726
- </ax-prefix>
4727
- <ax-dropdown-panel #panel>
4728
- <ax-button-item-list>
4729
- @for (item of secondaryActions(); track $index) {
4730
- @if (item.visible != false) {
4731
- <ax-button-item
4732
- [text]="item.title"
4733
- [color]="item.color"
4734
- [disabled]="item.disabled"
4735
- (onClick)="handleSecondaryActionClick(item)"
4736
- >
4737
- <ax-prefix>
4738
- <ax-icon icon="fa-light {{ item.icon }}"></ax-icon>
4739
- </ax-prefix>
4740
- </ax-button-item>
4741
- @if (item.break) {
4742
- <ax-divider></ax-divider>
4743
- }
4744
- }
4745
- }
4746
- </ax-button-item-list>
4747
- </ax-dropdown-panel>
4748
- </ax-button>
4749
- }
4750
- </div>
4751
- }
4752
- <div class="ax-flex ax-flex-col ax-gap-2 ax-h-full">
4753
- @if (toolbarNode() != null && showToolbar()) {
4754
- <ng-container
4755
- #toolbar
4756
- axp-widget-renderer
4757
- [node]="toolbarNode()!"
4758
- [parentNode]="this"
4759
- [index]="index"
4760
- [mode]="this.mode"
4761
- ></ng-container>
4762
- }
4763
- @if (listNode() != null) {
4764
- <ng-container
4765
- #list
4766
- axp-widget-renderer
4767
- [node]="listNode()!"
4768
- [parentNode]="this"
4769
- [index]="index"
4770
- [mode]="this.mode"
4771
- ></ng-container>
4772
- }
4773
- </div>
4774
- `,
4775
- standalone: true,
4776
- host: {
4777
- '[class]': '"ax-h-full"',
4778
- },
4779
- changeDetection: ChangeDetectionStrategy.OnPush,
4780
- providers: [AXPEntityListTableService, AXPEntityListToolbarService],
4781
- imports: [CommonModule, AXDecoratorModule, AXPLayoutBuilderModule, AXButtonModule, AXDropdownModule],
4782
- }]
4783
- }] });
4784
-
4785
- var entityListWidgetView_component = /*#__PURE__*/Object.freeze({
4786
- __proto__: null,
4787
- AXPEntityListWidgetViewComponent: AXPEntityListWidgetViewComponent
4788
- });
4789
2920
 
4790
- const AXPEntityListWidget = {
4791
- name: 'entity-list',
4792
- title: 'Entity List',
4793
- description: 'Displays entity data in a table format',
4794
- type: 'view',
4795
- categories: [],
4796
- groups: [AXPWidgetGroupEnum.EntityWidget],
4797
- icon: 'fa-solid fa-square',
4798
- properties: [AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY],
4799
- components: {
4800
- view: {
4801
- component: () => Promise.resolve().then(function () { return entityListWidgetView_component; }).then((c) => c.AXPEntityListWidgetViewComponent),
4802
- },
4803
- edit: {
4804
- component: () => Promise.resolve().then(function () { return entityListWidgetView_component; }).then((c) => c.AXPEntityListWidgetViewComponent),
4805
- },
4806
- print: {
4807
- component: () => Promise.resolve().then(function () { return entityListWidgetView_component; }).then((c) => c.AXPEntityListWidgetViewComponent),
4808
- },
4809
- designer: {
4810
- component: () => Promise.resolve().then(function () { return entityListWidgetView_component; }).then((c) => c.AXPEntityListWidgetViewComponent),
4811
- },
4812
- },
4813
- };
2921
+ // Core middleware types and utilities
4814
2922
 
4815
- class AXPEntityReferenceWidgetViewComponent extends AXPLayoutBaseWidgetComponent {
4816
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4817
- 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 }); }
2923
+ class AXPEntityCommandSearchDefinitionProvider {
2924
+ async provide(context) {
2925
+ context.addDefinition('command', 'Commands', 'command', 'fa-solid fa-command', 1, {
2926
+ format: {
2927
+ id: '{{id}}',
2928
+ },
2929
+ actions: [
2930
+ {
2931
+ name: 'open-entity',
2932
+ type: 'view',
2933
+ priority: 'primary',
2934
+ },
2935
+ ],
2936
+ });
2937
+ }
4818
2938
  }
4819
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetViewComponent, decorators: [{
4820
- type: Component,
4821
- args: [{
4822
- template: ``,
4823
- standalone: true,
4824
- changeDetection: ChangeDetectionStrategy.OnPush,
4825
- imports: [CommonModule],
4826
- }]
4827
- }] });
4828
-
4829
- var entityReferenceWidgetView_component = /*#__PURE__*/Object.freeze({
4830
- __proto__: null,
4831
- AXPEntityReferenceWidgetViewComponent: AXPEntityReferenceWidgetViewComponent
4832
- });
4833
2939
 
4834
- class AXPEntityReferenceWidgetEditComponent extends AXPLayoutBaseWidgetComponent {
2940
+ class AXPEntitySearchDefinitionProvider {
4835
2941
  constructor() {
4836
- super(...arguments);
4837
- this.injector = inject(Injector);
4838
- this.entityResolver = inject(AXPEntityResolver);
4839
- this.entity = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entity" }] : []));
4840
- this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : []));
4841
- this.#efEntity = effect(async () => {
4842
- const [module, entity] = this.entity().split('.');
4843
- this.entityDef.set(await this.entityResolver.get(module, entity));
4844
- console.log(this.entityDef());
4845
- }, ...(ngDevMode ? [{ debugName: "#efEntity" }] : []));
2942
+ this.entityRegister = inject(AXPEntityDefinitionRegistryService);
2943
+ }
2944
+ async provide(context) {
2945
+ console.log("AXPEntitySearchDefinitionProvider", this.entityRegister.getAll());
2946
+ this.entityRegister.getAll().forEach((entity) => {
2947
+ context.addDefinition(`Module.${entity.module}.${entity.name}`, entity.formats.searchResult?.description ?? entity.module, `Module.${entity.module}`, 'fa-solid fa-objects-column', 4, {
2948
+ actions: [
2949
+ {
2950
+ name: 'open-entity',
2951
+ type: 'view',
2952
+ priority: 'primary',
2953
+ },
2954
+ ],
2955
+ format: {
2956
+ title: entity.formats.searchResult?.title,
2957
+ description: (entity.formats.searchResult?.description ?? entity.module) + ' / ' + entity.title,
2958
+ id: '{{data.id}}',
2959
+ },
2960
+ });
2961
+ });
4846
2962
  }
4847
- #efEntity;
4848
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4849
- 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 }); }
4850
- }
4851
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetEditComponent, decorators: [{
4852
- type: Component,
4853
- args: [{
4854
- template: ``,
4855
- standalone: true,
4856
- changeDetection: ChangeDetectionStrategy.OnPush,
4857
- imports: [CommonModule, FormsModule],
4858
- }]
4859
- }] });
4860
-
4861
- var entityReferenceWidgetEdit_component = /*#__PURE__*/Object.freeze({
4862
- __proto__: null,
4863
- AXPEntityReferenceWidgetEditComponent: AXPEntityReferenceWidgetEditComponent
4864
- });
4865
-
4866
- class AXPEntityReferenceWidgetColumnComponent extends AXPColumnWidgetComponent {
4867
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetColumnComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4868
- 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 }); }
4869
- }
4870
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetColumnComponent, decorators: [{
4871
- type: Component,
4872
- args: [{
4873
- template: `{{rawValue}}`,
4874
- standalone: true,
4875
- changeDetection: ChangeDetectionStrategy.OnPush,
4876
- imports: [CommonModule],
4877
- inputs: ['rawValue']
4878
- }]
4879
- }] });
4880
-
4881
- var entityReferenceWidgetColumn_component = /*#__PURE__*/Object.freeze({
4882
- __proto__: null,
4883
- AXPEntityReferenceWidgetColumnComponent: AXPEntityReferenceWidgetColumnComponent
4884
- });
4885
-
4886
- class AXPEntityReferenceWidgetPrintComponent extends AXPLayoutBaseWidgetComponent {
4887
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetPrintComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4888
- 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 }); }
4889
- }
4890
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetPrintComponent, decorators: [{
4891
- type: Component,
4892
- args: [{
4893
- template: ``,
4894
- standalone: true,
4895
- changeDetection: ChangeDetectionStrategy.OnPush,
4896
- imports: [CommonModule],
4897
- inputs: [],
4898
- }]
4899
- }] });
4900
-
4901
- var entityReferenceWidgetPrint_component = /*#__PURE__*/Object.freeze({
4902
- __proto__: null,
4903
- AXPEntityReferenceWidgetPrintComponent: AXPEntityReferenceWidgetPrintComponent
4904
- });
4905
-
4906
- class AXPEntityReferenceWidgetDesignerComponent extends AXPLayoutBaseWidgetComponent {
4907
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetDesignerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4908
- 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 }); }
4909
2963
  }
4910
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetDesignerComponent, decorators: [{
4911
- type: Component,
4912
- args: [{
4913
- template: ``,
4914
- standalone: true,
4915
- changeDetection: ChangeDetectionStrategy.OnPush,
4916
- imports: [CommonModule],
4917
- }]
4918
- }] });
4919
-
4920
- var entityReferenceWidgetDesigner_component = /*#__PURE__*/Object.freeze({
4921
- __proto__: null,
4922
- AXPEntityReferenceWidgetDesignerComponent: AXPEntityReferenceWidgetDesignerComponent
4923
- });
4924
-
4925
- const AXPEntityReferenceWidget = {
4926
- name: 'entity-reference',
4927
- title: 'Entity Reference',
4928
- description: '',
4929
- type: 'view',
4930
- categories: [],
4931
- groups: [AXPWidgetGroupEnum.EntityWidget],
4932
- icon: 'fa-solid fa-square',
4933
- properties: [AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY],
4934
- components: {
4935
- view: {
4936
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetView_component; }).then((c) => c.AXPEntityReferenceWidgetViewComponent),
4937
- },
4938
- edit: {
4939
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetEdit_component; }).then((c) => c.AXPEntityReferenceWidgetEditComponent),
4940
- },
4941
- column: {
4942
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetColumn_component; }).then((c) => c.AXPEntityReferenceWidgetColumnComponent),
4943
- },
4944
- print: {
4945
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetPrint_component; }).then((c) => c.AXPEntityReferenceWidgetPrintComponent),
4946
- },
4947
- designer: {
4948
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetDesigner_component; }).then((c) => c.AXPEntityReferenceWidgetDesignerComponent),
4949
- },
4950
- },
4951
- };
4952
2964
 
4953
2965
  class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
4954
2966
  constructor() {
@@ -5195,7 +3207,7 @@ class AXPLookupWidgetSelectorComponent extends AXBasePageComponent {
5195
3207
  }
5196
3208
  </ax-suffix>
5197
3209
  </ax-footer>
5198
- `, 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 }); }
3210
+ `, 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 }); }
5199
3211
  }
5200
3212
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLookupWidgetSelectorComponent, decorators: [{
5201
3213
  type: Component,
@@ -5295,7 +3307,6 @@ class AXPLookupWidgetSelectorViewModel {
5295
3307
  this.options = options;
5296
3308
  this.workflow = this.injector.get(AXPWorkflowService);
5297
3309
  this.filterOperatorMiddleware = this.injector.get(AXPFilterOperatorMiddlewareService);
5298
- this.widgetResolver = this.injector.get(AXPWidgetRegistryService);
5299
3310
  this.dataSource = new AXDataSource({
5300
3311
  byKey: (key) => {
5301
3312
  const func = this.entityDef.queries.byKey.execute;
@@ -5317,41 +3328,23 @@ class AXPLookupWidgetSelectorViewModel {
5317
3328
  }, ...(ngDevMode ? [{ debugName: "parentKey" }] : []));
5318
3329
  this.allowMultiple = computed(() => {
5319
3330
  return this.options.allowMultiple ?? false;
5320
- }, ...(ngDevMode ? [{ debugName: "allowMultiple" }] : []));
5321
- this.inlineFiltersPlaceholders = computed(() => {
5322
- return (this.entityDef?.properties.filter((p) => p.options?.filter?.inline?.enabled).map((c) => c.title ?? c.name) ?? []);
5323
- }, ...(ngDevMode ? [{ debugName: "inlineFiltersPlaceholders" }] : []));
5324
- this.hasInlineFilters = computed(() => {
5325
- return this.inlineFiltersPlaceholders().length > 0;
5326
- }, ...(ngDevMode ? [{ debugName: "hasInlineFilters" }] : []));
5327
- this.columns = () => {
5328
- const { columns = [], properties } = this.entityDef;
5329
- const visibleProperties = properties.filter(({ schema }) => !schema?.hidden);
5330
- const visiblePropNames = new Set(visibleProperties.map(({ name }) => name));
5331
- return columns
5332
- .filter(({ name, showAs }) => visiblePropNames.has(name) || showAs)
5333
- .filter(({ name }) => ((this.options.columns?.length ?? 0) == 0) || this.options.columns?.includes(name))
5334
- .map((column) => {
5335
- if (column.showAs) {
5336
- const widgetConfig = this.widgetResolver.resolve(column.showAs.type);
5337
- const property = {
5338
- ...widgetConfig,
5339
- name: column.name,
5340
- title: column.title ?? '',
5341
- schema: {
5342
- dataType: 'string',
5343
- interface: {
5344
- type: column.showAs.type,
5345
- options: column.showAs.options,
5346
- },
5347
- },
5348
- };
5349
- return new AXPEntityListViewColumnViewModel(property, column);
5350
- }
5351
- else {
5352
- const property = visibleProperties.find(({ name }) => name === column.name);
5353
- return new AXPEntityListViewColumnViewModel(property, column);
5354
- }
3331
+ }, ...(ngDevMode ? [{ debugName: "allowMultiple" }] : []));
3332
+ this.inlineFiltersPlaceholders = computed(() => {
3333
+ return (this.entityDef?.properties.filter((p) => p.options?.filter?.inline?.enabled).map((c) => c.title ?? c.name) ?? []);
3334
+ }, ...(ngDevMode ? [{ debugName: "inlineFiltersPlaceholders" }] : []));
3335
+ this.hasInlineFilters = computed(() => {
3336
+ return this.inlineFiltersPlaceholders().length > 0;
3337
+ }, ...(ngDevMode ? [{ debugName: "hasInlineFilters" }] : []));
3338
+ this.columns = () => {
3339
+ const listColumns = this.entityDef.columns ?? [];
3340
+ const columns = listColumns?.map((c) => c.name) ?? [];
3341
+ const props = this.entityDef.properties.filter((p) => p.schema.hidden != true);
3342
+ const displayColumns = props.filter((p) => (this.options.columns?.length ?? 0) > 0
3343
+ ? this.options.columns.some((c) => c == p.name)
3344
+ : columns.some((c) => c == p.name));
3345
+ //
3346
+ return displayColumns.map((p) => {
3347
+ return new AXPEntityListViewColumnViewModel(p, listColumns?.find((c) => c.name == p.name));
5355
3348
  });
5356
3349
  };
5357
3350
  this.inlineFilters = {
@@ -5460,24 +3453,12 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
5460
3453
  this.entity = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entity" }] : []));
5461
3454
  this.disabled = computed(() => this.options()['disabled'], ...(ngDevMode ? [{ debugName: "disabled" }] : []));
5462
3455
  this.columns = computed(() => this.options()['columns'] ?? [], ...(ngDevMode ? [{ debugName: "columns" }] : []));
5463
- this.textField = computed(() => this.options()['textField'] ?? '', ...(ngDevMode ? [{ debugName: "textField" }] : []));
5464
3456
  this.customFilter = computed(() => this.options()['filter'], ...(ngDevMode ? [{ debugName: "customFilter" }] : []));
5465
3457
  this.multiple = computed(() => (this.options()['multiple'] ?? false), ...(ngDevMode ? [{ debugName: "multiple" }] : []));
5466
3458
  this.look = computed(() => this.options()['look'] ?? 'lookup', ...(ngDevMode ? [{ debugName: "look" }] : []));
5467
- this.allowClear = computed(() => (this.options()['allowClear'] ?? false), ...(ngDevMode ? [{ debugName: "allowClear" }] : []));
5468
- this.defaultTextField = computed(() => {
5469
- const textField = this.entityDef()?.formats.lookup ?? this.entityDef()?.properties.find((c) => c.name != 'id')?.name ?? 'title';
5470
- return textField;
5471
- }, ...(ngDevMode ? [{ debugName: "defaultTextField" }] : []));
5472
- this.displayField = computed(() => {
5473
- if (this.textField()) {
5474
- return this.textField();
5475
- }
5476
- return this.defaultTextField();
5477
- }, ...(ngDevMode ? [{ debugName: "displayField" }] : []));
5478
- this.selectedItemsText = computed(() => {
5479
- return this.selectedItems().map((item) => get(item, this.displayField())).join(', ');
5480
- }, ...(ngDevMode ? [{ debugName: "selectedItemsText" }] : []));
3459
+ this.textField = computed(() => {
3460
+ return (this.entityDef()?.formats.lookup ?? this.entityDef()?.properties.find((c) => c.name != 'id')?.name ?? 'title');
3461
+ }, ...(ngDevMode ? [{ debugName: "textField" }] : []));
5481
3462
  this.valueField = computed(() => this.entityDef()?.properties.find((c) => c.name == 'id')?.name ?? 'id', ...(ngDevMode ? [{ debugName: "valueField" }] : []));
5482
3463
  this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : []));
5483
3464
  this.searchTerm = signal(null, ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
@@ -5542,11 +3523,11 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
5542
3523
  }
5543
3524
  showSelector() {
5544
3525
  this.isOpen.set(true);
5545
- const columnsCount = this.columns().length > 0 ? this.columns().length : (this.vm()?.columns().length ?? 0);
3526
+ const columnsCount = this.columns().length > 0 ? this.columns().length : this.vm()?.columns().length ?? 0;
5546
3527
  this.popupService
5547
3528
  .open(AXPLookupWidgetSelectorComponent, {
5548
3529
  title: `${this.translateService.translateSync('widget.lookup.search')} ${this.translateService.translateSync(this.entityDef()?.formats.plural ?? '')}`,
5549
- size: columnsCount < 3 ? 'md' : 'lg',
3530
+ size: columnsCount < 4 ? 'md' : 'lg',
5550
3531
  data: {
5551
3532
  vm: new AXPLookupWidgetSelectorViewModel(this.injector, this.entityDef(), {
5552
3533
  customFilter: this.customFilter(),
@@ -5617,7 +3598,6 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
5617
3598
  this.selectedItems.set(items);
5618
3599
  //
5619
3600
  const keys = items.map((item) => get(item, this.valueField()));
5620
- const text = items.map((item) => get(item, this.displayField()));
5621
3601
  //
5622
3602
  // extract data from valueField and set context by expose path
5623
3603
  if (this.expose()) {
@@ -5669,132 +3649,110 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
5669
3649
  }
5670
3650
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLookupWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5671
3651
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: AXPLookupWidgetEditComponent, isStandalone: true, selector: "axp-lookup-widget-edit", viewQueries: [{ propertyName: "textbox", first: true, predicate: AXTagBoxComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
5672
- @if(vm()) {
5673
3652
  @if (look() == 'select') {
5674
3653
  <ax-select-box
5675
3654
  [dataSource]="vm()?.dataSource!"
5676
3655
  [ngModel]="selectedItems()"
5677
- [textField]="displayField()"
3656
+ [textField]="textField()"
5678
3657
  [valueField]="valueField()"
5679
3658
  [disabled]="disabled()"
5680
3659
  [multiple]="multiple()"
5681
3660
  (onValueChanged)="selectBoxValueChange($event)"
5682
3661
  >
5683
- <ax-search-box>
5684
- <ax-clear-button></ax-clear-button>
5685
- </ax-search-box>
5686
- @if (allowClear()) {
5687
- <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5688
- }
5689
- </ax-select-box>
3662
+ <ax-search-box>
3663
+ </ax-search-box>
3664
+ </ax-select-box>
5690
3665
  } @else {
5691
- <ax-tag-box
5692
- [ngModel]="selectedItems()"
5693
- [textField]="displayField()"
5694
- [valueField]="valueField()"
5695
- (onValueChanged)="handleValueChange($event)"
5696
- [placeholder]="placeholder() | translate | async"
5697
- [addOnEnter]="false"
5698
- [addOnComma]="false"
5699
- [disabled]="disabled()"
5700
- (onKeyUp)="handleKeyUp($event)"
5701
- (onBlur)="handleOnBlur($event)"
5702
- >
5703
- @for (validation of validationRules(); track $index) {
5704
- <ax-validation-rule
5705
- [rule]="validation.rule"
5706
- [message]="validation.options?.message"
5707
- [options]="validation.options"
5708
- ></ax-validation-rule>
5709
- }
5710
- @if (selectedItems().length > 1 || allowClear()) {
5711
- <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5712
- }
3666
+ <ax-tag-box
3667
+ [ngModel]="selectedItems()"
3668
+ [textField]="textField()"
3669
+ [valueField]="valueField()"
3670
+ (onValueChanged)="handleValueChange($event)"
3671
+ [placeholder]="placeholder() | translate | async"
3672
+ [addOnEnter]="false"
3673
+ [addOnComma]="false"
3674
+ [disabled]="disabled()"
3675
+ (onKeyUp)="handleKeyUp($event)"
3676
+ (onBlur)="handleOnBlur($event)"
3677
+ >
3678
+ @for (validation of validationRules(); track $index) {
3679
+ <ax-validation-rule
3680
+ [rule]="validation.rule"
3681
+ [message]="validation.options?.message"
3682
+ [options]="validation.options"
3683
+ ></ax-validation-rule>
3684
+ }
3685
+ @if (selectedItems().length > 1) {
3686
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
3687
+ }
5713
3688
 
5714
- <ax-suffix>
5715
- <ax-button
5716
- color="ghost"
5717
- look="blank"
5718
- [disabled]="isLoading() || disabled()"
5719
- (onClick)="handleOnClick($event)"
5720
- >
5721
- @if (isLoading()) {
5722
- <ax-loading></ax-loading>
5723
- } @else {
5724
- <ax-icon icon="far fa-search"> </ax-icon>
5725
- }
5726
- </ax-button>
5727
- </ax-suffix>
5728
- </ax-tag-box>
5729
- }
3689
+ <ax-suffix>
3690
+ <ax-button color="ghost" look="blank" [disabled]="isLoading() || disabled()" (onClick)="handleOnClick($event)">
3691
+ @if (isLoading()) {
3692
+ <ax-loading></ax-loading>
3693
+ } @else {
3694
+ <ax-icon icon="far fa-search"> </ax-icon>
3695
+ }
3696
+ </ax-button>
3697
+ </ax-suffix>
3698
+ </ax-tag-box>
5730
3699
  }
5731
3700
  `, 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:
5732
3701
  //
5733
- 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", "onItemSelected", "onItemClick"] }, { 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 }); }
3702
+ 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 }); }
5734
3703
  }
5735
3704
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLookupWidgetEditComponent, decorators: [{
5736
3705
  type: Component,
5737
3706
  args: [{
5738
3707
  selector: 'axp-lookup-widget-edit',
5739
3708
  template: `
5740
- @if(vm()) {
5741
3709
  @if (look() == 'select') {
5742
3710
  <ax-select-box
5743
3711
  [dataSource]="vm()?.dataSource!"
5744
3712
  [ngModel]="selectedItems()"
5745
- [textField]="displayField()"
3713
+ [textField]="textField()"
5746
3714
  [valueField]="valueField()"
5747
3715
  [disabled]="disabled()"
5748
3716
  [multiple]="multiple()"
5749
3717
  (onValueChanged)="selectBoxValueChange($event)"
5750
3718
  >
5751
- <ax-search-box>
5752
- <ax-clear-button></ax-clear-button>
5753
- </ax-search-box>
5754
- @if (allowClear()) {
5755
- <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5756
- }
5757
- </ax-select-box>
3719
+ <ax-search-box>
3720
+ </ax-search-box>
3721
+ </ax-select-box>
5758
3722
  } @else {
5759
- <ax-tag-box
5760
- [ngModel]="selectedItems()"
5761
- [textField]="displayField()"
5762
- [valueField]="valueField()"
5763
- (onValueChanged)="handleValueChange($event)"
5764
- [placeholder]="placeholder() | translate | async"
5765
- [addOnEnter]="false"
5766
- [addOnComma]="false"
5767
- [disabled]="disabled()"
5768
- (onKeyUp)="handleKeyUp($event)"
5769
- (onBlur)="handleOnBlur($event)"
5770
- >
5771
- @for (validation of validationRules(); track $index) {
5772
- <ax-validation-rule
5773
- [rule]="validation.rule"
5774
- [message]="validation.options?.message"
5775
- [options]="validation.options"
5776
- ></ax-validation-rule>
5777
- }
5778
- @if (selectedItems().length > 1 || allowClear()) {
5779
- <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5780
- }
3723
+ <ax-tag-box
3724
+ [ngModel]="selectedItems()"
3725
+ [textField]="textField()"
3726
+ [valueField]="valueField()"
3727
+ (onValueChanged)="handleValueChange($event)"
3728
+ [placeholder]="placeholder() | translate | async"
3729
+ [addOnEnter]="false"
3730
+ [addOnComma]="false"
3731
+ [disabled]="disabled()"
3732
+ (onKeyUp)="handleKeyUp($event)"
3733
+ (onBlur)="handleOnBlur($event)"
3734
+ >
3735
+ @for (validation of validationRules(); track $index) {
3736
+ <ax-validation-rule
3737
+ [rule]="validation.rule"
3738
+ [message]="validation.options?.message"
3739
+ [options]="validation.options"
3740
+ ></ax-validation-rule>
3741
+ }
3742
+ @if (selectedItems().length > 1) {
3743
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
3744
+ }
5781
3745
 
5782
- <ax-suffix>
5783
- <ax-button
5784
- color="ghost"
5785
- look="blank"
5786
- [disabled]="isLoading() || disabled()"
5787
- (onClick)="handleOnClick($event)"
5788
- >
5789
- @if (isLoading()) {
5790
- <ax-loading></ax-loading>
5791
- } @else {
5792
- <ax-icon icon="far fa-search"> </ax-icon>
5793
- }
5794
- </ax-button>
5795
- </ax-suffix>
5796
- </ax-tag-box>
5797
- }
3746
+ <ax-suffix>
3747
+ <ax-button color="ghost" look="blank" [disabled]="isLoading() || disabled()" (onClick)="handleOnClick($event)">
3748
+ @if (isLoading()) {
3749
+ <ax-loading></ax-loading>
3750
+ } @else {
3751
+ <ax-icon icon="far fa-search"> </ax-icon>
3752
+ }
3753
+ </ax-button>
3754
+ </ax-suffix>
3755
+ </ax-tag-box>
5798
3756
  }
5799
3757
  `,
5800
3758
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -5810,7 +3768,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
5810
3768
  AXTagBoxModule,
5811
3769
  AXTranslationModule,
5812
3770
  AXSelectBoxModule,
5813
- AXSearchBoxComponent,
3771
+ AXSearchBoxComponent
5814
3772
  ],
5815
3773
  }]
5816
3774
  }] });
@@ -5889,7 +3847,6 @@ const AXPLookupWidget = {
5889
3847
  type: 'editor',
5890
3848
  properties: [
5891
3849
  AXP_DISABLED_PROPERTY,
5892
- AXP_ALLOW_CLEAR_PROPERTY,
5893
3850
  AXP_DATA_PATH_PROPERTY,
5894
3851
  {
5895
3852
  name: 'expose',
@@ -6073,7 +4030,7 @@ class AXPTagableBoxWidgetEditComponent extends AXPValueWidgetComponent {
6073
4030
  </ax-prefix>
6074
4031
  </ax-button>
6075
4032
  </div>
6076
- `, 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", "onItemSelected", "onItemClick"] }, { 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 }); }
4033
+ `, 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 }); }
6077
4034
  }
6078
4035
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPTagableBoxWidgetEditComponent, decorators: [{
6079
4036
  type: Component,
@@ -6281,7 +4238,6 @@ const AXPTagableBoxWidget = {
6281
4238
  description: 'Inputs text with tags',
6282
4239
  categories: AXP_WIDGETS_EDITOR_CATEGORY,
6283
4240
  type: 'editor',
6284
- groups: [AXPWidgetGroupEnum.EntityWidget],
6285
4241
  defaultFilterWidgetName: 'string-filter',
6286
4242
  properties: [AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY],
6287
4243
  components: {
@@ -6370,7 +4326,7 @@ class AXPWidgetSelectorWidgetEditComponent extends AXPValueWidgetComponent {
6370
4326
  <axp-widget-property-viewer [widget]="selectedWidgetNode()!" (onChanged)="handleChangeWidget($event)">
6371
4327
  </axp-widget-property-viewer>
6372
4328
  }
6373
- `, 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 }); }
4329
+ `, 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 }); }
6374
4330
  }
6375
4331
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPWidgetSelectorWidgetEditComponent, decorators: [{
6376
4332
  type: Component,
@@ -6678,10 +4634,10 @@ class AXPShowDetailViewAction extends AXPWorkflowAction {
6678
4634
  this.sessionService = inject(AXPSessionService);
6679
4635
  }
6680
4636
  async execute(context) {
6681
- const [module, entity] = context.getVariable('entity').split('.');
4637
+ const [module, entity] = context.getVariable('entity').split(".");
6682
4638
  const { id } = context.getVariable('data');
6683
4639
  const newPayload = {
6684
- commands: `/${this.sessionService.application?.name}/m/${module}/e/${entity}/${id}/new-view`,
4640
+ commands: `/${this.sessionService.application?.name}/m/${module}/e/${entity}/${id}/view`,
6685
4641
  };
6686
4642
  context.setVariable('payload', newPayload);
6687
4643
  this.navigation.execute(context);
@@ -6723,7 +4679,6 @@ class AXPShowFileUploaderPopupAction extends AXPWorkflowAction {
6723
4679
  multiple: multiple,
6724
4680
  accept: accept,
6725
4681
  fileEditable: fileEditable,
6726
- // maxFileSize: maxFileSize,
6727
4682
  });
6728
4683
  // Handle case when result is undefined or empty array
6729
4684
  if (!res || res.length === 0) {
@@ -6813,56 +4768,146 @@ const AXPShowListViewWorkflow = {
6813
4768
  },
6814
4769
  };
6815
4770
 
6816
- /**
6817
- * Default widths for common text columns
6818
- */
6819
- const DEFAULT_COLUMN_WIDTHS = {
6820
- title: '250px',
6821
- description: '500px',
6822
- note: '350px',
6823
- notes: '350px',
6824
- content: '500px'
6825
- };
6826
- /**
6827
- * Factory to create a column width middleware using provided config map.
6828
- * Sets width for columns defined in the map if not already defined on the column.
6829
- */
6830
- const columnWidthMiddlewareFactory = (widths) => {
6831
- return (context) => {
6832
- const columns = context.columns.list();
6833
- if (!columns) {
6834
- return;
6835
- }
6836
- columns.forEach((column) => {
6837
- const desiredWidth = widths[column.name];
6838
- if (desiredWidth && !column.options?.width) {
6839
- const normalizedWidth = typeof desiredWidth === 'number' ? `${desiredWidth}px` : desiredWidth;
6840
- context.columns.find(column.name).update((col) => ({
6841
- ...col,
6842
- options: {
6843
- ...col.options,
6844
- width: normalizedWidth
6845
- }
6846
- }));
6847
- }
6848
- });
6849
- };
6850
- };
6851
- //#endregion
6852
- //#region ---- Provider Registration ----
6853
- /**
6854
- * Helper to create a provider for the column width middleware.
6855
- * By default it applies to all entities using the '*' pattern.
6856
- */
6857
- const createColumnWidthMiddlewareProvider = (widths, entityName = '*') => ({
6858
- entityName,
6859
- modifier: columnWidthMiddlewareFactory(widths)
4771
+ class AXPEntityReferenceWidgetViewComponent extends AXPLayoutWidgetComponent {
4772
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4773
+ 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 }); }
4774
+ }
4775
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetViewComponent, decorators: [{
4776
+ type: Component,
4777
+ args: [{
4778
+ template: ``,
4779
+ standalone: true,
4780
+ changeDetection: ChangeDetectionStrategy.OnPush,
4781
+ imports: [CommonModule]
4782
+ }]
4783
+ }] });
4784
+
4785
+ var entityReferenceWidgetView_component = /*#__PURE__*/Object.freeze({
4786
+ __proto__: null,
4787
+ AXPEntityReferenceWidgetViewComponent: AXPEntityReferenceWidgetViewComponent
6860
4788
  });
6861
- /**
6862
- * Default provider registered with the default map.
6863
- */
6864
- const columnWidthMiddlewareProvider = createColumnWidthMiddlewareProvider(DEFAULT_COLUMN_WIDTHS);
6865
- //#endregion
4789
+
4790
+ class AXPEntityReferenceWidgetEditComponent extends AXPLayoutWidgetComponent {
4791
+ constructor() {
4792
+ super(...arguments);
4793
+ this.injector = inject(Injector);
4794
+ this.entityResolver = inject(AXPEntityResolver);
4795
+ this.entity = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entity" }] : []));
4796
+ this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : []));
4797
+ this.#efEntity = effect(async () => {
4798
+ const [module, entity] = this.entity().split('.');
4799
+ this.entityDef.set(await this.entityResolver.get(module, entity));
4800
+ console.log(this.entityDef());
4801
+ }, ...(ngDevMode ? [{ debugName: "#efEntity" }] : []));
4802
+ }
4803
+ #efEntity;
4804
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4805
+ 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 }); }
4806
+ }
4807
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetEditComponent, decorators: [{
4808
+ type: Component,
4809
+ args: [{
4810
+ template: ``,
4811
+ standalone: true,
4812
+ changeDetection: ChangeDetectionStrategy.OnPush,
4813
+ imports: [CommonModule, FormsModule],
4814
+ }]
4815
+ }] });
4816
+
4817
+ var entityReferenceWidgetEdit_component = /*#__PURE__*/Object.freeze({
4818
+ __proto__: null,
4819
+ AXPEntityReferenceWidgetEditComponent: AXPEntityReferenceWidgetEditComponent
4820
+ });
4821
+
4822
+ class AXPEntityReferenceWidgetColumnComponent extends AXPColumnWidgetComponent {
4823
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetColumnComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4824
+ 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 }); }
4825
+ }
4826
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetColumnComponent, decorators: [{
4827
+ type: Component,
4828
+ args: [{
4829
+ template: `{{rawValue}}`,
4830
+ standalone: true,
4831
+ changeDetection: ChangeDetectionStrategy.OnPush,
4832
+ imports: [CommonModule],
4833
+ inputs: ['rawValue']
4834
+ }]
4835
+ }] });
4836
+
4837
+ var entityReferenceWidgetColumn_component = /*#__PURE__*/Object.freeze({
4838
+ __proto__: null,
4839
+ AXPEntityReferenceWidgetColumnComponent: AXPEntityReferenceWidgetColumnComponent
4840
+ });
4841
+
4842
+ class AXPEntityReferenceWidgetPrintComponent extends AXPLayoutWidgetComponent {
4843
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetPrintComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4844
+ 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 }); }
4845
+ }
4846
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetPrintComponent, decorators: [{
4847
+ type: Component,
4848
+ args: [{
4849
+ template: ``,
4850
+ standalone: true,
4851
+ changeDetection: ChangeDetectionStrategy.OnPush,
4852
+ imports: [CommonModule],
4853
+ inputs: []
4854
+ }]
4855
+ }] });
4856
+
4857
+ var entityReferenceWidgetPrint_component = /*#__PURE__*/Object.freeze({
4858
+ __proto__: null,
4859
+ AXPEntityReferenceWidgetPrintComponent: AXPEntityReferenceWidgetPrintComponent
4860
+ });
4861
+
4862
+ class AXPEntityReferenceWidgetDesignerComponent extends AXPLayoutWidgetComponent {
4863
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetDesignerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4864
+ 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 }); }
4865
+ }
4866
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetDesignerComponent, decorators: [{
4867
+ type: Component,
4868
+ args: [{
4869
+ template: ``,
4870
+ standalone: true,
4871
+ changeDetection: ChangeDetectionStrategy.OnPush,
4872
+ imports: [CommonModule]
4873
+ }]
4874
+ }] });
4875
+
4876
+ var entityReferenceWidgetDesigner_component = /*#__PURE__*/Object.freeze({
4877
+ __proto__: null,
4878
+ AXPEntityReferenceWidgetDesignerComponent: AXPEntityReferenceWidgetDesignerComponent
4879
+ });
4880
+
4881
+ const AXPEntityReferenceWidget = {
4882
+ name: "entity-reference",
4883
+ title: "Entity Reference",
4884
+ description: '',
4885
+ type: 'view',
4886
+ categories: [],
4887
+ groups: [AXPWidgetGroupEnum.FormElement],
4888
+ icon: "fa-solid fa-square",
4889
+ properties: [
4890
+ AXP_NAME_PROPERTY,
4891
+ AXP_DATA_PATH_PROPERTY,
4892
+ ],
4893
+ components: {
4894
+ view: {
4895
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetView_component; }).then((c) => c.AXPEntityReferenceWidgetViewComponent),
4896
+ },
4897
+ edit: {
4898
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetEdit_component; }).then((c) => c.AXPEntityReferenceWidgetEditComponent),
4899
+ },
4900
+ column: {
4901
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetColumn_component; }).then((c) => c.AXPEntityReferenceWidgetColumnComponent),
4902
+ },
4903
+ print: {
4904
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetPrint_component; }).then((c) => c.AXPEntityReferenceWidgetPrintComponent),
4905
+ },
4906
+ designer: {
4907
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetDesigner_component; }).then((c) => c.AXPEntityReferenceWidgetDesignerComponent),
4908
+ },
4909
+ }
4910
+ };
6866
4911
 
6867
4912
  function routesFacory() {
6868
4913
  const config = inject(AXP_ENTITY_CONFIG_TOKEN);
@@ -6896,14 +4941,6 @@ function routesFacory() {
6896
4941
  },
6897
4942
  data: { reuse: false },
6898
4943
  },
6899
- {
6900
- path: 'e/:entity/:id/new-view',
6901
- resolve: { adapter: AXPLayoutDetailsViewRouteResolver },
6902
- loadComponent: () => {
6903
- return config.viewers.master.details();
6904
- },
6905
- data: { reuse: false },
6906
- },
6907
4944
  {
6908
4945
  path: 'e/:entity/:id',
6909
4946
  redirectTo: 'e/:entity/:id/view',
@@ -6935,7 +4972,7 @@ class AXPEntityModule {
6935
4972
  });
6936
4973
  }
6937
4974
  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 }); }
6938
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, imports: [RouterModule, i2$2.AXPWorkflowModule, i2.AXPLayoutBuilderModule] }); }
4975
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, imports: [RouterModule, i2$2.AXPWorkflowModule, i6.AXPLayoutBuilderModule] }); }
6939
4976
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, providers: [
6940
4977
  {
6941
4978
  provide: ROUTES,
@@ -6952,11 +4989,6 @@ class AXPEntityModule {
6952
4989
  useClass: AXPEntityCommandSearchDefinitionProvider,
6953
4990
  multi: true,
6954
4991
  },
6955
- {
6956
- provide: AXP_ENTITY_MODIFIER,
6957
- useValue: columnWidthMiddlewareProvider,
6958
- multi: true,
6959
- },
6960
4992
  ], imports: [RouterModule,
6961
4993
  AXPWorkflowModule.forChild({
6962
4994
  actions: {
@@ -6986,13 +5018,7 @@ class AXPEntityModule {
6986
5018
  functions: {},
6987
5019
  }),
6988
5020
  AXPLayoutBuilderModule.forChild({
6989
- widgets: [
6990
- AXPLookupWidget,
6991
- AXPWidgetSelectorWidget,
6992
- AXPTagableBoxWidget,
6993
- AXPEntityListWidget,
6994
- AXPEntityReferenceWidget,
6995
- ],
5021
+ widgets: [AXPLookupWidget, AXPWidgetSelectorWidget, AXPTagableBoxWidget, AXPEntityReferenceWidget],
6996
5022
  })] }); }
6997
5023
  }
6998
5024
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, decorators: [{
@@ -7028,13 +5054,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
7028
5054
  functions: {},
7029
5055
  }),
7030
5056
  AXPLayoutBuilderModule.forChild({
7031
- widgets: [
7032
- AXPLookupWidget,
7033
- AXPWidgetSelectorWidget,
7034
- AXPTagableBoxWidget,
7035
- AXPEntityListWidget,
7036
- AXPEntityReferenceWidget,
7037
- ],
5057
+ widgets: [AXPLookupWidget, AXPWidgetSelectorWidget, AXPTagableBoxWidget, AXPEntityReferenceWidget],
7038
5058
  }),
7039
5059
  ],
7040
5060
  exports: [],
@@ -7055,11 +5075,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
7055
5075
  useClass: AXPEntityCommandSearchDefinitionProvider,
7056
5076
  multi: true,
7057
5077
  },
7058
- {
7059
- provide: AXP_ENTITY_MODIFIER,
7060
- useValue: columnWidthMiddlewareProvider,
7061
- multi: true,
7062
- },
7063
5078
  ],
7064
5079
  }]
7065
5080
  }], ctorParameters: () => [{ type: i1$4.AXPAppStartUpService }, { type: i0.Injector }] });
@@ -7090,7 +5105,6 @@ function entityMasterViewAction() {
7090
5105
  priority: 'secondary',
7091
5106
  type: 'view',
7092
5107
  scope: AXPEntityCommandScope.Individual,
7093
- default: true,
7094
5108
  };
7095
5109
  }
7096
5110
  function entityMasterDeleteAction() {
@@ -7111,7 +5125,9 @@ function entityMasterCrudActions() {
7111
5125
  ];
7112
5126
  }
7113
5127
  function entityMasterRecordActions() {
7114
- return [entityMasterDeleteAction()];
5128
+ return [
5129
+ entityMasterDeleteAction(),
5130
+ ];
7115
5131
  }
7116
5132
  // #endregion
7117
5133
  // #region Details
@@ -7142,9 +5158,8 @@ function entityDetailsSimpleCondition(fk) {
7142
5158
  value: '{{context.eval("id")}}',
7143
5159
  };
7144
5160
  }
7145
- function entityDetailsReferenceCondition(type) {
7146
- return [
7147
- {
5161
+ function entityDetailsReferenceCondition() {
5162
+ return [{
7148
5163
  name: 'reference.id',
7149
5164
  operator: { type: 'equal' },
7150
5165
  value: '{{context.eval("id")}}',
@@ -7152,8 +5167,8 @@ function entityDetailsReferenceCondition(type) {
7152
5167
  {
7153
5168
  name: 'reference.type',
7154
5169
  operator: { type: 'equal' },
7155
- value: type,
7156
- },
5170
+ value: '{{context.eval("entityName")}}',
5171
+ }
7157
5172
  ];
7158
5173
  }
7159
5174
  function entityDetailsEditAction() {
@@ -7162,7 +5177,6 @@ function entityDetailsEditAction() {
7162
5177
  command: 'quick-modify-entity',
7163
5178
  priority: 'secondary',
7164
5179
  type: 'update',
7165
- default: true,
7166
5180
  scope: AXPEntityCommandScope.Individual,
7167
5181
  };
7168
5182
  }
@@ -7177,9 +5191,13 @@ function entityOverrideDetailsViewAction() {
7177
5191
  };
7178
5192
  }
7179
5193
  function entityDetailsCrudActions(parentId) {
7180
- return [entityDetailsCreateActions(parentId), entityDetailsEditAction(), entityOverrideDetailsViewAction()];
5194
+ return [
5195
+ entityDetailsCreateActions(parentId),
5196
+ entityDetailsEditAction(),
5197
+ entityOverrideDetailsViewAction(),
5198
+ ];
7181
5199
  }
7182
- function entityDetailsReferenceCreateActions(type) {
5200
+ function entityDetailsReferenceCreateActions() {
7183
5201
  return [
7184
5202
  {
7185
5203
  title: '@general:actions.create.title',
@@ -7190,10 +5208,10 @@ function entityDetailsReferenceCreateActions(type) {
7190
5208
  redirect: false,
7191
5209
  canCreateNewOne: true,
7192
5210
  data: {
7193
- reference: {
7194
- id: '{{context.eval("id")}}',
7195
- type: type,
7196
- },
5211
+ 'reference': {
5212
+ 'id': '{{context.eval("id")}}',
5213
+ 'type': '{{context.eval("entityName")}}'
5214
+ }
7197
5215
  },
7198
5216
  },
7199
5217
  },
@@ -7206,65 +5224,11 @@ function entityDetailsReferenceCreateActions(type) {
7206
5224
  entityOverrideDetailsViewAction(),
7207
5225
  ];
7208
5226
  }
7209
- /**
7210
- * Computes a diff between two plain objects with array-aware semantics.
7211
- * - For arrays of objects with an id field, computes added/removed by id.
7212
- * - For arrays of primitives or objects without id, uses deep equality.
7213
- * - For scalars/objects, reports oldValue/newValue when changed.
7214
- */
7215
- function detectEntityChanges(oldObj, newObj) {
7216
- return transform(newObj, (result, value, key) => {
7217
- if (!isEqual(value, oldObj[key])) {
7218
- const oldValue = oldObj[key];
7219
- if (Array.isArray(value) || Array.isArray(oldValue)) {
7220
- const oldArray = Array.isArray(oldValue) ? oldValue : [];
7221
- const newArray = Array.isArray(value) ? value : [];
7222
- const hasId = newArray.length > 0 && typeof newArray[0] === 'object' && newArray[0] !== null && 'id' in newArray[0];
7223
- if (hasId) {
7224
- const added = newArray.filter((item) => !oldArray.some((oldItem) => oldItem.id === item.id));
7225
- const removed = oldArray.filter((item) => !newArray.some((newItem) => newItem.id === item.id));
7226
- result[key] = { oldValue, newValue: value, added, removed };
7227
- }
7228
- else {
7229
- const added = newArray.filter((item) => !oldArray.some((oldItem) => isEqual(item, oldItem)));
7230
- const removed = oldArray.filter((item) => !newArray.some((newItem) => isEqual(item, newItem)));
7231
- result[key] = { oldValue, newValue: value, added, removed };
7232
- }
7233
- }
7234
- else {
7235
- result[key] = { oldValue, newValue: value };
7236
- }
7237
- }
7238
- }, {});
7239
- }
7240
- //#endregion
7241
-
7242
- const eventDispatchMiddleware = {
7243
- target: { ops: ['create', 'update', 'delete'], order: 90 },
7244
- execute: async (ctx, next) => {
7245
- const dispatcher = inject(AXPEntityEventDispatcherService);
7246
- await next();
7247
- if (ctx.op === 'create') {
7248
- const createdData = ctx.result ? { ...ctx.data, id: ctx.result } : ctx.data;
7249
- await dispatcher.dispatchInserted(ctx.entityName, { refType: ctx.entityName, data: createdData });
7250
- }
7251
- else if (ctx.op === 'update') {
7252
- await dispatcher.dispatchUpdated(ctx.entityName, {
7253
- refType: ctx.entityName,
7254
- data: ctx.result,
7255
- changes: ctx.locals.get('changes'),
7256
- });
7257
- }
7258
- else if (ctx.op === 'delete') {
7259
- // For delete, prefer previous entity if available
7260
- await dispatcher.dispatchDeleted(ctx.entityName, { refType: ctx.entityName, data: ctx.result ?? ctx.previous });
7261
- }
7262
- },
7263
- };
5227
+ // #endregion
7264
5228
 
7265
5229
  /**
7266
5230
  * Generated bundle index. Do not edit.
7267
5231
  */
7268
5232
 
7269
- 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 };
5233
+ 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 };
7270
5234
  //# sourceMappingURL=acorex-platform-layout-entity.mjs.map