@acorex/platform 20.2.4-next.0 → 20.2.4-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/common/index.d.ts +82 -1
  2. package/core/index.d.ts +24 -2
  3. package/fesm2022/acorex-platform-common.mjs +1 -1
  4. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-layout-builder.mjs +47 -5
  6. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-layout-components.mjs +943 -39
  8. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-layout-designer.mjs +15 -122
  10. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-layout-entity.mjs +1290 -564
  12. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  13. package/fesm2022/acorex-platform-layout-views.mjs +83 -40
  14. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  15. package/fesm2022/{acorex-platform-themes-default-entity-master-list-view.component-ezrf2oBR.mjs → acorex-platform-themes-default-entity-master-list-view.component-DXGLsVis.mjs} +174 -50
  16. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DXGLsVis.mjs.map +1 -0
  17. package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-D8r3S2lI.mjs → acorex-platform-themes-default-entity-master-single-view.component-CVaJzWb2.mjs} +14 -11
  18. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-CVaJzWb2.mjs.map +1 -0
  19. package/fesm2022/acorex-platform-themes-default.mjs +19 -7
  20. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  21. package/fesm2022/{acorex-platform-themes-shared-color-chooser-column.component-DjKLg513.mjs → acorex-platform-themes-shared-theme-color-chooser-column.component-DjKLg513.mjs} +1 -1
  22. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-DjKLg513.mjs.map +1 -0
  23. package/fesm2022/{acorex-platform-themes-shared-color-chooser-view.component-DE0wO98F.mjs → acorex-platform-themes-shared-theme-color-chooser-view.component-DE0wO98F.mjs} +1 -1
  24. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-DE0wO98F.mjs.map +1 -0
  25. package/fesm2022/acorex-platform-themes-shared.mjs +10 -12
  26. package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
  27. package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-edit.component-B3SJUnGQ.mjs +50 -0
  28. package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-edit.component-B3SJUnGQ.mjs.map +1 -0
  29. package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-view.component-BLR0JkRt.mjs +42 -0
  30. package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-view.component-BLR0JkRt.mjs.map +1 -0
  31. package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-edit.component-hzR2FgOm.mjs +55 -0
  32. package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-edit.component-hzR2FgOm.mjs.map +1 -0
  33. package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-view.component-IDm6Clua.mjs +50 -0
  34. package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-view.component-IDm6Clua.mjs.map +1 -0
  35. package/fesm2022/acorex-platform-widgets-extra-properties-widget-edit.component-BRO9tYDa.mjs +48 -0
  36. package/fesm2022/acorex-platform-widgets-extra-properties-widget-edit.component-BRO9tYDa.mjs.map +1 -0
  37. package/fesm2022/acorex-platform-widgets-extra-properties-widget-view.component-CkpLimyW.mjs +42 -0
  38. package/fesm2022/acorex-platform-widgets-extra-properties-widget-view.component-CkpLimyW.mjs.map +1 -0
  39. package/fesm2022/{acorex-platform-widgets-file-list-popup.component-DFbPO0ud.mjs → acorex-platform-widgets-file-list-popup.component-B601gPsW.mjs} +66 -3
  40. package/fesm2022/acorex-platform-widgets-file-list-popup.component-B601gPsW.mjs.map +1 -0
  41. package/fesm2022/acorex-platform-widgets.mjs +770 -118
  42. package/fesm2022/acorex-platform-widgets.mjs.map +1 -1
  43. package/fesm2022/acorex-platform-workflow.mjs +3 -0
  44. package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
  45. package/layout/builder/index.d.ts +12 -2
  46. package/layout/components/index.d.ts +172 -6
  47. package/layout/designer/index.d.ts +3 -46
  48. package/layout/entity/index.d.ts +70 -7
  49. package/layout/views/index.d.ts +25 -7
  50. package/package.json +1 -1
  51. package/themes/default/index.d.ts +4 -1
  52. package/widgets/index.d.ts +20 -11
  53. package/workflow/index.d.ts +3 -1
  54. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-ezrf2oBR.mjs.map +0 -1
  55. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-D8r3S2lI.mjs.map +0 -1
  56. package/fesm2022/acorex-platform-themes-shared-color-chooser-column.component-DjKLg513.mjs.map +0 -1
  57. package/fesm2022/acorex-platform-themes-shared-color-chooser-view.component-DE0wO98F.mjs.map +0 -1
  58. package/fesm2022/acorex-platform-widgets-file-list-popup.component-DFbPO0ud.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, Injectable, computed, signal, Injector, EnvironmentInjector, runInInjectionContext, viewChild, viewChildren, untracked, ChangeDetectionStrategy, Component, effect, HostBinding, ViewChild, NgModule } from '@angular/core';
2
+ import { InjectionToken, inject, Injectable, computed, signal, Injector, runInInjectionContext, EnvironmentInjector, viewChild, viewChildren, linkedSignal, effect, untracked, ChangeDetectionStrategy, Component, HostBinding, ViewChild, NgModule } from '@angular/core';
3
3
  import { castArray, get, cloneDeep, set, merge, isNil, isEmpty, sortBy } from 'lodash-es';
4
4
  import * as i1$2 from '@acorex/cdk/common';
5
5
  import { AXDataSource, AXCommonModule } from '@acorex/cdk/common';
@@ -10,10 +10,11 @@ import { AXPExpressionEvaluatorService, AXPPlatformScope, AXPDistributedEventLis
10
10
  import * as i2$2 from '@acorex/platform/workflow';
11
11
  import { AXPWorkflowService, ofType, createWorkFlowEvent, AXPWorkflowAction, AXPWorkflowModule } from '@acorex/platform/workflow';
12
12
  import * as i2 from '@acorex/platform/layout/builder';
13
- import { AXPPageStatus, AXPWidgetRegistryService, AXPWidgetsCatalog, AXPValueWidgetComponent, AXPWidgetRendererDirective, AXPLayoutBuilderModule, AXPWidgetGroupEnum, AXPLayoutWidgetComponent, AXPColumnWidgetComponent, AXP_WIDGETS_EDITOR_CATEGORY } from '@acorex/platform/layout/builder';
13
+ import { AXPPageStatus, AXPWidgetRegistryService, AXPWidgetsCatalog, AXPValueWidgetComponent, AXPWidgetContainerComponent, AXPWidgetRendererDirective, AXPLayoutBuilderModule, AXPWidgetGroupEnum, AXPLayoutWidgetComponent, AXPColumnWidgetComponent, AXP_WIDGETS_EDITOR_CATEGORY } from '@acorex/platform/layout/builder';
14
14
  import { AXPLayoutThemeService } from '@acorex/platform/themes/shared';
15
- import { AXPSessionService, AXPAuthGuard } from '@acorex/platform/auth';
16
15
  import { Subject, takeUntil } from 'rxjs';
16
+ import { AXPSessionService, AXPAuthGuard } from '@acorex/platform/auth';
17
+ import { AXPCommandService } from '@acorex/platform/runtime';
17
18
  import * as i8 from '@acorex/core/translation';
18
19
  import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
19
20
  import { AXDialogService } from '@acorex/components/dialog';
@@ -51,7 +52,7 @@ import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
51
52
  import { AXBasePageComponent } from '@acorex/components/page';
52
53
  import * as i2$1 from '@acorex/components/text-box';
53
54
  import { AXTextBoxModule, AXTextBoxComponent } from '@acorex/components/text-box';
54
- import { AXPWidgetPropertyViewerComponent } from '@acorex/platform/layout/designer';
55
+ import { AXPWidgetPropertyViewerComponent } from '@acorex/platform/layout/components';
55
56
  import { transform, isEqual } from 'lodash';
56
57
 
57
58
  const AXP_DATA_SEEDER_TOKEN = new InjectionToken('AXP_DATA_SEEDER_TOKEN');
@@ -224,7 +225,8 @@ class AXPEntityDetailListViewModel {
224
225
  return !usedOverrideActions.has(actionKey);
225
226
  })
226
227
  .map((action) => new AXPEntityCommandTriggerViewModel(this.detailEntity(), action));
227
- return [...additionalActions, ...mergedActions].filter((a) => !a.hidden);
228
+ // Do not filter by hidden here; hidden/disabled may be expressions that must be evaluated dynamically
229
+ return [...additionalActions, ...mergedActions];
228
230
  }, ...(ngDevMode ? [{ debugName: "allActions" }] : []));
229
231
  this.selectedScopeActionsCount = computed(() => {
230
232
  return this.allActions().filter((a) => a.scope == AXPEntityCommandScope.Selected).length;
@@ -370,6 +372,43 @@ class AXPEntityDetailListViewModel {
370
372
  options,
371
373
  });
372
374
  }
375
+ //#region ---- Evaluated Actions (Primary/Secondary) ----
376
+ /**
377
+ * Evaluate hidden/disabled expressions for primary actions and return the visible list.
378
+ */
379
+ async getPrimaryActions() {
380
+ const scope = {};
381
+ const actions = await Promise.all(this.allActions()
382
+ .filter((a) => a.priority == 'primary' &&
383
+ ((a.scope == AXPEntityCommandScope.Selected && this.hasSelectedItems()) ||
384
+ (a.scope == AXPEntityCommandScope.TypeLevel && !this.hasSelectedItems())))
385
+ .map(async (a) => {
386
+ const isHidden = await this.evaluateExpressions(a.hidden);
387
+ if (isHidden)
388
+ return null;
389
+ const disabled = await this.evaluateExpressions(a.disabled);
390
+ return { ...a, disabled };
391
+ }));
392
+ return actions.filter(Boolean);
393
+ }
394
+ /**
395
+ * Evaluate hidden/disabled expressions for secondary actions and return the visible list.
396
+ */
397
+ async getSecondaryActions() {
398
+ const scope = {};
399
+ const actions = await Promise.all(this.allActions()
400
+ .filter((a) => a.priority == 'secondary' &&
401
+ ((a.scope == AXPEntityCommandScope.Selected && this.hasSelectedItems()) ||
402
+ (a.scope == AXPEntityCommandScope.TypeLevel && !this.hasSelectedItems())))
403
+ .map(async (a) => {
404
+ const isHidden = await this.evaluateExpressions(a.hidden);
405
+ if (isHidden)
406
+ return null;
407
+ const disabled = await this.evaluateExpressions(a.disabled);
408
+ return { ...a, disabled };
409
+ }));
410
+ return actions.filter(Boolean);
411
+ }
373
412
  }
374
413
 
375
414
  function createModifierContext(entity) {
@@ -526,6 +565,15 @@ function createModifierContext(entity) {
526
565
  entity.interfaces.master = updater(entity.interfaces.master);
527
566
  return ctx;
528
567
  },
568
+ list: {
569
+ get: () => entity.interfaces?.master?.list,
570
+ update: (updater) => {
571
+ entity.interfaces ??= {};
572
+ entity.interfaces.master ??= {};
573
+ entity.interfaces.master.list = updater(entity.interfaces.master.list);
574
+ return ctx;
575
+ },
576
+ },
529
577
  create: {
530
578
  get: () => entity.interfaces?.master?.create,
531
579
  update: (updater) => {
@@ -611,6 +659,7 @@ class AXPEntityMiddleware {
611
659
  this.patternModifiers = [];
612
660
  this.providedModifiers = inject(AXP_ENTITY_MODIFIER, { optional: true }) || [];
613
661
  this.providedActionPlugins = inject(AXP_ENTITY_ACTION_PLUGIN, { optional: true }) || [];
662
+ this.injector = inject(Injector);
614
663
  for (const { entityName, modifier } of this.providedModifiers) {
615
664
  this.register(entityName, modifier);
616
665
  }
@@ -631,7 +680,7 @@ class AXPEntityMiddleware {
631
680
  }
632
681
  //#endregion
633
682
  //#region ---- Processing ----
634
- process(entity) {
683
+ async process(entity) {
635
684
  // First, expand action plugins if entity.plugins exists
636
685
  const context = createModifierContext(entity);
637
686
  const plugins = entity.plugins;
@@ -641,7 +690,7 @@ class AXPEntityMiddleware {
641
690
  const contrib = sorted.find((x) => x.name === p.name);
642
691
  if (contrib) {
643
692
  try {
644
- contrib.apply(context, p.options);
693
+ await runInInjectionContext(this.injector, () => contrib.apply(context, p.options));
645
694
  }
646
695
  catch (err) {
647
696
  console.error('[AXPEntityMiddleware] action plugin failed:', p.name, err);
@@ -683,11 +732,15 @@ class AXPEntityDefinitionRegistryService {
683
732
  this.providers = inject(AXP_ENTITY_DEFINITION_LOADER);
684
733
  this.resolver = inject(AXPEntityResolver);
685
734
  this.middleware = inject(AXPEntityMiddleware);
735
+ this.onChanged = new Subject();
686
736
  // Stores AXPEntityConfig objects, keyed by a combination of module and entity name.
687
737
  this.entities = new Map();
688
738
  // Entity resolver service for dynamically loading entity configurations.
689
739
  this.entityResolver = inject(AXPEntityResolver); // Assuming AXPEntityLoader is the correct type
690
740
  }
741
+ get onChanged$() {
742
+ return this.onChanged.asObservable();
743
+ }
691
744
  async preload() {
692
745
  const providers = Array.isArray(this.providers)
693
746
  ? this.providers
@@ -708,14 +761,14 @@ class AXPEntityDefinitionRegistryService {
708
761
  .catch(err => {
709
762
  console.error(`[AXPEntityDefinitionRegistryService] Failed to load entity ${item.module}.${item.entity}:`, err);
710
763
  return null;
711
- }), 3000, `${item.module}.${item.entity}`));
764
+ }), 10000, `${item.module}.${item.entity}`));
712
765
  });
713
766
  });
714
767
  const results = await Promise.allSettled(promises);
715
768
  const loadedEntities = [];
716
- results.forEach((result, idx) => {
769
+ results.forEach(async (result, idx) => {
717
770
  if (result.status === 'fulfilled' && result.value != null) {
718
- this.register(this.middleware.process(result.value));
771
+ this.register(await this.middleware.process(result.value));
719
772
  loadedEntities.push(result.value);
720
773
  }
721
774
  else if (result.status === 'rejected') {
@@ -724,6 +777,43 @@ class AXPEntityDefinitionRegistryService {
724
777
  });
725
778
  //console.log('[AXPEntityDefinitionRegistryService] Loaded entities:', loadedEntities);
726
779
  }
780
+ async refresh(arg1, arg2) {
781
+ // No parameters: refresh all currently registered entities
782
+ if (typeof arg1 === 'undefined' && typeof arg2 === 'undefined') {
783
+ const keys = Array.from(this.entities.keys());
784
+ for (const key of keys) {
785
+ const [m, e] = key.split('.');
786
+ if (m && e) {
787
+ await this.refreshOne(m, e);
788
+ }
789
+ }
790
+ return;
791
+ }
792
+ // One parameter: treat as fully-qualified name
793
+ if (typeof arg1 === 'string' && typeof arg2 === 'undefined') {
794
+ const [moduleName, entityName] = arg1.split('.');
795
+ if (!moduleName || !entityName) {
796
+ throw new Error(`Invalid entity full name: ${arg1}`);
797
+ }
798
+ await this.refreshOne(moduleName, entityName);
799
+ return;
800
+ }
801
+ // Two parameters: module + entity
802
+ if (typeof arg1 === 'string' && typeof arg2 === 'string') {
803
+ await this.refreshOne(arg1, arg2);
804
+ return;
805
+ }
806
+ }
807
+ /** Executes the actual refresh for a single entity */
808
+ async refreshOne(moduleName, entityName) {
809
+ const config = await this.entityResolver.get(moduleName, entityName);
810
+ if (!config) {
811
+ throw new Error(`Invalid entity name: ${moduleName}.${entityName}`);
812
+ }
813
+ const processedConfig = await this.middleware.process(config);
814
+ this.register(processedConfig);
815
+ }
816
+ //#endregion
727
817
  /**
728
818
  * Registers a new entity configuration. Entities are identified uniquely by a combination
729
819
  * of their module and name.
@@ -733,6 +823,7 @@ class AXPEntityDefinitionRegistryService {
733
823
  register(config) {
734
824
  const key = this.createEntityKey(config.module, config.name);
735
825
  this.entities.set(key, config);
826
+ this.onChanged.next({ name: key });
736
827
  }
737
828
  /**
738
829
  * Returns an array of all registered entity configurations.
@@ -759,7 +850,7 @@ class AXPEntityDefinitionRegistryService {
759
850
  try {
760
851
  config = await this.entityResolver.get(moduleName, entityName);
761
852
  if (config) {
762
- const processedConfig = this.middleware.process(config);
853
+ const processedConfig = await this.middleware.process(config);
763
854
  this.register(processedConfig);
764
855
  return processedConfig;
765
856
  }
@@ -978,7 +1069,7 @@ class AXPEntityMasterListViewModel {
978
1069
  this.applyViewColumns();
979
1070
  this.applyViewFilters();
980
1071
  // this.applyFilterAndSort();
981
- this.applySettings();
1072
+ await this.applySettings();
982
1073
  }
983
1074
  }
984
1075
  constructor(injector, config) {
@@ -992,9 +1083,12 @@ class AXPEntityMasterListViewModel {
992
1083
  this.settings = this.injector.get(AXPSettingService);
993
1084
  this.widgetResolver = this.injector.get(AXPWidgetRegistryService);
994
1085
  this.expressionEvaluator = this.injector.get(AXPExpressionEvaluatorService);
1086
+ this.commandService = this.injector.get(AXPCommandService);
995
1087
  this.filterOperatorMiddleware = this.injector.get(AXPFilterOperatorMiddlewareService);
996
1088
  this.settingEntityKey = `${this.config.module}:${this.config.name}`;
997
1089
  this.destroyed = new Subject();
1090
+ this.lastAppliedSortKey = null;
1091
+ this.lastAppliedFilterKey = null;
998
1092
  this.events$ = new Subject();
999
1093
  //****************** Views ******************//
1000
1094
  this.views = computed(() => {
@@ -1122,19 +1216,37 @@ class AXPEntityMasterListViewModel {
1122
1216
  this.saveSettings('view');
1123
1217
  const listViewSetting = await this.settings.get(this.settingEntityKey);
1124
1218
  if (listViewSetting) {
1125
- const columns = listViewSetting.list.views[this.view().name].columns;
1126
- const pageSize = listViewSetting.list.views[this.view().name].pageSize;
1127
- const columnVisibilityMap = new Map(columns.map((col) => [col.name, col.visible]));
1128
- const columnWidthsMap = new Map(columns.map((col) => [col.name, col.width]));
1129
- // if (pageSize) {
1130
- // this.dataSource.setPageSize(pageSize);
1131
- // }
1132
- this.columns.update((prev) => prev
1133
- .map((c) => {
1134
- return { ...c, width: columnWidthsMap.get(c.name), visible: columnVisibilityMap.get(c.name) ?? c.visible };
1135
- }) // Update visibility
1136
- .sort((a, b) => columns.findIndex((col) => col.name === a.name) -
1137
- columns.findIndex((col) => col.name === b.name)));
1219
+ const columns = listViewSetting.list?.views?.[this.view().name]?.columns;
1220
+ const pageSize = listViewSetting.list?.views?.[this.view().name]?.pageSize;
1221
+ const sorts = listViewSetting.list?.views?.[this.view().name]?.sorts;
1222
+ const filters = listViewSetting.list?.views?.[this.view().name]?.filters;
1223
+ let columnVisibilityMap;
1224
+ let columnWidthsMap;
1225
+ if (columns) {
1226
+ columnVisibilityMap = new Map(columns.map((col) => [col.name, col.visible]));
1227
+ columnWidthsMap = new Map(columns.map((col) => [col.name, col.width]));
1228
+ }
1229
+ // Do not set pageSize here to avoid triggering an extra load
1230
+ if (columns && columnVisibilityMap && columnWidthsMap) {
1231
+ this.columns.update((prev) => prev
1232
+ .map((c) => {
1233
+ return {
1234
+ ...c,
1235
+ width: columnWidthsMap.get(c.name),
1236
+ visible: columnVisibilityMap.get(c.name) ?? c.visible,
1237
+ };
1238
+ }) // Update visibility
1239
+ .sort((a, b) => columns.findIndex((col) => col.name === a.name) -
1240
+ columns.findIndex((col) => col.name === b.name)));
1241
+ }
1242
+ if (Array.isArray(sorts)) {
1243
+ // sorts are AXPSortQuery[]; ensure we map by name
1244
+ const sortsMap = new Map(sorts.map((s) => [s.name, s.dir]));
1245
+ this.sortedFields.update((prev) => prev.map((sf) => ({ ...sf, dir: sortsMap.get(sf.name) || sf.dir })));
1246
+ }
1247
+ if (Array.isArray(filters)) {
1248
+ this.filterQueries.set(filters);
1249
+ }
1138
1250
  }
1139
1251
  }
1140
1252
  async saveSettings(changesType, data) {
@@ -1188,6 +1300,36 @@ class AXPEntityMasterListViewModel {
1188
1300
  },
1189
1301
  }));
1190
1302
  break;
1303
+ case 'filters':
1304
+ updateSettings((prev) => ({
1305
+ ...prev,
1306
+ list: {
1307
+ ...prev?.list,
1308
+ views: {
1309
+ ...prev?.list?.views,
1310
+ [this.view().name]: {
1311
+ ...prev?.list?.views?.[this.view().name],
1312
+ filters: data,
1313
+ },
1314
+ },
1315
+ },
1316
+ }));
1317
+ break;
1318
+ case 'sorts':
1319
+ updateSettings((prev) => ({
1320
+ ...prev,
1321
+ list: {
1322
+ ...prev?.list,
1323
+ views: {
1324
+ ...prev?.list?.views,
1325
+ [this.view().name]: {
1326
+ ...prev?.list?.views?.[this.view().name],
1327
+ sorts: data,
1328
+ },
1329
+ },
1330
+ },
1331
+ }));
1332
+ break;
1191
1333
  default:
1192
1334
  break;
1193
1335
  }
@@ -1280,21 +1422,30 @@ class AXPEntityMasterListViewModel {
1280
1422
  operator: f.operator,
1281
1423
  value: f.value,
1282
1424
  }));
1283
- this.filterQueries.update((prev) => ({ ...prev, filters: viewFilters }));
1425
+ this.filterQueries.set(viewFilters);
1284
1426
  }
1285
1427
  resetFilters() {
1286
1428
  this.applyViewFilters();
1287
1429
  }
1288
1430
  async applyFilterAndSort() {
1289
- this.dataSource.clearFilter();
1290
- this.dataSource.sort(...this.sortedFields()
1431
+ const sorts = this.sortedFields()
1291
1432
  .filter((sf) => sf.dir)
1292
- .map((s) => ({ dir: s.dir, field: s.name })));
1433
+ .map((s) => ({ name: s.name, dir: s.dir }));
1434
+ const filters = this.filterQueries();
1435
+ const sortKey = JSON.stringify(sorts);
1436
+ const filterKey = JSON.stringify(filters);
1437
+ if (sortKey === this.lastAppliedSortKey && filterKey === this.lastAppliedFilterKey) {
1438
+ return; // No effective change; avoid redundant refresh
1439
+ }
1440
+ this.lastAppliedSortKey = sortKey;
1441
+ this.lastAppliedFilterKey = filterKey;
1442
+ this.dataSource.clearFilter();
1443
+ this.dataSource.sort(...sorts.map((s) => ({ dir: s.dir, field: s.name })));
1293
1444
  this.dataSource.filter(this.filterOperatorMiddleware.transformFilter({
1294
1445
  field: null,
1295
1446
  logic: 'and',
1296
1447
  operator: null,
1297
- filters: this.filterQueries(),
1448
+ filters: filters,
1298
1449
  }));
1299
1450
  this.dataSource.refresh();
1300
1451
  }
@@ -1342,19 +1493,24 @@ class AXPEntityMasterListViewModel {
1342
1493
  });
1343
1494
  const command = commandName.split('&')[0];
1344
1495
  const options = await this.evaluateExpressions(action?.options, data);
1345
- await this.workflow.execute(command, {
1346
- entity: getEntityInfo(this.entityDef).source,
1347
- entityInfo: {
1348
- name: this.entityDef.name,
1349
- module: this.entityDef.module,
1350
- title: this.entityDef.title,
1351
- parentKey: this.entityDef.parentKey,
1352
- source: this.entityDef.source,
1353
- },
1354
- data: action?.scope == AXPEntityCommandScope.Selected ? this.selectedItems() : data,
1355
- options: options,
1356
- metadata: action?.metadata,
1357
- });
1496
+ if (this.workflow.exists(command)) {
1497
+ await this.workflow.execute(command, {
1498
+ entity: getEntityInfo(this.entityDef).source,
1499
+ entityInfo: {
1500
+ name: this.entityDef.name,
1501
+ module: this.entityDef.module,
1502
+ title: this.entityDef.title,
1503
+ parentKey: this.entityDef.parentKey,
1504
+ source: this.entityDef.source,
1505
+ },
1506
+ data: action?.scope == AXPEntityCommandScope.Selected ? this.selectedItems() : data,
1507
+ options: options,
1508
+ metadata: action?.metadata,
1509
+ });
1510
+ }
1511
+ else {
1512
+ this.commandService.execute(command, options);
1513
+ }
1358
1514
  }
1359
1515
  async execute(command) {
1360
1516
  switch (command?.name) {
@@ -1893,10 +2049,14 @@ class AXPEntityMasterSingleViewModel {
1893
2049
  this.session = this.injector.get(AXPSessionService);
1894
2050
  this.formatService = this.injector.get(AXFormatService);
1895
2051
  this.workflow = this.injector.get(AXPWorkflowService);
2052
+ this.commandService = this.injector.get(AXPCommandService);
1896
2053
  this.destroyed = new Subject();
1897
2054
  this.translateService = this.injector.get(AXTranslationService);
1898
2055
  this.entityService = this.injector.get(AXPEntityService);
1899
2056
  this.expressionEvaluator = this.injector.get(AXPExpressionEvaluatorService);
2057
+ this.entityDefinitionRegistryService = this.injector.get(AXPEntityDefinitionRegistryService);
2058
+ this._updateTrigger = signal(1, ...(ngDevMode ? [{ debugName: "_updateTrigger" }] : []));
2059
+ this.updateTrigger = this._updateTrigger.asReadonly();
1900
2060
  this.context = signal(cloneDeep(this.entityData), ...(ngDevMode ? [{ debugName: "context" }] : []));
1901
2061
  this.actions = computed(() => {
1902
2062
  return (this.entityDef.interfaces?.master?.single?.actions?.map((tr) => new AXPEntityCommandTriggerViewModel(this.entityDef, tr)) ?? []);
@@ -1980,6 +2140,13 @@ class AXPEntityMasterSingleViewModel {
1980
2140
  this.context.set(event.payload.values);
1981
2141
  }
1982
2142
  });
2143
+ this.entityDefinitionRegistryService.onChanged$
2144
+ .pipe(takeUntil(this.destroyed))
2145
+ .subscribe((event) => {
2146
+ if (event.name == getEntityInfo(this.entityDef).source) {
2147
+ this._updateTrigger.set(this._updateTrigger() + 1);
2148
+ }
2149
+ });
1983
2150
  }
1984
2151
  navigateToUp() {
1985
2152
  this.workflow.execute('navigate', {
@@ -1989,7 +2156,7 @@ class AXPEntityMasterSingleViewModel {
1989
2156
  });
1990
2157
  }
1991
2158
  async executeCommand(commandName, data = null) {
1992
- //TODO: syntact for workflow
2159
+ //TODO: syntax for workflow
1993
2160
  const command = commandName.split('&')[0];
1994
2161
  switch (command) {
1995
2162
  case 'modify-entity-section': {
@@ -2005,11 +2172,17 @@ class AXPEntityMasterSingleViewModel {
2005
2172
  default: {
2006
2173
  const action = this.actions().find((c) => c.name == commandName);
2007
2174
  const options = await this.evaluateExpressions(action?.options, this.context());
2008
- this.workflow.execute(command, {
2009
- entity: getEntityInfo(this.entityDef).source,
2010
- data: this.context(),
2011
- options,
2012
- });
2175
+ //
2176
+ if (this.workflow.exists(command)) {
2177
+ this.workflow.execute(command, {
2178
+ entity: getEntityInfo(this.entityDef).source,
2179
+ data: this.context(),
2180
+ options,
2181
+ });
2182
+ }
2183
+ else {
2184
+ this.commandService.execute(command, data);
2185
+ }
2013
2186
  }
2014
2187
  }
2015
2188
  }
@@ -2362,231 +2535,662 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
2362
2535
  }]
2363
2536
  }] });
2364
2537
 
2365
- async function entityRelatedEntityPageDetails(relatedEntity, entityResolver) {
2366
- const moduleName = relatedEntity.entity.split('.')[0];
2367
- const entityName = relatedEntity.entity.split('.')[1];
2368
- const entityDef = await entityResolver.get(moduleName, entityName);
2369
- if (!entityDef) {
2370
- throw new Error(`Entity ${relatedEntity.entity} not found`);
2371
- }
2372
- const groups = entityDef?.groups ?? [];
2373
- const singleInterface = entityDef?.interfaces?.master?.single;
2374
- const getGroupById = (id) => {
2375
- return groups.find((s) => s.id === id);
2376
- };
2377
- const getPropertyByGroupId = (groupId) => {
2378
- return entityDef?.properties.filter((p) => p.groupId === groupId) ?? [];
2379
- };
2380
- const getPropertyLayout = (name) => {
2381
- return singleInterface?.properties?.find((p) => p.name === name)?.layout;
2382
- };
2383
- return {
2384
- id: entityDef?.name ?? '',
2385
- title: relatedEntity.title ?? entityDef?.title ?? '',
2386
- icon: relatedEntity.icon,
2387
- settings: {
2538
+ class AXPLayoutAdapterBuilder {
2539
+ constructor() {
2540
+ this.adapter = {};
2541
+ }
2542
+ setEntity(entity, rootContext) {
2543
+ this.entity = entity;
2544
+ this.rootContext = rootContext;
2545
+ return this;
2546
+ }
2547
+ setDependencies(dependencies) {
2548
+ this.dependencies = dependencies;
2549
+ return this;
2550
+ }
2551
+ setMainPage(mainPage) {
2552
+ this.adapter.pages = [mainPage];
2553
+ return this;
2554
+ }
2555
+ setRelatedPages(relatedPages) {
2556
+ this.adapter.pages = [...(this.adapter.pages || []), ...relatedPages];
2557
+ return this;
2558
+ }
2559
+ build() {
2560
+ return {
2561
+ title: this.entity?.formats.plural || this.entity?.title,
2562
+ actions: [],
2563
+ breadcrumbs: this.createBreadcrumbs(),
2564
+ execute: this.createExecuteFunction(),
2565
+ load: this.createLoadFunction(),
2566
+ pages: this.adapter.pages || [],
2567
+ };
2568
+ }
2569
+ createBreadcrumbs() {
2570
+ const session = this.dependencies.session;
2571
+ const moduleName = this.entity?.module;
2572
+ const entityName = this.entity?.name;
2573
+ return [
2574
+ {
2575
+ title: this.entity?.formats.plural ?? '',
2576
+ command: {
2577
+ name: 'navigate',
2578
+ options: {
2579
+ path: `/${session.application?.name}/m/${moduleName}/e/${entityName}/list`,
2580
+ },
2581
+ },
2582
+ },
2583
+ {
2584
+ title: this.entity?.interfaces?.master?.single?.title ?? '',
2585
+ command: {
2586
+ name: 'navigate',
2587
+ options: {
2588
+ path: `/${session.application?.name}/m/${moduleName}/e/${entityName}/${this.rootContext.id}/new-view`,
2589
+ },
2590
+ },
2591
+ },
2592
+ ];
2593
+ }
2594
+ createExecuteFunction() {
2595
+ return (command, context) => {
2596
+ console.log('layout execute', command, context);
2597
+ return Promise.resolve({ success: true });
2598
+ };
2599
+ }
2600
+ createLoadFunction() {
2601
+ return async () => {
2602
+ return {
2603
+ success: true,
2604
+ result: this.rootContext,
2605
+ };
2606
+ };
2607
+ }
2608
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterBuilder, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2609
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterBuilder, providedIn: 'root' }); }
2610
+ }
2611
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterBuilder, decorators: [{
2612
+ type: Injectable,
2613
+ args: [{
2614
+ providedIn: 'root',
2615
+ }]
2616
+ }] });
2617
+
2618
+ class AXPBaseRelatedEntityConverter {
2619
+ async getEntityDefinition(relatedEntity, entityResolver) {
2620
+ const [moduleName, entityName] = relatedEntity.entity.split('.');
2621
+ const entityDef = await entityResolver.resolve(moduleName, entityName);
2622
+ if (!entityDef) {
2623
+ throw new Error(`Entity ${relatedEntity.entity} not found`);
2624
+ }
2625
+ return { entityDef, moduleName, entityName };
2626
+ }
2627
+ createExpressionEvaluator(context, expressionEvaluator) {
2628
+ return async (actionData) => {
2629
+ const scope = {
2630
+ context: {
2631
+ eval: (path) => get(context, path),
2632
+ },
2633
+ };
2634
+ return await expressionEvaluator.evaluate(actionData, scope);
2635
+ };
2636
+ }
2637
+ async createFilters(relatedEntity, evaluateExpressions) {
2638
+ return (relatedEntity.conditions?.map(async (c) => {
2639
+ const value = await evaluateExpressions(c.value);
2640
+ return {
2641
+ field: c.name,
2642
+ operator: c.operator,
2643
+ value: value,
2644
+ };
2645
+ }) ?? []);
2646
+ }
2647
+ createEntityHelpers(entityDef) {
2648
+ const groups = entityDef?.groups ?? [];
2649
+ const singleInterface = entityDef?.interfaces?.master?.single;
2650
+ return {
2651
+ getGroupById: (id) => groups.find((s) => s.id === id),
2652
+ getPropertyByGroupId: (groupId) => entityDef?.properties.filter((p) => p.groupId === groupId) ?? [],
2653
+ getPropertyLayout: (name) => singleInterface?.properties?.find((p) => p.name === name)?.layout,
2654
+ singleInterface,
2655
+ groups,
2656
+ };
2657
+ }
2658
+ createGridLayoutStructure(singleInterface, helpers) {
2659
+ return {
2660
+ type: 'grid-layout',
2661
+ options: {
2662
+ grid: {
2663
+ default: {
2664
+ gridTemplateColumns: 'repeat(12, 1fr)',
2665
+ gridTemplateRows: 'repeat(1, 1fr)',
2666
+ gap: '20px',
2667
+ },
2668
+ },
2669
+ },
2670
+ children: singleInterface?.sections.map((s) => ({
2671
+ type: 'grid-item-layout',
2672
+ name: s.id,
2673
+ options: {
2674
+ colSpan: s.layout?.positions?.lg?.colSpan ?? 12,
2675
+ colStart: s.layout?.positions?.lg?.colStart,
2676
+ colEnd: s.layout?.positions?.lg?.colEnd,
2677
+ },
2678
+ children: [
2679
+ {
2680
+ type: 'fieldset-layout',
2681
+ options: {
2682
+ title: helpers.getGroupById(s.id)?.title ?? '',
2683
+ collapsible: true,
2684
+ },
2685
+ children: [this.createPropertyGrid(s.id, helpers)],
2686
+ },
2687
+ ],
2688
+ })),
2689
+ };
2690
+ }
2691
+ createPropertyGrid(sectionId, helpers) {
2692
+ return {
2693
+ type: 'grid-layout',
2694
+ mode: 'edit',
2695
+ options: {
2696
+ grid: {
2697
+ default: {
2698
+ gridTemplateColumns: 'repeat(12, 1fr)',
2699
+ gridTemplateRows: 'repeat(1, 1fr)',
2700
+ gap: '20px',
2701
+ },
2702
+ },
2703
+ },
2704
+ children: helpers
2705
+ .getPropertyByGroupId(sectionId)
2706
+ .filter((property) => !property.schema.hidden)
2707
+ .map((p) => {
2708
+ const layout = helpers.getPropertyLayout(p.name);
2709
+ return {
2710
+ type: 'grid-item-layout',
2711
+ name: p.name,
2712
+ options: {
2713
+ colSpan: layout?.positions?.lg?.colSpan ?? 12,
2714
+ colStart: layout?.positions?.lg?.colStart,
2715
+ colEnd: layout?.positions?.lg?.colEnd,
2716
+ },
2717
+ children: [
2718
+ {
2719
+ type: 'form-field',
2720
+ options: {
2721
+ label: p.title,
2722
+ },
2723
+ children: [
2724
+ {
2725
+ type: p.schema.interface?.type ?? '',
2726
+ path: p.name,
2727
+ name: p.name,
2728
+ defaultValue: p.schema.defaultValue,
2729
+ children: p.schema.interface?.children,
2730
+ options: p.schema.interface?.options,
2731
+ triggers: p.schema.interface?.triggers,
2732
+ valueTransforms: p.schema.interface?.valueTransforms,
2733
+ },
2734
+ ],
2735
+ },
2736
+ ],
2737
+ };
2738
+ }),
2739
+ };
2740
+ }
2741
+ }
2742
+
2743
+ class AXPPageDetailsConverter extends AXPBaseRelatedEntityConverter {
2744
+ async convert(relatedEntity, context) {
2745
+ const { entityDef } = await this.getEntityDefinition(relatedEntity, context.entityResolver);
2746
+ const helpers = this.createEntityHelpers(entityDef);
2747
+ return {
2748
+ id: entityDef?.name ?? '',
2749
+ title: relatedEntity.title ?? entityDef?.title ?? '',
2750
+ label: relatedEntity.title ?? entityDef?.formats.displayName ?? '',
2751
+ icon: relatedEntity.icon || entityDef.icon,
2752
+ settings: this.createPageSettings(),
2753
+ load: this.createLoadFunction(entityDef, relatedEntity),
2754
+ execute: this.createExecuteFunction(entityDef),
2755
+ content: [this.createGridLayoutStructure(helpers.singleInterface, helpers)],
2756
+ };
2757
+ }
2758
+ createPageSettings() {
2759
+ return {
2388
2760
  commands: {
2389
2761
  reject: {
2390
2762
  title: 't("discard")',
2391
2763
  color: 'default',
2392
2764
  visible: '{{context.isDirty()}}',
2393
- command: {
2394
- name: 'discard',
2395
- },
2765
+ command: { name: 'discard' },
2396
2766
  },
2397
2767
  accept: {
2398
2768
  title: 't("confirm")',
2399
2769
  color: 'secondary',
2400
2770
  visible: '{{context.isDirty()}}',
2401
- command: {
2402
- name: 'update-entity',
2403
- },
2771
+ command: { name: 'update-entity' },
2404
2772
  },
2405
2773
  },
2406
- },
2407
- load: async (context) => {
2774
+ };
2775
+ }
2776
+ createLoadFunction(entityDef, relatedEntity) {
2777
+ return async (context) => {
2408
2778
  const fn = entityDef?.queries.byKey?.execute;
2409
2779
  const conditionNames = relatedEntity.conditions?.map((c) => c.name) ?? [];
2410
2780
  const id = getSmart(context, conditionNames[0]);
2411
2781
  const result = await fn(id);
2412
- return {
2413
- success: true,
2414
- result: result,
2415
- };
2416
- },
2417
- execute: async (e, context) => {
2418
- if (e.name == 'update-entity') {
2782
+ return { success: true, result };
2783
+ };
2784
+ }
2785
+ createExecuteFunction(entityDef) {
2786
+ return async (e, context) => {
2787
+ if (e.name === 'update-entity') {
2419
2788
  const fn = entityDef?.commands?.update?.execute;
2420
2789
  const result = await fn(context);
2421
- return {
2422
- success: true,
2423
- result: result,
2424
- };
2790
+ return { success: true, result };
2425
2791
  }
2426
2792
  else {
2427
2793
  return {
2428
2794
  success: false,
2429
- error: {
2430
- code: 'invalid_command',
2431
- message: 'Invalid command',
2432
- },
2795
+ error: { code: 'invalid_command', message: 'Invalid command' },
2433
2796
  };
2434
2797
  }
2435
- },
2436
- content: [
2437
- {
2438
- type: 'grid-layout',
2439
- mode: 'edit',
2440
- options: {
2441
- grid: {
2442
- default: {
2443
- gridTemplateColumns: 'repeat(12, 1fr)',
2444
- gridTemplateRows: 'repeat(1, 1fr)',
2445
- gap: '20px',
2446
- },
2798
+ };
2799
+ }
2800
+ }
2801
+
2802
+ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
2803
+ async convert(relatedEntity, context) {
2804
+ const { entityDef } = await this.getEntityDefinition(relatedEntity, context.entityResolver);
2805
+ const evaluateExpressions = async (actionData) => {
2806
+ const scope = {
2807
+ context: {
2808
+ eval: (path) => {
2809
+ return get(context.context, path);
2447
2810
  },
2448
2811
  },
2449
- children: singleInterface?.sections.map((s) => {
2450
- console.log('s', s);
2812
+ };
2813
+ return await context.expressionEvaluator.evaluate(actionData, scope);
2814
+ };
2815
+ const filters = relatedEntity.conditions?.map(async (c) => {
2816
+ const value = await evaluateExpressions(c.value);
2817
+ return {
2818
+ field: c.name,
2819
+ operator: c.operator,
2820
+ value: value,
2821
+ hidden: true,
2822
+ };
2823
+ }) ?? [];
2824
+ return {
2825
+ id: entityDef?.name ?? '',
2826
+ title: `${context.rootTitle}`,
2827
+ label: relatedEntity.title,
2828
+ icon: relatedEntity.icon || entityDef.icon,
2829
+ actions: this.mergeActions(entityDef, relatedEntity)
2830
+ ?.filter((a) => a.priority === 'primary')
2831
+ ?.map((a) => {
2832
+ return {
2833
+ ...a,
2834
+ zone: 'header',
2835
+ // visible:
2836
+ // a.scope === AXPEntityCommandScope.Selected
2837
+ // ? "{{widget.find('table').outputs().selectedItem().length > 0}}"
2838
+ // : true,
2839
+ visible: '{{context.eval("table")}}',
2840
+ priority: 'primary',
2841
+ name: a.name,
2842
+ title: a.title,
2843
+ scope: a.scope,
2844
+ icon: a.icon,
2845
+ color: a.color,
2846
+ disabled: a.disabled,
2847
+ command: {
2848
+ name: a.name,
2849
+ options: a.options,
2850
+ metadata: a.metadata,
2851
+ },
2852
+ };
2853
+ }),
2854
+ execute: async (command, executeContext) => {
2855
+ try {
2856
+ const commandName = command.name.split('&')[0];
2857
+ const mergedActions = this.mergeActions(entityDef, relatedEntity);
2858
+ const action = mergedActions.find((a) => {
2859
+ return a.name === commandName || a.name.split('&')[0] === commandName;
2860
+ });
2861
+ if (!action) {
2862
+ console.warn(`Action ${commandName} not found in entity definition`);
2863
+ return {
2864
+ success: false,
2865
+ error: {
2866
+ code: 'ACTION_NOT_FOUND',
2867
+ message: `Action ${commandName} not found`,
2868
+ details: command,
2869
+ },
2870
+ };
2871
+ }
2872
+ let evaluatedOptions = command.options;
2873
+ if (action.options) {
2874
+ evaluatedOptions = await evaluateExpressions(action.options);
2875
+ }
2876
+ await context.workflowService.execute(commandName, {
2877
+ entity: getEntityInfo(entityDef).source,
2878
+ entityInfo: {
2879
+ name: entityDef.name,
2880
+ module: entityDef.module,
2881
+ title: entityDef.title,
2882
+ parentKey: entityDef.parentKey,
2883
+ source: entityDef.source,
2884
+ },
2885
+ data: action.scope == AXPEntityCommandScope.Selected
2886
+ ? executeContext
2887
+ : evaluatedOptions?.['process']?.data || null,
2888
+ options: evaluatedOptions,
2889
+ metadata: action.metadata,
2890
+ });
2891
+ return { success: true };
2892
+ }
2893
+ catch (error) {
2894
+ console.error('Error executing command:', error);
2451
2895
  return {
2452
- type: 'grid-item-layout',
2453
- name: s.id,
2454
- options: {
2455
- colSpan: s.layout?.positions?.lg?.colSpan ?? 12,
2456
- colStart: s.layout?.positions?.lg?.colStart,
2457
- colEnd: s.layout?.positions?.lg?.colEnd,
2896
+ success: false,
2897
+ error: {
2898
+ code: 'EXECUTION_ERROR',
2899
+ message: error instanceof Error ? error.message : 'Unknown error occurred',
2900
+ details: error,
2458
2901
  },
2459
- children: [
2460
- {
2461
- type: 'fieldset-layout',
2462
- options: {
2463
- title: getGroupById(s.id)?.title ?? '',
2464
- collapsible: true,
2465
- },
2466
- children: [
2467
- {
2468
- type: 'grid-layout',
2469
- options: {
2470
- grid: {
2471
- default: {
2472
- gridTemplateColumns: 'repeat(12, 1fr)',
2473
- gridTemplateRows: 'repeat(1, 1fr)',
2474
- gap: '20px',
2475
- },
2476
- },
2477
- },
2478
- children: getPropertyByGroupId(s.id)
2479
- .filter((property) => !property.schema.hidden)
2480
- .map((p) => {
2481
- const layout = getPropertyLayout(p.name);
2482
- return {
2483
- type: 'grid-item-layout',
2484
- name: p.name,
2485
- options: {
2486
- colSpan: layout?.positions?.lg?.colSpan ?? 12,
2487
- colStart: layout?.positions?.lg?.colStart,
2488
- colEnd: layout?.positions?.lg?.colEnd,
2489
- },
2490
- children: [
2491
- {
2492
- type: 'form-field',
2493
- options: {
2494
- label: p.title,
2495
- },
2496
- children: [
2497
- {
2498
- type: p.schema.interface?.type ?? '',
2499
- path: p.name,
2500
- name: p.name,
2501
- defaultValue: p.schema.defaultValue,
2502
- children: p.schema.interface?.children,
2503
- options: p.schema.interface?.options,
2504
- triggers: p.schema.interface?.triggers,
2505
- valueTransforms: p.schema.interface?.valueTransforms,
2506
- },
2507
- ],
2508
- },
2509
- ],
2510
- };
2511
- }),
2512
- },
2513
- ],
2514
- },
2515
- ],
2516
2902
  };
2517
- }),
2903
+ }
2518
2904
  },
2519
- ],
2520
- };
2905
+ content: [
2906
+ {
2907
+ type: AXPWidgetsCatalog.entityList,
2908
+ name: 'page-list',
2909
+ defaultValue: {
2910
+ toolbar: {
2911
+ filters: await Promise.all(filters),
2912
+ },
2913
+ },
2914
+ options: {
2915
+ entity: relatedEntity.entity,
2916
+ showEntityActions: false,
2917
+ },
2918
+ },
2919
+ ],
2920
+ };
2921
+ }
2922
+ mergeActions(entityDef, relatedEntity) {
2923
+ const originalList = entityDef?.interfaces?.master?.list?.actions ?? [];
2924
+ const relatedEntityActionList = relatedEntity.actions ?? [];
2925
+ // Create a map to track which actions from relatedEntityActionList have been used
2926
+ const usedOverrideActions = new Set();
2927
+ // Start with original actions, applying overrides where they exist
2928
+ const mergedActions = originalList.map((originalAction) => {
2929
+ const originalCommandName = typeof originalAction.command === 'string' ? originalAction.command : originalAction.command.name;
2930
+ const overrideAction = relatedEntityActionList.find((action) => {
2931
+ const actionCommandName = typeof action.command === 'string' ? action.command : action.command.name;
2932
+ return actionCommandName === originalCommandName && action.name === originalAction.name;
2933
+ });
2934
+ if (overrideAction) {
2935
+ // Mark this override action as used
2936
+ const overrideKey = `${typeof overrideAction.command === 'string' ? overrideAction.command : overrideAction.command.name}_${overrideAction.name}`;
2937
+ usedOverrideActions.add(overrideKey);
2938
+ return new AXPEntityCommandTriggerViewModel(entityDef, overrideAction);
2939
+ }
2940
+ return new AXPEntityCommandTriggerViewModel(entityDef, originalAction);
2941
+ });
2942
+ // Add any remaining actions from relatedEntityActionList that weren't used as overrides
2943
+ const additionalActions = relatedEntityActionList
2944
+ .filter((action) => {
2945
+ const actionKey = `${typeof action.command === 'string' ? action.command : action.command.name}_${action.name}`;
2946
+ return !usedOverrideActions.has(actionKey);
2947
+ })
2948
+ .map((action) => new AXPEntityCommandTriggerViewModel(entityDef, action));
2949
+ return [...additionalActions, ...mergedActions].filter((a) => !a.hidden);
2950
+ }
2521
2951
  }
2522
2952
 
2523
- async function entityRelatedEntityPageList(relatedEntity, entityResolver) {
2524
- const moduleName = relatedEntity.entity.split('.')[0];
2525
- const entityName = relatedEntity.entity.split('.')[1];
2526
- const entityDef = await entityResolver.get(moduleName, entityName);
2527
- if (!entityDef) {
2528
- throw new Error(`Entity ${relatedEntity.entity} not found`);
2953
+ class AXPTabDetailsConverter extends AXPBaseRelatedEntityConverter {
2954
+ async convert(relatedEntity, context) {
2955
+ const { entityDef } = await this.getEntityDefinition(relatedEntity, context.entityResolver);
2956
+ const helpers = this.createEntityHelpers(entityDef);
2957
+ return {
2958
+ id: entityDef?.name ?? '',
2959
+ title: relatedEntity.title ?? entityDef?.title ?? '',
2960
+ icon: relatedEntity.icon || entityDef.icon,
2961
+ content: [this.createGridLayoutStructure(helpers.singleInterface, helpers)],
2962
+ };
2529
2963
  }
2530
- return {
2531
- id: entityDef?.name ?? '',
2532
- title: relatedEntity.title || '',
2533
- icon: relatedEntity.icon,
2534
- content: [
2535
- {
2536
- type: AXPWidgetsCatalog.entityList,
2537
- name: 'page-list',
2538
- options: {
2539
- entity: relatedEntity.entity,
2964
+ }
2965
+
2966
+ class AXPTabListConverter extends AXPBaseRelatedEntityConverter {
2967
+ async convert(relatedEntity, context) {
2968
+ const { entityDef } = await this.getEntityDefinition(relatedEntity, context.entityResolver);
2969
+ const evaluateExpressions = async (actionData) => {
2970
+ const scope = {
2971
+ context: {
2972
+ eval: (path) => {
2973
+ return get(context.context, path);
2974
+ },
2540
2975
  },
2541
- },
2542
- ],
2543
- };
2976
+ };
2977
+ return await context.expressionEvaluator.evaluate(actionData, scope);
2978
+ };
2979
+ // console.log({ relatedEntity });
2980
+ const filters = relatedEntity.conditions?.map(async (c) => {
2981
+ const value = await evaluateExpressions(c.value);
2982
+ return {
2983
+ field: c.name,
2984
+ operator: c.operator,
2985
+ value: value,
2986
+ hidden: true,
2987
+ };
2988
+ }) ?? [];
2989
+ return {
2990
+ id: entityDef?.name ?? '',
2991
+ title: relatedEntity.title ?? entityDef?.title ?? '',
2992
+ icon: relatedEntity.icon || entityDef.icon,
2993
+ content: [
2994
+ {
2995
+ type: AXPWidgetsCatalog.entityList,
2996
+ name: 'tab-list',
2997
+ defaultValue: {
2998
+ toolbar: {
2999
+ filters: await Promise.all(filters),
3000
+ },
3001
+ },
3002
+ options: {
3003
+ entity: relatedEntity.entity,
3004
+ showEntityActions: true,
3005
+ showToolbar: true,
3006
+ },
3007
+ },
3008
+ ],
3009
+ };
3010
+ }
2544
3011
  }
2545
3012
 
2546
- async function entityRelatedEntityTabDetails(relatedEntity, entityResolver) {
2547
- const moduleName = relatedEntity.entity.split('.')[0];
2548
- const entityName = relatedEntity.entity.split('.')[1];
2549
- const entityDef = await entityResolver.get(moduleName, entityName);
2550
- if (!entityDef) {
2551
- throw new Error(`Entity ${relatedEntity.entity} not found`);
2552
- }
2553
- const groups = entityDef?.groups ?? [];
2554
- const singleInterface = entityDef?.interfaces?.master?.single;
2555
- const getGroupById = (id) => {
2556
- return groups.find((s) => s.id === id);
2557
- };
2558
- const getPropertyByGroupId = (groupId) => {
2559
- return entityDef?.properties.filter((p) => p.groupId === groupId) ?? [];
2560
- };
2561
- const getPropertyLayout = (name) => {
2562
- return singleInterface?.properties?.find((p) => p.name === name)?.layout;
2563
- };
2564
- return {
2565
- id: entityDef?.name ?? '',
2566
- title: relatedEntity.title ?? entityDef?.title ?? '',
2567
- icon: relatedEntity.icon,
2568
- content: [
2569
- {
2570
- type: 'grid-layout',
2571
- mode: 'edit',
2572
- options: {
2573
- grid: {
2574
- default: {
2575
- gridTemplateColumns: 'repeat(12, 1fr)',
2576
- gridTemplateRows: 'repeat(1, 1fr)',
2577
- gap: '20px',
3013
+ class AXPRelatedEntityConverterFactory {
3014
+ createConverter(type) {
3015
+ switch (type) {
3016
+ case 'page-detail':
3017
+ return new AXPPageDetailsConverter();
3018
+ case 'page-list':
3019
+ return new AXPPageListConverter();
3020
+ case 'tab-detail':
3021
+ return new AXPTabDetailsConverter();
3022
+ case 'tab-list':
3023
+ return new AXPTabListConverter();
3024
+ default:
3025
+ throw new Error(`Unsupported converter type: ${type}`);
3026
+ }
3027
+ }
3028
+ createPageDetailsConverter() {
3029
+ return this.createConverter('page-detail');
3030
+ }
3031
+ createPageListConverter() {
3032
+ return this.createConverter('page-list');
3033
+ }
3034
+ createTabDetailsConverter() {
3035
+ return this.createConverter('tab-detail');
3036
+ }
3037
+ createTabListConverter() {
3038
+ return this.createConverter('tab-list');
3039
+ }
3040
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPRelatedEntityConverterFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3041
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPRelatedEntityConverterFactory, providedIn: 'root' }); }
3042
+ }
3043
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPRelatedEntityConverterFactory, decorators: [{
3044
+ type: Injectable,
3045
+ args: [{
3046
+ providedIn: 'root',
3047
+ }]
3048
+ }] });
3049
+
3050
+ class AXPMainEntityContentBuilder {
3051
+ constructor(relatedEntityConverterFactory) {
3052
+ this.relatedEntityConverterFactory = relatedEntityConverterFactory;
3053
+ this.workflowService = inject(AXPWorkflowService);
3054
+ this.commandService = inject(AXPCommandService);
3055
+ }
3056
+ async build(entity, rootContext, dependencies) {
3057
+ const groups = entity?.groups ?? [];
3058
+ const singleInterface = entity?.interfaces?.master?.single;
3059
+ const getGroupById = (id) => {
3060
+ return groups.find((s) => s.id === id);
3061
+ };
3062
+ const filterValidSections = (sections) => {
3063
+ return (sections?.filter((section) => {
3064
+ return groups.some((group) => group.id === section.id);
3065
+ }) ?? []);
3066
+ };
3067
+ const getPropertyByGroupId = (groupId) => {
3068
+ return entity?.properties.filter((p) => p.groupId === groupId) ?? [];
3069
+ };
3070
+ const getPropertyLayout = (name) => {
3071
+ return singleInterface?.properties?.find((p) => p.name === name)?.layout;
3072
+ };
3073
+ // Get related entities for tabs
3074
+ const tabDetailEntities = entity?.relatedEntities?.filter((re) => !re.hidden && re.layoutType === 'tab-detail');
3075
+ const tabListEntities = entity?.relatedEntities?.filter((re) => !re.hidden && (!re.layoutType || re.layoutType === 'tab-list'));
3076
+ // Build related tabs if dependencies are provided
3077
+ const tabDetailTabs = await this.buildTabDetails(tabDetailEntities ?? [], dependencies);
3078
+ const tabListTabs = await this.buildTabLists(tabListEntities ?? [], rootContext, dependencies);
3079
+ // Build actions from single interface
3080
+ const actions = this.buildActions(entity, singleInterface);
3081
+ // Create expression evaluator for actions
3082
+ const evaluateExpressions = dependencies?.expressionEvaluator
3083
+ ? this.createExpressionEvaluator(rootContext, dependencies.expressionEvaluator)
3084
+ : null;
3085
+ return {
3086
+ id: entity?.name ?? '',
3087
+ title: singleInterface?.title ?? entity?.formats.individual ?? '',
3088
+ label: entity?.formats.displayName ?? singleInterface?.title ?? '',
3089
+ icon: entity?.icon,
3090
+ actions: await this.buildEvaluatedActions(actions, evaluateExpressions),
3091
+ settings: {
3092
+ commands: {
3093
+ reject: {
3094
+ title: 't("discard")',
3095
+ color: 'default',
3096
+ visible: '{{context.isDirty()}}',
3097
+ command: {
3098
+ name: 'discard',
3099
+ },
3100
+ },
3101
+ accept: {
3102
+ title: 't("confirm")',
3103
+ color: 'secondary',
3104
+ visible: '{{context.isDirty()}}',
3105
+ command: {
3106
+ name: 'update-entity',
3107
+ },
3108
+ },
3109
+ },
3110
+ },
3111
+ load: async () => {
3112
+ return {
3113
+ success: true,
3114
+ result: rootContext,
3115
+ };
3116
+ },
3117
+ execute: async (e, context) => {
3118
+ if (e.name == 'update-entity') {
3119
+ const fn = entity?.commands?.update?.execute;
3120
+ const result = await fn(context);
3121
+ return {
3122
+ success: true,
3123
+ result: result,
3124
+ };
3125
+ }
3126
+ else {
3127
+ // Find action in single interface actions
3128
+ const action = actions.find((a) => a.name === e.name);
3129
+ if (action && dependencies?.workflowService) {
3130
+ // Evaluate action options with current context
3131
+ let evaluatedOptions = action.options;
3132
+ if (evaluateExpressions && action.options) {
3133
+ try {
3134
+ evaluatedOptions = await evaluateExpressions(action.options);
3135
+ }
3136
+ catch {
3137
+ // Keep original options if evaluation fails
3138
+ }
3139
+ }
3140
+ const commandName = e.name.split('&')[0];
3141
+ if (this.workflowService.exists(commandName)) {
3142
+ await this.workflowService.execute(commandName, {
3143
+ entity: getEntityInfo(entity).source,
3144
+ data: context,
3145
+ entityInfo: {
3146
+ name: entity.name,
3147
+ module: entity.module,
3148
+ title: entity.title,
3149
+ parentKey: entity.parentKey,
3150
+ source: entity.source,
3151
+ },
3152
+ options: evaluatedOptions,
3153
+ metadata: action.metadata,
3154
+ });
3155
+ return {
3156
+ success: true,
3157
+ };
3158
+ }
3159
+ if (this.commandService.exists(commandName)) {
3160
+ // check options for evaluation
3161
+ await this.commandService.execute(commandName, e.options);
3162
+ }
3163
+ }
3164
+ return {
3165
+ success: false,
3166
+ error: {
3167
+ code: 'invalid_command',
3168
+ message: 'Invalid command',
3169
+ },
3170
+ };
3171
+ }
3172
+ },
3173
+ tabs: [...tabDetailTabs, ...tabListTabs],
3174
+ content: [
3175
+ {
3176
+ type: 'grid-layout',
3177
+ mode: 'edit',
3178
+ options: {
3179
+ grid: {
3180
+ default: {
3181
+ gridTemplateColumns: 'repeat(12, 1fr)',
3182
+ gridTemplateRows: 'repeat(1, 1fr)',
3183
+ gap: '20px',
3184
+ },
2578
3185
  },
2579
3186
  },
2580
- },
2581
- children: singleInterface?.sections.map((s) => {
2582
- console.log('s', s);
2583
- return {
3187
+ children: filterValidSections(singleInterface?.sections ?? []).map((s) => ({
2584
3188
  type: 'grid-item-layout',
2585
3189
  name: s.id,
2586
3190
  options: {
2587
3191
  colSpan: s.layout?.positions?.lg?.colSpan ?? 12,
2588
- colStart: s.layout?.positions?.lg?.colStart,
2589
- colEnd: s.layout?.positions?.lg?.colEnd,
3192
+ colStart: s.layout?.positions?.lg?.colStart ?? 1,
3193
+ colEnd: s.layout?.positions?.lg?.colEnd ?? 13,
2590
3194
  },
2591
3195
  children: [
2592
3196
  {
@@ -2594,6 +3198,7 @@ async function entityRelatedEntityTabDetails(relatedEntity, entityResolver) {
2594
3198
  options: {
2595
3199
  title: getGroupById(s.id)?.title ?? '',
2596
3200
  collapsible: true,
3201
+ isOpen: !s.collapsed,
2597
3202
  },
2598
3203
  children: [
2599
3204
  {
@@ -2615,7 +3220,7 @@ async function entityRelatedEntityTabDetails(relatedEntity, entityResolver) {
2615
3220
  type: 'grid-item-layout',
2616
3221
  name: p.name,
2617
3222
  options: {
2618
- colSpan: layout?.positions?.lg?.colSpan ?? 12,
3223
+ colSpan: layout?.positions?.lg?.colSpan,
2619
3224
  colStart: layout?.positions?.lg?.colStart,
2620
3225
  colEnd: layout?.positions?.lg?.colEnd,
2621
3226
  },
@@ -2632,9 +3237,15 @@ async function entityRelatedEntityTabDetails(relatedEntity, entityResolver) {
2632
3237
  name: p.name,
2633
3238
  defaultValue: p.schema.defaultValue,
2634
3239
  children: p.schema.interface?.children,
2635
- options: p.schema.interface?.options,
2636
3240
  triggers: p.schema.interface?.triggers,
2637
3241
  valueTransforms: p.schema.interface?.valueTransforms,
3242
+ options: merge(p.schema.interface?.options, {
3243
+ validations: p.validations?.map((c) => ({
3244
+ rule: c.rule,
3245
+ message: c.message,
3246
+ options: c.options,
3247
+ })),
3248
+ }),
2638
3249
  },
2639
3250
  ],
2640
3251
  },
@@ -2645,236 +3256,192 @@ async function entityRelatedEntityTabDetails(relatedEntity, entityResolver) {
2645
3256
  ],
2646
3257
  },
2647
3258
  ],
2648
- };
2649
- }),
2650
- },
2651
- ],
2652
- };
3259
+ })),
3260
+ },
3261
+ ],
3262
+ };
3263
+ }
3264
+ buildActions(entity, singleInterface) {
3265
+ const actions = singleInterface?.actions ?? [];
3266
+ return actions.map((action) => new AXPEntityCommandTriggerViewModel(entity, action));
3267
+ }
3268
+ createExpressionEvaluator(context, expressionEvaluator) {
3269
+ return async (actionData) => {
3270
+ const scope = {
3271
+ context: {
3272
+ eval: (path) => {
3273
+ return get(context, path);
3274
+ },
3275
+ },
3276
+ };
3277
+ return await expressionEvaluator.evaluate(actionData, scope);
3278
+ };
3279
+ }
3280
+ async buildEvaluatedActions(actions, evaluateExpressions) {
3281
+ const evaluatedActions = [];
3282
+ for (const action of actions) {
3283
+ // Evaluate disabled condition
3284
+ let disabled = action.disabled;
3285
+ if (disabled && typeof disabled === 'string' && evaluateExpressions) {
3286
+ try {
3287
+ const result = await evaluateExpressions({ disabled: disabled });
3288
+ disabled = result.disabled;
3289
+ }
3290
+ catch {
3291
+ disabled = false;
3292
+ }
3293
+ }
3294
+ // Evaluate hidden condition
3295
+ let hidden = action.hidden;
3296
+ if (hidden && typeof hidden === 'string' && evaluateExpressions) {
3297
+ try {
3298
+ const result = await evaluateExpressions({ hidden: hidden });
3299
+ hidden = result.hidden;
3300
+ }
3301
+ catch {
3302
+ hidden = false;
3303
+ }
3304
+ }
3305
+ // Skip if hidden
3306
+ if (hidden)
3307
+ continue;
3308
+ // Evaluate options
3309
+ let options = action.options;
3310
+ if (options && evaluateExpressions) {
3311
+ try {
3312
+ options = await evaluateExpressions(options);
3313
+ }
3314
+ catch {
3315
+ // Keep original options if evaluation fails
3316
+ }
3317
+ }
3318
+ evaluatedActions.push({
3319
+ name: action.name,
3320
+ title: action.title,
3321
+ icon: action.icon,
3322
+ color: action.color,
3323
+ disabled: disabled || false,
3324
+ zone: 'header',
3325
+ priority: action.priority,
3326
+ command: {
3327
+ name: action.name,
3328
+ options: options,
3329
+ metadata: action.metadata,
3330
+ },
3331
+ });
3332
+ }
3333
+ return evaluatedActions;
3334
+ }
3335
+ async buildTabDetails(tabDetailEntities, dependencies) {
3336
+ if (!dependencies?.entityResolver || !tabDetailEntities?.length) {
3337
+ return [];
3338
+ }
3339
+ const tabs = [];
3340
+ for (const relatedEntity of tabDetailEntities) {
3341
+ const converter = this.relatedEntityConverterFactory.createTabDetailsConverter();
3342
+ tabs.push(await converter.convert(relatedEntity, {
3343
+ entityResolver: dependencies.entityResolver,
3344
+ }));
3345
+ }
3346
+ return tabs;
3347
+ }
3348
+ async buildTabLists(tabListEntities, rootContext, dependencies) {
3349
+ if (!dependencies?.entityResolver || !tabListEntities?.length) {
3350
+ return [];
3351
+ }
3352
+ const tabs = [];
3353
+ for (const relatedEntity of tabListEntities) {
3354
+ const converter = this.relatedEntityConverterFactory.createTabListConverter();
3355
+ tabs.push(await converter.convert(relatedEntity, {
3356
+ entityResolver: dependencies.entityResolver,
3357
+ expressionEvaluator: dependencies.expressionEvaluator,
3358
+ context: rootContext,
3359
+ }));
3360
+ }
3361
+ return tabs;
3362
+ }
3363
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMainEntityContentBuilder, deps: [{ token: AXPRelatedEntityConverterFactory }], target: i0.ɵɵFactoryTarget.Injectable }); }
3364
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMainEntityContentBuilder, providedIn: 'root' }); }
2653
3365
  }
3366
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMainEntityContentBuilder, decorators: [{
3367
+ type: Injectable,
3368
+ args: [{
3369
+ providedIn: 'root',
3370
+ }]
3371
+ }], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }] });
2654
3372
 
2655
- async function entityRelatedEntityTabList(relatedEntity, entityResolver) {
2656
- const moduleName = relatedEntity.entity.split('.')[0];
2657
- const entityName = relatedEntity.entity.split('.')[1];
2658
- const entityDef = await entityResolver.get(moduleName, entityName);
2659
- if (!entityDef) {
2660
- throw new Error(`Entity ${relatedEntity.entity} not found`);
3373
+ class AXPLayoutAdapterFactory {
3374
+ constructor(relatedEntityConverterFactory, mainEntityContentBuilder, layoutAdapterBuilder) {
3375
+ this.relatedEntityConverterFactory = relatedEntityConverterFactory;
3376
+ this.mainEntityContentBuilder = mainEntityContentBuilder;
3377
+ this.layoutAdapterBuilder = layoutAdapterBuilder;
3378
+ }
3379
+ async createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies) {
3380
+ const entity = await entityResolver.resolve(moduleName, entityName);
3381
+ if (!entity) {
3382
+ throw new Error(`Entity ${moduleName}.${entityName} not found`);
3383
+ }
3384
+ const rootContext = await this.loadRootContext(entity, id);
3385
+ return this.layoutAdapterBuilder
3386
+ .setEntity(entity, rootContext)
3387
+ .setDependencies(dependencies)
3388
+ .setMainPage(await this.buildMainPage(entity, rootContext, dependencies))
3389
+ .setRelatedPages(await this.buildRelatedPages(entity, rootContext, dependencies))
3390
+ .build();
3391
+ }
3392
+ async loadRootContext(entity, id) {
3393
+ const fn = entity?.queries.byKey?.execute;
3394
+ return await fn(id);
3395
+ }
3396
+ async buildMainPage(entity, rootContext, dependencies) {
3397
+ return this.mainEntityContentBuilder.build(entity, rootContext, dependencies);
3398
+ }
3399
+ async buildRelatedPages(entity, rootContext, dependencies) {
3400
+ const pages = [];
3401
+ // Page Details
3402
+ const pageDetailEntities = entity?.relatedEntities?.filter((re) => !re.hidden && re.layoutType === 'page-detail');
3403
+ for (const relatedEntity of pageDetailEntities || []) {
3404
+ const converter = this.relatedEntityConverterFactory.createPageDetailsConverter();
3405
+ pages.push(await converter.convert(relatedEntity, { entityResolver: dependencies.entityResolver }));
3406
+ }
3407
+ // Page Lists
3408
+ const pageListEntities = entity?.relatedEntities?.filter((re) => !re.hidden && re.layoutType === 'page-list');
3409
+ for (const relatedEntity of pageListEntities || []) {
3410
+ const converter = this.relatedEntityConverterFactory.createPageListConverter();
3411
+ pages.push(await converter.convert(relatedEntity, {
3412
+ ...dependencies,
3413
+ context: rootContext,
3414
+ rootTitle: await this.getRootTitle(entity, rootContext, dependencies),
3415
+ }));
3416
+ }
3417
+ return pages;
2661
3418
  }
2662
- return {
2663
- id: entityDef?.name ?? '',
2664
- title: relatedEntity.title || '',
2665
- icon: relatedEntity.icon,
2666
- content: [
2667
- {
2668
- type: AXPWidgetsCatalog.entityList,
2669
- name: 'tab-list',
2670
- options: {
2671
- entity: relatedEntity.entity,
2672
- },
2673
- },
2674
- ],
2675
- };
3419
+ async getRootTitle(entity, rootContext, dependencies) {
3420
+ // Logic for getting root title
3421
+ return await dependencies.expressionEvaluator.evaluate(entity.interfaces?.master?.single?.title, rootContext);
3422
+ }
3423
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterFactory, deps: [{ token: AXPRelatedEntityConverterFactory }, { token: AXPMainEntityContentBuilder }, { token: AXPLayoutAdapterBuilder }], target: i0.ɵɵFactoryTarget.Injectable }); }
3424
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterFactory, providedIn: 'root' }); }
2676
3425
  }
3426
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLayoutAdapterFactory, decorators: [{
3427
+ type: Injectable,
3428
+ args: [{
3429
+ providedIn: 'root',
3430
+ }]
3431
+ }], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }, { type: AXPMainEntityContentBuilder }, { type: AXPLayoutAdapterBuilder }] });
2677
3432
 
2678
- const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver = inject(AXPEntityResolver), session = inject(AXPSessionService)) => {
3433
+ const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver = inject(AXPEntityDefinitionRegistryService), expressionEvaluator = inject(AXPExpressionEvaluatorService), session = inject(AXPSessionService), formatService = inject(AXFormatService), workflowService = inject(AXPWorkflowService), layoutAdapterFactory = inject(AXPLayoutAdapterFactory)) => {
2679
3434
  const moduleName = route.parent?.paramMap.get('module');
2680
3435
  const entityName = route.paramMap.get('entity');
2681
- const entity = await entityResolver.get(moduleName, entityName);
2682
3436
  const id = route.paramMap.get('id');
2683
- const groups = entity?.groups ?? [];
2684
- const singleInterface = entity?.interfaces?.master?.single;
2685
- const getGroupById = (id) => {
2686
- return groups.find((s) => s.id === id);
2687
- };
2688
- const getPropertyByGroupId = (groupId) => {
2689
- return entity?.properties.filter((p) => p.groupId === groupId) ?? [];
2690
- };
2691
- const getPropertyLayout = (name) => {
2692
- return singleInterface?.properties?.find((p) => p.name === name)?.layout;
2693
- };
2694
- const getRelatedEntities = (type) => {
2695
- return entity?.relatedEntities?.filter((re) => !re.hidden && re.layoutType === type);
2696
- };
2697
- //
2698
- const adapter = {
2699
- title: entity?.title,
2700
- // description: entity?.description,
2701
- actions: [],
2702
- breadcrumbs: [
2703
- {
2704
- title: entity?.formats.plural ?? '',
2705
- command: {
2706
- name: 'navigate',
2707
- options: {
2708
- path: `/${session.application?.name}/m/${moduleName}/e/${entityName}/list`,
2709
- },
2710
- },
2711
- },
2712
- {
2713
- title: entity?.interfaces?.master?.single?.title ?? '',
2714
- },
2715
- ],
2716
- execute: (command, context) => {
2717
- console.log('layout execute', command, context);
2718
- return Promise.resolve({ success: true });
2719
- },
2720
- load: async () => {
2721
- const fn = entity?.queries.byKey?.execute;
2722
- const result = await fn(id);
2723
- return {
2724
- success: true,
2725
- result: result,
2726
- };
2727
- },
2728
- pages: [
2729
- {
2730
- id: entity?.name ?? '',
2731
- // title: singleInterface?.title ?? entity?.formats.individual ?? '',
2732
- title: entity?.formats.individual ?? '',
2733
- icon: entity?.icon,
2734
- settings: {
2735
- commands: {
2736
- reject: {
2737
- title: 't("discard")',
2738
- color: 'default',
2739
- visible: '{{context.isDirty()}}',
2740
- command: {
2741
- name: 'discard',
2742
- },
2743
- },
2744
- accept: {
2745
- title: 't("confirm")',
2746
- color: 'secondary',
2747
- visible: '{{context.isDirty()}}',
2748
- command: {
2749
- name: 'update-entity',
2750
- },
2751
- },
2752
- },
2753
- },
2754
- load: async () => {
2755
- const fn = entity?.queries.byKey?.execute;
2756
- const result = await fn(id);
2757
- return {
2758
- success: true,
2759
- result: result,
2760
- };
2761
- },
2762
- execute: async (e, context) => {
2763
- if (e.name == 'update-entity') {
2764
- const fn = entity?.commands?.update?.execute;
2765
- const result = await fn(context);
2766
- return {
2767
- success: true,
2768
- result: result,
2769
- };
2770
- }
2771
- else {
2772
- return {
2773
- success: false,
2774
- error: {
2775
- code: 'invalid_command',
2776
- message: 'Invalid command',
2777
- },
2778
- };
2779
- }
2780
- },
2781
- tabs: [
2782
- ...(await Promise.all(getRelatedEntities('tab-detail')?.map(async (e) => await entityRelatedEntityTabDetails(e, entityResolver)) ?? [])),
2783
- ...(await Promise.all(getRelatedEntities('tab-list')?.map(async (e) => await entityRelatedEntityTabList(e, entityResolver)) ?? [])),
2784
- ],
2785
- content: [
2786
- {
2787
- type: 'grid-layout',
2788
- mode: 'edit',
2789
- options: {
2790
- grid: {
2791
- default: {
2792
- gridTemplateColumns: 'repeat(12, 1fr)',
2793
- gridTemplateRows: 'repeat(1, 1fr)',
2794
- gap: '20px',
2795
- },
2796
- },
2797
- },
2798
- children: singleInterface?.sections.map((s) => ({
2799
- type: 'grid-item-layout',
2800
- name: s.id,
2801
- options: {
2802
- colSpan: s.layout?.positions?.lg?.colSpan ?? 12,
2803
- colStart: s.layout?.positions?.lg?.colStart ?? 1,
2804
- colEnd: s.layout?.positions?.lg?.colEnd ?? 13,
2805
- },
2806
- children: [
2807
- {
2808
- type: 'fieldset-layout',
2809
- options: {
2810
- title: getGroupById(s.id)?.title ?? '',
2811
- collapsible: true,
2812
- },
2813
- children: [
2814
- {
2815
- type: 'grid-layout',
2816
- options: {
2817
- grid: {
2818
- default: {
2819
- gridTemplateColumns: 'repeat(12, 1fr)',
2820
- gridTemplateRows: 'repeat(1, 1fr)',
2821
- gap: '20px',
2822
- },
2823
- },
2824
- },
2825
- children: getPropertyByGroupId(s.id)
2826
- .filter((property) => !property.schema.hidden)
2827
- .map((p) => {
2828
- const layout = getPropertyLayout(p.name);
2829
- return {
2830
- type: 'grid-item-layout',
2831
- name: p.name,
2832
- options: {
2833
- colSpan: layout?.positions?.lg?.colSpan,
2834
- colStart: layout?.positions?.lg?.colStart,
2835
- colEnd: layout?.positions?.lg?.colEnd,
2836
- },
2837
- children: [
2838
- {
2839
- type: 'form-field',
2840
- options: {
2841
- label: p.title,
2842
- },
2843
- children: [
2844
- {
2845
- type: p.schema.interface?.type ?? '',
2846
- path: p.name,
2847
- name: p.name,
2848
- defaultValue: p.schema.defaultValue,
2849
- children: p.schema.interface?.children,
2850
- options: p.schema.interface?.options,
2851
- triggers: p.schema.interface?.triggers,
2852
- valueTransforms: p.schema.interface?.valueTransforms,
2853
- },
2854
- ],
2855
- },
2856
- ],
2857
- };
2858
- }),
2859
- },
2860
- ],
2861
- },
2862
- ],
2863
- })),
2864
- },
2865
- ],
2866
- },
2867
- ...(await Promise.all(getRelatedEntities('page-detail')?.map(async (e) => await entityRelatedEntityPageDetails(e, entityResolver)) ??
2868
- [])),
2869
- ...(await Promise.all(getRelatedEntities('page-list')?.map(async (e) => await entityRelatedEntityPageList(e, entityResolver)) ?? [])),
2870
- ],
3437
+ const dependencies = {
3438
+ entityResolver,
3439
+ expressionEvaluator,
3440
+ session,
3441
+ formatService,
3442
+ workflowService,
2871
3443
  };
2872
- //
2873
- return new Promise((resolve) => {
2874
- setTimeout(() => {
2875
- resolve(adapter);
2876
- }, 200);
2877
- });
3444
+ return await layoutAdapterFactory.createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies);
2878
3445
  };
2879
3446
 
2880
3447
  class AXPEntityCommandSearchDefinitionProvider {
@@ -2919,13 +3486,12 @@ class AXPEntitySearchDefinitionProvider {
2919
3486
  }
2920
3487
  }
2921
3488
 
2922
- class AXPEntityListConverterService {
3489
+ class AXPEntityListTableService {
2923
3490
  constructor() {
2924
3491
  //#region ---- Services & Dependencies ----
2925
3492
  this.entityResolver = inject(AXPEntityResolver);
2926
3493
  this.workflow = inject(AXPWorkflowService);
2927
3494
  this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
2928
- this.widgetResolver = inject(AXPWidgetRegistryService);
2929
3495
  this.evaluateExpressions = async (options, data) => {
2930
3496
  const scope = {
2931
3497
  context: {
@@ -2939,14 +3505,6 @@ class AXPEntityListConverterService {
2939
3505
  }
2940
3506
  //#endregion
2941
3507
  //#region ---- Public Methods ----
2942
- async convertEntityToolbarOptions(entity, options) {
2943
- const toolbarOptions = {
2944
- filterDefinitions: this.createFilterDefinitions(entity),
2945
- columnDefinitions: this.createColumnDefinitions(entity, options),
2946
- sortDefinitions: this.createSortDefinitions(entity),
2947
- };
2948
- return toolbarOptions;
2949
- }
2950
3508
  /**
2951
3509
  * Convert Entity to List Widget Options
2952
3510
  */
@@ -2968,6 +3526,8 @@ class AXPEntityListConverterService {
2968
3526
  showFooter: false,
2969
3527
  // 🔗 Entity Configuration
2970
3528
  parentField: entity.parentKey,
3529
+ fetchDataMode: 'manual',
3530
+ minHeight: 250,
2971
3531
  // 🎪 Events
2972
3532
  ...this.createDefaultEvents(entity, allActions),
2973
3533
  };
@@ -3136,6 +3696,36 @@ class AXPEntityListConverterService {
3136
3696
  },
3137
3697
  };
3138
3698
  }
3699
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListTableService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3700
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListTableService }); }
3701
+ }
3702
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListTableService, decorators: [{
3703
+ type: Injectable
3704
+ }] });
3705
+
3706
+ class AXPEntityListToolbarService {
3707
+ constructor() {
3708
+ //#region ---- Services & Dependencies ----
3709
+ this.widgetResolver = inject(AXPWidgetRegistryService);
3710
+ }
3711
+ //#endregion
3712
+ //#region ---- Public Methods ----
3713
+ /**
3714
+ * Convert Entity to Toolbar Options
3715
+ */
3716
+ async convertEntityToolbarOptions(entity, options) {
3717
+ const toolbarOptions = {
3718
+ filterDefinitions: this.createFilterDefinitions(entity),
3719
+ columnDefinitions: this.createColumnDefinitions(entity, options),
3720
+ sortDefinitions: this.createSortDefinitions(entity),
3721
+ };
3722
+ return toolbarOptions;
3723
+ }
3724
+ //#endregion
3725
+ //#region ---- Private Methods ----
3726
+ /**
3727
+ * Create Filter Definitions for Toolbar
3728
+ */
3139
3729
  createFilterDefinitions(entity) {
3140
3730
  const props = entity.properties.filter((c) => c.options?.filter?.advance?.enabled || c.options?.filter?.inline?.enabled);
3141
3731
  return props.map((e) => {
@@ -3160,6 +3750,9 @@ class AXPEntityListConverterService {
3160
3750
  };
3161
3751
  });
3162
3752
  }
3753
+ /**
3754
+ * Create Column Definitions for Toolbar
3755
+ */
3163
3756
  createColumnDefinitions(entity, options) {
3164
3757
  const { columns = [], properties } = entity;
3165
3758
  const excludeColumns = options?.excludeColumns || [];
@@ -3185,6 +3778,9 @@ class AXPEntityListConverterService {
3185
3778
  };
3186
3779
  });
3187
3780
  }
3781
+ /**
3782
+ * Create Sort Definitions for Toolbar
3783
+ */
3188
3784
  createSortDefinitions(entity) {
3189
3785
  const props = entity.properties.filter((c) => c.options?.sort?.enabled);
3190
3786
  return props.map((e) => {
@@ -3194,10 +3790,10 @@ class AXPEntityListConverterService {
3194
3790
  };
3195
3791
  });
3196
3792
  }
3197
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListConverterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3198
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListConverterService }); }
3793
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListToolbarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3794
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListToolbarService }); }
3199
3795
  }
3200
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListConverterService, decorators: [{
3796
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListToolbarService, decorators: [{
3201
3797
  type: Injectable
3202
3798
  }] });
3203
3799
 
@@ -3206,21 +3802,26 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
3206
3802
  super(...arguments);
3207
3803
  this.entityResolver = inject(AXPEntityResolver);
3208
3804
  this.workflow = inject(AXPWorkflowService);
3209
- this.entityListService = inject(AXPEntityListConverterService);
3805
+ this.entityListTableService = inject(AXPEntityListTableService);
3806
+ this.entityListToolbarService = inject(AXPEntityListToolbarService);
3210
3807
  this.layoutThemeService = inject(AXPLayoutThemeService);
3808
+ this.container = viewChild(AXPWidgetContainerComponent, ...(ngDevMode ? [{ debugName: "container" }] : []));
3809
+ this.isMounted = signal(false, ...(ngDevMode ? [{ debugName: "isMounted" }] : []));
3211
3810
  this.entity = signal(null, ...(ngDevMode ? [{ debugName: "entity" }] : []));
3212
3811
  this.listNode = signal(null, ...(ngDevMode ? [{ debugName: "listNode" }] : []));
3213
3812
  this.list = viewChild('list', ...(ngDevMode ? [{ debugName: "list" }] : []));
3214
3813
  this.allWidgets = viewChildren(AXPWidgetRendererDirective, ...(ngDevMode ? [{ debugName: "allWidgets" }] : []));
3215
- this.listWidget = computed(() => this.allWidgets().find((widget) => widget.node()?.type === AXPWidgetsCatalog.list), ...(ngDevMode ? [{ debugName: "listWidget" }] : []));
3814
+ this.listWidget = linkedSignal(() => this.allWidgets().find((widget) => widget.node()?.type === AXPWidgetsCatalog.list));
3216
3815
  this.toolbarWidget = computed(() => this.allWidgets().find((widget) => widget.node()?.type === AXPWidgetsCatalog.listToolbar), ...(ngDevMode ? [{ debugName: "toolbarWidget" }] : []));
3217
- this.selectedItems = computed(() => this.contextService.getValue(`${this.fullPath()}.table`) || [], ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
3816
+ this.selectedItems = computed(() => this.getValue()?.table || [], ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
3218
3817
  this.toolbarNode = signal(null, ...(ngDevMode ? [{ debugName: "toolbarNode" }] : []));
3219
3818
  this.destroyed = new Subject();
3220
3819
  //options
3221
3820
  this.entitySource = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entitySource" }] : []));
3222
3821
  this.excludeColumns = computed(() => this.options()['excludeColumns'], ...(ngDevMode ? [{ debugName: "excludeColumns" }] : []));
3223
3822
  this.includeColumns = computed(() => this.options()['includeColumns'], ...(ngDevMode ? [{ debugName: "includeColumns" }] : []));
3823
+ this.showEntityActions = computed(() => this.options()['showEntityActions'] ?? true, ...(ngDevMode ? [{ debugName: "showEntityActions" }] : []));
3824
+ this.showToolbar = computed(() => this.options()['showToolbar'] ?? true, ...(ngDevMode ? [{ debugName: "showToolbar" }] : []));
3224
3825
  //actions
3225
3826
  this.allActions = computed(() => {
3226
3827
  const list = this.entity()?.interfaces?.master?.list?.actions ?? [];
@@ -3263,6 +3864,20 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
3263
3864
  }));
3264
3865
  return actions;
3265
3866
  }, ...(ngDevMode ? [{ debugName: "secondaryActions" }] : []));
3867
+ //#region ---- Query Change Handler ----
3868
+ this.#effect = effect(() => {
3869
+ const queries = this.getValue()?.toolbar;
3870
+ const listInstance = this.listWidget()?.instance;
3871
+ const dataSource = this.listWidget()?.options()['dataSource'];
3872
+ const isMounted = this.isMounted();
3873
+ if (!this.hasRequiredDependencies(dataSource, queries, listInstance)) {
3874
+ return;
3875
+ }
3876
+ untracked(() => {
3877
+ this.handleQueryChanges(queries, dataSource, listInstance, isMounted);
3878
+ });
3879
+ }, ...(ngDevMode ? [{ debugName: "#effect" }] : []));
3880
+ //#endregion
3266
3881
  this.context = {};
3267
3882
  this.previousQueries = null;
3268
3883
  }
@@ -3276,6 +3891,9 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
3276
3891
  this.execute(item.command.name, null);
3277
3892
  }
3278
3893
  }
3894
+ // ngDoCheck(): void {
3895
+ // console.log(this.listWidget()?.instance.output('selectedRows'));
3896
+ // }
3279
3897
  async execute(commandName, data) {
3280
3898
  const action = this.allActions().find((c) => {
3281
3899
  return (c.name == commandName &&
@@ -3300,30 +3918,71 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
3300
3918
  metadata: action?.metadata,
3301
3919
  });
3302
3920
  }
3303
- onContextChanged(context) {
3304
- const queries = context.data.list.toolbar;
3921
+ //#region ---- Query Change Handler ----
3922
+ #effect;
3923
+ /**
3924
+ * Validates that all required dependencies are available
3925
+ */
3926
+ hasRequiredDependencies(dataSource, queries, listInstance) {
3927
+ return !!(dataSource && queries && listInstance);
3928
+ }
3929
+ /**
3930
+ * Handles all query-related changes (filters, sorts, columns)
3931
+ */
3932
+ handleQueryChanges(queries, dataSource, listInstance, isMounted) {
3933
+ const changeTracker = this.analyzeChanges(queries);
3934
+ this.previousQueries = queries;
3935
+ this.applyDataSourceChanges(dataSource, queries, changeTracker);
3936
+ this.handleListRefresh(listInstance, changeTracker, isMounted);
3937
+ this.handleColumnChanges(changeTracker);
3938
+ }
3939
+ /**
3940
+ * Analyzes what has changed between current and previous queries
3941
+ */
3942
+ analyzeChanges(queries) {
3305
3943
  const changes = getChangedPaths(queries, this.previousQueries);
3306
- console.log('changes', changes, queries);
3307
- const listInstance = untracked(() => this.listWidget()?.instance);
3308
- const isFilterChanged = changes.includes('filters');
3309
- const isSortChanged = changes.includes('sorts');
3310
- const isColumnsChanged = changes.includes('columns');
3311
- untracked(() => {
3312
- this.previousQueries = queries;
3313
- const dataSource = listInstance?.options()['dataSource'];
3314
- if (isFilterChanged) {
3315
- dataSource.filter({
3316
- filters: queries.filters,
3317
- });
3318
- listInstance?.call('refresh');
3319
- }
3320
- if (isSortChanged) {
3321
- dataSource.sort(...queries.sorts);
3322
- listInstance?.call('refresh');
3944
+ return {
3945
+ isFilterChanged: changes.includes('filters'),
3946
+ isSortChanged: changes.includes('sorts'),
3947
+ isColumnsChanged: changes.includes('columns'),
3948
+ hasAnyChange: changes.length > 0,
3949
+ };
3950
+ }
3951
+ /**
3952
+ * Applies filter and sort changes to the data source
3953
+ */
3954
+ applyDataSourceChanges(dataSource, queries, changeTracker) {
3955
+ if (changeTracker.isFilterChanged) {
3956
+ dataSource.filter({
3957
+ filters: queries?.filters,
3958
+ });
3959
+ }
3960
+ if (changeTracker.isSortChanged) {
3961
+ dataSource.sort(...(queries.sorts || []));
3962
+ }
3963
+ }
3964
+ /**
3965
+ * Handles list refresh logic based on changes and mount status
3966
+ */
3967
+ handleListRefresh(listInstance, changeTracker, isMounted) {
3968
+ const shouldRefresh = changeTracker.isFilterChanged || changeTracker.isSortChanged || !isMounted;
3969
+ if (shouldRefresh) {
3970
+ listInstance.call('refresh');
3971
+ // Set mounted flag only on initial load (not when filters/sorts change)
3972
+ if (!changeTracker.isFilterChanged && !changeTracker.isSortChanged) {
3973
+ this.isMounted.set(true);
3323
3974
  }
3324
- // if(isColumnsChanged){
3325
- // }
3326
- });
3975
+ }
3976
+ }
3977
+ /**
3978
+ * Handles column-related changes
3979
+ * TODO: Implement column change logic
3980
+ */
3981
+ handleColumnChanges(changeTracker) {
3982
+ if (changeTracker.isColumnsChanged) {
3983
+ // TODO: Implement column change handling
3984
+ console.log('Column changes detected - implementation needed');
3985
+ }
3327
3986
  }
3328
3987
  async ngOnInit() {
3329
3988
  super.ngOnInit();
@@ -3341,21 +4000,26 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
3341
4000
  excludeColumns: this.excludeColumns(),
3342
4001
  includeColumns: this.includeColumns(),
3343
4002
  };
3344
- const listOptions = await this.entityListService.convertEntityToListOptions(resolvedEntity, options);
3345
- const toolbarOptions = await this.entityListService.convertEntityToolbarOptions(resolvedEntity, options);
4003
+ const listOptions = await this.entityListTableService.convertEntityToListOptions(resolvedEntity, options);
4004
+ const toolbarOptions = await this.entityListToolbarService.convertEntityToolbarOptions(resolvedEntity, options);
3346
4005
  this.listNode.set({
3347
4006
  type: AXPWidgetsCatalog.list,
3348
4007
  options: listOptions,
3349
4008
  path: `table`,
4009
+ name: 'table',
3350
4010
  mode: 'view',
3351
- defaultValue: this.getValue(),
4011
+ defaultValue: this.getValue()?.table,
3352
4012
  });
3353
4013
  this.toolbarNode.set({
3354
4014
  type: AXPWidgetsCatalog.listToolbar,
3355
4015
  path: `toolbar`,
3356
4016
  options: toolbarOptions,
3357
4017
  mode: 'view',
3358
- defaultValue: this.getValue(),
4018
+ defaultValue: {
4019
+ filters: this.getValue()?.toolbar?.filters,
4020
+ sorts: this.getValue()?.toolbar?.sorts,
4021
+ columns: this.getValue()?.toolbar?.columns,
4022
+ },
3359
4023
  });
3360
4024
  }
3361
4025
  ngAfterViewInit() {
@@ -3368,13 +4032,14 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
3368
4032
  }
3369
4033
  });
3370
4034
  }
3371
- destroy() {
4035
+ ngOnDestroy() {
4036
+ this.listWidget.set(undefined);
3372
4037
  this.destroyed.next();
3373
4038
  this.destroyed.complete();
3374
4039
  }
3375
4040
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3376
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: AXPEntityListWidgetViewComponent, isStandalone: true, selector: "ng-component", providers: [AXPEntityListConverterService], viewQueries: [{ propertyName: "list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "allWidgets", predicate: AXPWidgetRendererDirective, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
3377
- <axp-widgets-container [context]="context" (onContextChanged)="onContextChanged($event)">
4041
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: AXPEntityListWidgetViewComponent, isStandalone: true, selector: "ng-component", host: { properties: { "class": "\"ax-h-full\"" } }, providers: [AXPEntityListTableService, AXPEntityListToolbarService], viewQueries: [{ propertyName: "container", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }, { propertyName: "list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "allWidgets", predicate: AXPWidgetRendererDirective, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
4042
+ @if (showEntityActions()) {
3378
4043
  <div class="ax-flex ax-gap-2 ax-justify-end ax-mb-4">
3379
4044
  @for (action of primaryActions(); track $index) {
3380
4045
  @if (action.visible != false) {
@@ -3451,37 +4116,36 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
3451
4116
  </ax-button>
3452
4117
  }
3453
4118
  </div>
3454
-
3455
- <div class="ax-flex ax-flex-col ax-gap-2">
3456
- @if (toolbarNode() != null) {
3457
- <ng-container
3458
- #toolbar
3459
- axp-widget-renderer
3460
- [node]="toolbarNode()!"
3461
- [parentNode]="this"
3462
- [index]="index"
3463
- [mode]="this.mode"
3464
- ></ng-container>
3465
- }
3466
- @if (listNode() != null) {
3467
- <ng-container
3468
- #list
3469
- axp-widget-renderer
3470
- [node]="listNode()!"
3471
- [parentNode]="this"
3472
- [index]="index"
3473
- [mode]="this.mode"
3474
- ></ng-container>
3475
- }
3476
- </div>
3477
- </axp-widgets-container>
3478
- `, 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: "component", type: i2.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { 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 }); }
4119
+ }
4120
+ <div class="ax-flex ax-flex-col ax-gap-2 ax-h-full">
4121
+ @if (toolbarNode() != null && showToolbar()) {
4122
+ <ng-container
4123
+ #toolbar
4124
+ axp-widget-renderer
4125
+ [node]="toolbarNode()!"
4126
+ [parentNode]="this"
4127
+ [index]="index"
4128
+ [mode]="this.mode"
4129
+ ></ng-container>
4130
+ }
4131
+ @if (listNode() != null) {
4132
+ <ng-container
4133
+ #list
4134
+ axp-widget-renderer
4135
+ [node]="listNode()!"
4136
+ [parentNode]="this"
4137
+ [index]="index"
4138
+ [mode]="this.mode"
4139
+ ></ng-container>
4140
+ }
4141
+ </div>
4142
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXPLayoutBuilderModule }, { kind: "directive", type: i2.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i3$1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i3$1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i4.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3479
4143
  }
3480
4144
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListWidgetViewComponent, decorators: [{
3481
4145
  type: Component,
3482
4146
  args: [{
3483
4147
  template: `
3484
- <axp-widgets-container [context]="context" (onContextChanged)="onContextChanged($event)">
4148
+ @if (showEntityActions()) {
3485
4149
  <div class="ax-flex ax-gap-2 ax-justify-end ax-mb-4">
3486
4150
  @for (action of primaryActions(); track $index) {
3487
4151
  @if (action.visible != false) {
@@ -3558,34 +4222,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
3558
4222
  </ax-button>
3559
4223
  }
3560
4224
  </div>
3561
-
3562
- <div class="ax-flex ax-flex-col ax-gap-2">
3563
- @if (toolbarNode() != null) {
3564
- <ng-container
3565
- #toolbar
3566
- axp-widget-renderer
3567
- [node]="toolbarNode()!"
3568
- [parentNode]="this"
3569
- [index]="index"
3570
- [mode]="this.mode"
3571
- ></ng-container>
3572
- }
3573
- @if (listNode() != null) {
3574
- <ng-container
3575
- #list
3576
- axp-widget-renderer
3577
- [node]="listNode()!"
3578
- [parentNode]="this"
3579
- [index]="index"
3580
- [mode]="this.mode"
3581
- ></ng-container>
3582
- }
3583
- </div>
3584
- </axp-widgets-container>
4225
+ }
4226
+ <div class="ax-flex ax-flex-col ax-gap-2 ax-h-full">
4227
+ @if (toolbarNode() != null && showToolbar()) {
4228
+ <ng-container
4229
+ #toolbar
4230
+ axp-widget-renderer
4231
+ [node]="toolbarNode()!"
4232
+ [parentNode]="this"
4233
+ [index]="index"
4234
+ [mode]="this.mode"
4235
+ ></ng-container>
4236
+ }
4237
+ @if (listNode() != null) {
4238
+ <ng-container
4239
+ #list
4240
+ axp-widget-renderer
4241
+ [node]="listNode()!"
4242
+ [parentNode]="this"
4243
+ [index]="index"
4244
+ [mode]="this.mode"
4245
+ ></ng-container>
4246
+ }
4247
+ </div>
3585
4248
  `,
3586
4249
  standalone: true,
4250
+ host: {
4251
+ '[class]': '"ax-h-full"',
4252
+ },
3587
4253
  changeDetection: ChangeDetectionStrategy.OnPush,
3588
- providers: [AXPEntityListConverterService],
4254
+ providers: [AXPEntityListTableService, AXPEntityListToolbarService],
3589
4255
  imports: [CommonModule, AXDecoratorModule, AXPLayoutBuilderModule, AXButtonModule, AXDropdownModule],
3590
4256
  }]
3591
4257
  }] });
@@ -3731,17 +4397,14 @@ var entityReferenceWidgetDesigner_component = /*#__PURE__*/Object.freeze({
3731
4397
  });
3732
4398
 
3733
4399
  const AXPEntityReferenceWidget = {
3734
- name: "entity-reference",
3735
- title: "Entity Reference",
4400
+ name: 'entity-reference',
4401
+ title: 'Entity Reference',
3736
4402
  description: '',
3737
4403
  type: 'view',
3738
4404
  categories: [],
3739
- groups: [AXPWidgetGroupEnum.FormElement],
3740
- icon: "fa-solid fa-square",
3741
- properties: [
3742
- AXP_NAME_PROPERTY,
3743
- AXP_DATA_PATH_PROPERTY,
3744
- ],
4405
+ groups: [AXPWidgetGroupEnum.EntityWidget],
4406
+ icon: 'fa-solid fa-square',
4407
+ properties: [AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY],
3745
4408
  components: {
3746
4409
  view: {
3747
4410
  component: () => Promise.resolve().then(function () { return entityReferenceWidgetView_component; }).then((c) => c.AXPEntityReferenceWidgetViewComponent),
@@ -3758,7 +4421,7 @@ const AXPEntityReferenceWidget = {
3758
4421
  designer: {
3759
4422
  component: () => Promise.resolve().then(function () { return entityReferenceWidgetDesigner_component; }).then((c) => c.AXPEntityReferenceWidgetDesignerComponent),
3760
4423
  },
3761
- }
4424
+ },
3762
4425
  };
3763
4426
 
3764
4427
  class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
@@ -5057,6 +5720,7 @@ const AXPTagableBoxWidget = {
5057
5720
  description: 'Inputs text with tags',
5058
5721
  categories: AXP_WIDGETS_EDITOR_CATEGORY,
5059
5722
  type: 'editor',
5723
+ groups: [AXPWidgetGroupEnum.EntityWidget],
5060
5724
  defaultFilterWidgetName: 'string-filter',
5061
5725
  properties: [AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY],
5062
5726
  components: {
@@ -5453,10 +6117,10 @@ class AXPShowDetailViewAction extends AXPWorkflowAction {
5453
6117
  this.sessionService = inject(AXPSessionService);
5454
6118
  }
5455
6119
  async execute(context) {
5456
- const [module, entity] = context.getVariable('entity').split(".");
6120
+ const [module, entity] = context.getVariable('entity').split('.');
5457
6121
  const { id } = context.getVariable('data');
5458
6122
  const newPayload = {
5459
- commands: `/${this.sessionService.application?.name}/m/${module}/e/${entity}/${id}/view`,
6123
+ commands: `/${this.sessionService.application?.name}/m/${module}/e/${entity}/${id}/new-view`,
5460
6124
  };
5461
6125
  context.setVariable('payload', newPayload);
5462
6126
  this.navigation.execute(context);
@@ -5498,6 +6162,7 @@ class AXPShowFileUploaderPopupAction extends AXPWorkflowAction {
5498
6162
  multiple: multiple,
5499
6163
  accept: accept,
5500
6164
  fileEditable: fileEditable,
6165
+ // maxFileSize: maxFileSize,
5501
6166
  });
5502
6167
  // Handle case when result is undefined or empty array
5503
6168
  if (!res || res.length === 0) {
@@ -5587,6 +6252,57 @@ const AXPShowListViewWorkflow = {
5587
6252
  },
5588
6253
  };
5589
6254
 
6255
+ /**
6256
+ * Default widths for common text columns
6257
+ */
6258
+ const DEFAULT_COLUMN_WIDTHS = {
6259
+ title: '250px',
6260
+ description: '500px',
6261
+ note: '350px',
6262
+ notes: '350px',
6263
+ content: '500px'
6264
+ };
6265
+ /**
6266
+ * Factory to create a column width middleware using provided config map.
6267
+ * Sets width for columns defined in the map if not already defined on the column.
6268
+ */
6269
+ const columnWidthMiddlewareFactory = (widths) => {
6270
+ return (context) => {
6271
+ const columns = context.columns.list();
6272
+ if (!columns) {
6273
+ return;
6274
+ }
6275
+ columns.forEach((column) => {
6276
+ const desiredWidth = widths[column.name];
6277
+ if (desiredWidth && !column.options?.width) {
6278
+ const normalizedWidth = typeof desiredWidth === 'number' ? `${desiredWidth}px` : desiredWidth;
6279
+ context.columns.find(column.name).update((col) => ({
6280
+ ...col,
6281
+ options: {
6282
+ ...col.options,
6283
+ width: normalizedWidth
6284
+ }
6285
+ }));
6286
+ }
6287
+ });
6288
+ };
6289
+ };
6290
+ //#endregion
6291
+ //#region ---- Provider Registration ----
6292
+ /**
6293
+ * Helper to create a provider for the column width middleware.
6294
+ * By default it applies to all entities using the '*' pattern.
6295
+ */
6296
+ const createColumnWidthMiddlewareProvider = (widths, entityName = '*') => ({
6297
+ entityName,
6298
+ modifier: columnWidthMiddlewareFactory(widths)
6299
+ });
6300
+ /**
6301
+ * Default provider registered with the default map.
6302
+ */
6303
+ const columnWidthMiddlewareProvider = createColumnWidthMiddlewareProvider(DEFAULT_COLUMN_WIDTHS);
6304
+ //#endregion
6305
+
5590
6306
  function routesFacory() {
5591
6307
  const config = inject(AXP_ENTITY_CONFIG_TOKEN);
5592
6308
  let routes = [];
@@ -5675,6 +6391,11 @@ class AXPEntityModule {
5675
6391
  useClass: AXPEntityCommandSearchDefinitionProvider,
5676
6392
  multi: true,
5677
6393
  },
6394
+ {
6395
+ provide: AXP_ENTITY_MODIFIER,
6396
+ useValue: columnWidthMiddlewareProvider,
6397
+ multi: true,
6398
+ },
5678
6399
  ], imports: [RouterModule,
5679
6400
  AXPWorkflowModule.forChild({
5680
6401
  actions: {
@@ -5773,6 +6494,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
5773
6494
  useClass: AXPEntityCommandSearchDefinitionProvider,
5774
6495
  multi: true,
5775
6496
  },
6497
+ {
6498
+ provide: AXP_ENTITY_MODIFIER,
6499
+ useValue: columnWidthMiddlewareProvider,
6500
+ multi: true,
6501
+ },
5776
6502
  ],
5777
6503
  }]
5778
6504
  }], ctorParameters: () => [{ type: i1$4.AXPAppStartUpService }, { type: i0.Injector }] });
@@ -5803,6 +6529,7 @@ function entityMasterViewAction() {
5803
6529
  priority: 'secondary',
5804
6530
  type: 'view',
5805
6531
  scope: AXPEntityCommandScope.Individual,
6532
+ default: true,
5806
6533
  };
5807
6534
  }
5808
6535
  function entityMasterDeleteAction() {
@@ -5954,7 +6681,6 @@ const eventDispatchMiddleware = {
5954
6681
  target: { ops: ['create', 'update', 'delete'], order: 90 },
5955
6682
  execute: async (ctx, next) => {
5956
6683
  const dispatcher = inject(AXPEntityEventDispatcherService);
5957
- console.log(ctx);
5958
6684
  await next();
5959
6685
  if (ctx.op === 'create') {
5960
6686
  const createdData = ctx.result ? { ...ctx.data, id: ctx.result } : ctx.data;
@@ -5978,5 +6704,5 @@ const eventDispatchMiddleware = {
5978
6704
  * Generated bundle index. Do not edit.
5979
6705
  */
5980
6706
 
5981
- 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, actionExists, createModifierContext, detectEntityChanges, ensureListActions, entityDetailsCreateActions, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware };
6707
+ export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntityApplyUpdatesAction, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, DEFAULT_COLUMN_WIDTHS, actionExists, columnWidthMiddlewareFactory, columnWidthMiddlewareProvider, createColumnWidthMiddlewareProvider, createModifierContext, detectEntityChanges, ensureListActions, entityDetailsCreateActions, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware };
5982
6708
  //# sourceMappingURL=acorex-platform-layout-entity.mjs.map