@acorex/platform 20.2.3 → 20.2.4-next.0

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 (45) hide show
  1. package/common/index.d.ts +9 -2
  2. package/core/index.d.ts +42 -57
  3. package/fesm2022/acorex-platform-common.mjs +17 -9
  4. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-core.mjs +110 -158
  6. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-layout-builder.mjs +62 -50
  8. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-layout-components.mjs +170 -23
  10. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-layout-entity.mjs +1774 -988
  12. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  13. package/fesm2022/acorex-platform-layout-views.mjs +186 -51
  14. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  15. package/fesm2022/{acorex-platform-themes-default-entity-master-create-view.component-hHXxHlFG.mjs → acorex-platform-themes-default-entity-master-create-view.component-I7Eq8Nti.mjs} +3 -3
  16. package/fesm2022/{acorex-platform-themes-default-entity-master-create-view.component-hHXxHlFG.mjs.map → acorex-platform-themes-default-entity-master-create-view.component-I7Eq8Nti.mjs.map} +1 -1
  17. package/fesm2022/{acorex-platform-themes-default-entity-master-list-view.component-hf4QOz_4.mjs → acorex-platform-themes-default-entity-master-list-view.component-ezrf2oBR.mjs} +93 -176
  18. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-ezrf2oBR.mjs.map +1 -0
  19. package/fesm2022/{acorex-platform-themes-default-entity-master-modify-view.component-DC3MrDtI.mjs → acorex-platform-themes-default-entity-master-modify-view.component-16sdMBvH.mjs} +3 -10
  20. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-16sdMBvH.mjs.map +1 -0
  21. package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-Bb90PeHq.mjs → acorex-platform-themes-default-entity-master-single-view.component-D8r3S2lI.mjs} +12 -7
  22. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-D8r3S2lI.mjs.map +1 -0
  23. package/fesm2022/acorex-platform-themes-default.mjs +49 -491
  24. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  25. package/fesm2022/{acorex-platform-widgets-checkbox-widget-designer.component-BI18uzNZ.mjs → acorex-platform-widgets-checkbox-widget-designer.component-Cv7dEMCm.mjs} +2 -2
  26. package/fesm2022/acorex-platform-widgets-checkbox-widget-designer.component-Cv7dEMCm.mjs.map +1 -0
  27. package/fesm2022/{acorex-platform-widgets-tabular-data-edit-popup.component-nLZYiPnF.mjs → acorex-platform-widgets-tabular-data-edit-popup.component-BDQIfr0g.mjs} +5 -5
  28. package/fesm2022/{acorex-platform-widgets-tabular-data-edit-popup.component-nLZYiPnF.mjs.map → acorex-platform-widgets-tabular-data-edit-popup.component-BDQIfr0g.mjs.map} +1 -1
  29. package/fesm2022/{acorex-platform-widgets-tabular-data-view-popup.component-D6kiasYM.mjs → acorex-platform-widgets-tabular-data-view-popup.component-CmPqtt0G.mjs} +3 -3
  30. package/fesm2022/{acorex-platform-widgets-tabular-data-view-popup.component-D6kiasYM.mjs.map → acorex-platform-widgets-tabular-data-view-popup.component-CmPqtt0G.mjs.map} +1 -1
  31. package/fesm2022/acorex-platform-widgets.mjs +584 -102
  32. package/fesm2022/acorex-platform-widgets.mjs.map +1 -1
  33. package/layout/builder/index.d.ts +7 -3
  34. package/layout/components/index.d.ts +45 -6
  35. package/layout/entity/index.d.ts +136 -328
  36. package/layout/views/index.d.ts +64 -20
  37. package/package.json +5 -5
  38. package/themes/default/index.d.ts +1 -1
  39. package/widgets/index.d.ts +91 -4
  40. package/fesm2022/acorex-platform-themes-default-create-entity-view.component-SY0oMDoH.mjs +0 -22
  41. package/fesm2022/acorex-platform-themes-default-create-entity-view.component-SY0oMDoH.mjs.map +0 -1
  42. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-hf4QOz_4.mjs.map +0 -1
  43. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-DC3MrDtI.mjs.map +0 -1
  44. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Bb90PeHq.mjs.map +0 -1
  45. package/fesm2022/acorex-platform-widgets-checkbox-widget-designer.component-BI18uzNZ.mjs.map +0 -1
@@ -1,16 +1,16 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, Injectable, computed, signal, Injector, EnvironmentInjector, runInInjectionContext, makeEnvironmentProviders, effect, HostBinding, ChangeDetectionStrategy, Component, viewChild, ViewChild, NgModule } from '@angular/core';
2
+ import { InjectionToken, inject, Injectable, computed, signal, Injector, EnvironmentInjector, runInInjectionContext, viewChild, viewChildren, untracked, ChangeDetectionStrategy, Component, effect, HostBinding, ViewChild, NgModule } from '@angular/core';
3
3
  import { castArray, get, cloneDeep, set, merge, isNil, isEmpty, sortBy } from 'lodash-es';
4
4
  import * as i1$2 from '@acorex/cdk/common';
5
5
  import { AXDataSource, AXCommonModule } from '@acorex/cdk/common';
6
6
  import { AXFormatService } from '@acorex/core/format';
7
- import { resolveActionLook, AXPFilterOperatorMiddlewareService, AXPEntityCommandScope, getEntityInfo, AXPSettingService, AXPRefreshEvent, AXPLockService, AXPCleanNestedFilters, AXPWorkflowNavigateAction, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER } from '@acorex/platform/common';
7
+ import { resolveActionLook, AXPFilterOperatorMiddlewareService, AXPEntityCommandScope, getEntityInfo, AXPSettingService, AXPRefreshEvent, AXPReloadEvent, AXPCleanNestedFilters, AXPWorkflowNavigateAction, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER } from '@acorex/platform/common';
8
8
  import * as i1$4 from '@acorex/platform/core';
9
- import { AXPExpressionEvaluatorService, AXPPlatformScope, extractValue, setSmart } from '@acorex/platform/core';
9
+ import { AXPExpressionEvaluatorService, AXPPlatformScope, AXPDistributedEventListenerService, getSmart, getChangedPaths, extractValue, setSmart } from '@acorex/platform/core';
10
10
  import * as i2$2 from '@acorex/platform/workflow';
11
11
  import { AXPWorkflowService, ofType, createWorkFlowEvent, AXPWorkflowAction, AXPWorkflowModule } from '@acorex/platform/workflow';
12
- import * as i6 from '@acorex/platform/layout/builder';
13
- import { AXPPageStatus, AXPWidgetRegistryService, AXPValueWidgetComponent, AXPLayoutBuilderModule, AXPColumnWidgetComponent, AXPWidgetsCatalog, AXPWidgetGroupEnum, AXP_WIDGETS_EDITOR_CATEGORY, AXPLayoutWidgetComponent } from '@acorex/platform/layout/builder';
12
+ import * as i2 from '@acorex/platform/layout/builder';
13
+ import { AXPPageStatus, AXPWidgetRegistryService, AXPWidgetsCatalog, AXPValueWidgetComponent, AXPWidgetRendererDirective, AXPLayoutBuilderModule, AXPWidgetGroupEnum, AXPLayoutWidgetComponent, AXPColumnWidgetComponent, AXP_WIDGETS_EDITOR_CATEGORY } from '@acorex/platform/layout/builder';
14
14
  import { AXPLayoutThemeService } from '@acorex/platform/themes/shared';
15
15
  import { AXPSessionService, AXPAuthGuard } from '@acorex/platform/auth';
16
16
  import { Subject, takeUntil } from 'rxjs';
@@ -21,35 +21,38 @@ import { AXLoadingDialogService } from '@acorex/components/loading-dialog';
21
21
  import { AXPopupService } from '@acorex/components/popup';
22
22
  import { AXPlatform } from '@acorex/core/platform';
23
23
  import { RouterModule, ROUTES } from '@angular/router';
24
- import * as i1 from '@acorex/components/loading';
25
- import { AXLoadingModule } from '@acorex/components/loading';
26
- import * as i1$1 from '@acorex/components/badge';
27
- import { AXBadgeModule } from '@acorex/components/badge';
28
- import * as i2 from '@acorex/components/button';
24
+ import * as i3$1 from '@acorex/components/button';
29
25
  import { AXButtonModule } from '@acorex/components/button';
30
26
  import * as i3 from '@acorex/components/decorators';
31
27
  import { AXDecoratorModule } from '@acorex/components/decorators';
32
- import * as i5$1 from '@acorex/components/form';
33
- import { AXFormModule } from '@acorex/components/form';
34
- import * as i6$1 from '@acorex/components/tag-box';
35
- import { AXTagBoxComponent, AXTagBoxModule } from '@acorex/components/tag-box';
36
- import { AXValidationModule } from '@acorex/core/validation';
28
+ import * as i4 from '@acorex/components/dropdown';
29
+ import { AXDropdownModule } from '@acorex/components/dropdown';
37
30
  import * as i7 from '@angular/common';
38
31
  import { CommonModule } from '@angular/common';
32
+ import { AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_DISABLED_PROPERTY, AXP_ALLOW_CLEAR_PROPERTY, AXP_DATA_PROPERTY_GROUP, AXP_ALLOW_MULTIPLE_PROPERTY, AXPFileUploaderWidgetService } from '@acorex/platform/widgets';
39
33
  import * as i1$3 from '@angular/forms';
40
34
  import { FormsModule } from '@angular/forms';
41
- import * as i4 from '@acorex/components/data-table';
42
- import { AXDataTableModule } from '@acorex/components/data-table';
43
- import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
44
- import { AXBasePageComponent } from '@acorex/components/page';
35
+ import * as i1 from '@acorex/components/loading';
36
+ import { AXLoadingModule } from '@acorex/components/loading';
37
+ import * as i1$1 from '@acorex/components/badge';
38
+ import { AXBadgeModule } from '@acorex/components/badge';
39
+ import * as i5$1 from '@acorex/components/form';
40
+ import { AXFormModule } from '@acorex/components/form';
45
41
  import * as i5 from '@acorex/components/search-box';
46
42
  import { AXSearchBoxModule, AXSearchBoxComponent } from '@acorex/components/search-box';
47
43
  import * as i7$1 from '@acorex/components/select-box';
48
44
  import { AXSelectBoxModule } from '@acorex/components/select-box';
49
- import { AXP_DISABLED_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_DATA_PROPERTY_GROUP, AXP_ALLOW_MULTIPLE_PROPERTY, AXP_NAME_PROPERTY, AXPFileUploaderWidgetService } from '@acorex/platform/widgets';
45
+ import * as i6 from '@acorex/components/tag-box';
46
+ import { AXTagBoxComponent, AXTagBoxModule } from '@acorex/components/tag-box';
47
+ import { AXValidationModule } from '@acorex/core/validation';
48
+ import * as i4$1 from '@acorex/components/data-table';
49
+ import { AXDataTableModule } from '@acorex/components/data-table';
50
+ import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
51
+ import { AXBasePageComponent } from '@acorex/components/page';
50
52
  import * as i2$1 from '@acorex/components/text-box';
51
53
  import { AXTextBoxModule, AXTextBoxComponent } from '@acorex/components/text-box';
52
54
  import { AXPWidgetPropertyViewerComponent } from '@acorex/platform/layout/designer';
55
+ import { transform, isEqual } from 'lodash';
53
56
 
54
57
  const AXP_DATA_SEEDER_TOKEN = new InjectionToken('AXP_DATA_SEEDER_TOKEN');
55
58
  class AXPDataSeederService {
@@ -576,25 +579,97 @@ function createModifierContext(entity) {
576
579
 
577
580
  const AXP_ENTITY_MODIFIER = new InjectionToken('AXP_ENTITY_MODIFIER');
578
581
 
582
+ function ensureListActions(ctx) {
583
+ ctx.interfaces.update((i) => {
584
+ const next = i ?? {};
585
+ next.master = next.master ?? {};
586
+ next.master.list = next.master.list ?? { actions: [], views: [] };
587
+ next.master.list.actions = next.master.list.actions ?? [];
588
+ return next;
589
+ });
590
+ }
591
+ function actionExists(actions, commandName, name) {
592
+ if (!actions)
593
+ return false;
594
+ return actions.some((a) => {
595
+ const cmd = typeof a.command === 'object' ? a.command?.name : a.command;
596
+ if (name && a.name) {
597
+ return a.name === name;
598
+ }
599
+ return cmd === commandName;
600
+ });
601
+ }
602
+
603
+ const AXP_ENTITY_ACTION_PLUGIN = new InjectionToken('AXP_ENTITY_ACTION_PLUGIN');
604
+
579
605
  class AXPEntityMiddleware {
606
+ //#endregion
607
+ //#region ---- Constructor ----
580
608
  constructor() {
581
- this.modifiers = new Map();
609
+ //#region ---- Fields ----
610
+ this.exactModifiers = new Map();
611
+ this.patternModifiers = [];
582
612
  this.providedModifiers = inject(AXP_ENTITY_MODIFIER, { optional: true }) || [];
613
+ this.providedActionPlugins = inject(AXP_ENTITY_ACTION_PLUGIN, { optional: true }) || [];
583
614
  for (const { entityName, modifier } of this.providedModifiers) {
584
615
  this.register(entityName, modifier);
585
616
  }
586
617
  }
618
+ //#endregion
619
+ //#region ---- Registration Methods ----
587
620
  register(entityName, modifier) {
588
- this.modifiers.set(entityName, modifier);
621
+ if (entityName instanceof RegExp) {
622
+ this.patternModifiers.push({ pattern: this.normalizeRegExp(entityName), modifier });
623
+ return;
624
+ }
625
+ if (entityName.includes('*')) {
626
+ const pattern = this.wildcardToRegExp(entityName);
627
+ this.patternModifiers.push({ pattern, modifier });
628
+ return;
629
+ }
630
+ this.exactModifiers.set(entityName, modifier);
589
631
  }
632
+ //#endregion
633
+ //#region ---- Processing ----
590
634
  process(entity) {
591
- const modifier = this.modifiers.get(entity.name);
592
- if (!modifier)
593
- return entity;
635
+ // First, expand action plugins if entity.plugins exists
594
636
  const context = createModifierContext(entity);
637
+ const plugins = entity.plugins;
638
+ if (plugins && plugins.length) {
639
+ const sorted = [...this.providedActionPlugins].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
640
+ for (const p of plugins) {
641
+ const contrib = sorted.find((x) => x.name === p.name);
642
+ if (contrib) {
643
+ try {
644
+ contrib.apply(context, p.options);
645
+ }
646
+ catch (err) {
647
+ console.error('[AXPEntityMiddleware] action plugin failed:', p.name, err);
648
+ }
649
+ }
650
+ }
651
+ }
652
+ // Then apply entity-specific modifiers
653
+ // Exact match first
654
+ const exact = this.exactModifiers.get(entity.name);
655
+ const modifier = exact ?? this.patternModifiers.find((x) => x.pattern.test(entity.name))?.modifier;
656
+ if (!modifier) {
657
+ return context.toEntity();
658
+ }
595
659
  modifier(context);
596
660
  return context.toEntity();
597
661
  }
662
+ //#endregion
663
+ //#region ---- Helpers ----
664
+ wildcardToRegExp(pattern) {
665
+ const escaped = pattern.replace(/[.+?^${}()|\[\]\\]/g, '\\$&');
666
+ const regexStr = `^${escaped.replace(/\*/g, '.*')}$`;
667
+ return new RegExp(regexStr);
668
+ }
669
+ normalizeRegExp(rx) {
670
+ const flags = rx.flags.replace('g', '');
671
+ return new RegExp(rx.source, flags);
672
+ }
598
673
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityMiddleware, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
599
674
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityMiddleware, providedIn: 'root' }); }
600
675
  }
@@ -778,6 +853,7 @@ class AXPEntityCreateViewElementViewModel {
778
853
  children: widget.children,
779
854
  formula: widget.formula,
780
855
  triggers: widget.triggers,
856
+ defaultValue: schema.defaultValue,
781
857
  valueTransforms: widget.valueTransforms,
782
858
  options: merge(schema.interface?.options, {
783
859
  validations: this.property.validations?.map((c) => ({ rule: c.rule, message: c.message, options: c.options })),
@@ -820,22 +896,6 @@ class AXPEntityMasterCreateViewModel {
820
896
  },
821
897
  },
822
898
  };
823
- const processDefault = async (value) => {
824
- if (typeof value == 'function') {
825
- return value();
826
- }
827
- else if (typeof value == 'string' && value.startsWith('{{')) {
828
- return await this.expressionEvaluator.evaluate(value, scope);
829
- }
830
- return value;
831
- };
832
- this.config.properties
833
- .filter((c) => !isNil(c.schema.defaultValue))
834
- .forEach(async (p) => {
835
- const value = await processDefault(p.schema.defaultValue);
836
- set(initialData, p.name, value);
837
- });
838
- //
839
899
  this.context.set(initialData);
840
900
  this.options.set(commandOptions);
841
901
  //
@@ -1048,7 +1108,7 @@ class AXPEntityMasterListViewModel {
1048
1108
  return await this.expressionEvaluator.evaluate(options, scope);
1049
1109
  };
1050
1110
  this.workflow.events$
1051
- .pipe(ofType(AXPRefreshEvent))
1111
+ .pipe(ofType(AXPRefreshEvent, AXPReloadEvent))
1052
1112
  .pipe(takeUntil(this.destroyed))
1053
1113
  .subscribe((event) => {
1054
1114
  if (event.payload.entity == getEntityInfo(this.entityDef).source) {
@@ -1596,7 +1656,6 @@ class AXPEntityMasterUpdateViewModel {
1596
1656
  this.props = props;
1597
1657
  this.entityDef = cloneDeep(this.config);
1598
1658
  this.workflow = this.injector.get(AXPWorkflowService);
1599
- this.lockService = this.injector.get(AXPLockService);
1600
1659
  this.sessionService = this.injector.get(AXPSessionService);
1601
1660
  this.isInProgress = signal(false, ...(ngDevMode ? [{ debugName: "isInProgress" }] : []));
1602
1661
  this.context = signal(cloneDeep(this.entityData), ...(ngDevMode ? [{ debugName: "context" }] : []));
@@ -1606,19 +1665,6 @@ class AXPEntityMasterUpdateViewModel {
1606
1665
  return new AXPEntityMasterUpdateElementViewModel(this.entityDef, e);
1607
1666
  });
1608
1667
  }, ...(ngDevMode ? [{ debugName: "elements" }] : []));
1609
- // Lock the record on creation
1610
- if (this.entityId) {
1611
- this.lockService.lock({
1612
- refId: this.entityId,
1613
- refType: `${this.moduleName}.${this.entityName}`,
1614
- type: 'user',
1615
- date: new Date().toISOString(),
1616
- lockedBy: {
1617
- id: this.sessionService.user?.id ?? 'system',
1618
- type: 'oidc.users',
1619
- },
1620
- });
1621
- }
1622
1668
  }
1623
1669
  async save() {
1624
1670
  this.isInProgress.set(true);
@@ -1643,15 +1689,6 @@ class AXPEntityMasterUpdateViewModel {
1643
1689
  reset() {
1644
1690
  this.context.set(cloneDeep(this.entityData));
1645
1691
  }
1646
- async unlock() {
1647
- if (this.entityId) {
1648
- await this.lockService.unlock({
1649
- refId: this.entityId,
1650
- refType: `${this.moduleName}.${this.entityName}`,
1651
- type: 'user',
1652
- });
1653
- }
1654
- }
1655
1692
  }
1656
1693
  class AXPEntityMasterUpdateViewModelFactory {
1657
1694
  constructor() {
@@ -2030,6 +2067,9 @@ const AXPEntityDetailViewModelResolver = (route, state, service = inject(AXPEnti
2030
2067
  return service.create(moduleName, entityName, id);
2031
2068
  };
2032
2069
 
2070
+ const AXP_ENTITY_STORAGE_BACKEND = new InjectionToken('AXP_ENTITY_STORAGE_BACKEND');
2071
+ const AXP_ENTITY_STORAGE_MIDDLEWARE = new InjectionToken('AXP_ENTITY_STORAGE_MIDDLEWARE');
2072
+
2033
2073
  class AXPEntityStorageService {
2034
2074
  }
2035
2075
  class AXPEntityDataProvider {
@@ -2153,734 +2193,689 @@ class AXMEntityCrudServiceImpl {
2153
2193
  }
2154
2194
  }
2155
2195
 
2156
- /**
2157
- * Compose entity storage middlewares into a pipeline
2158
- */
2159
- function composeEntityStorageMiddlewares(middlewares) {
2160
- return (handler) => {
2161
- let composed = handler;
2162
- // Reverse order composition for proper middleware chain
2163
- for (let i = middlewares.length - 1; i >= 0; i--) {
2164
- const mw = middlewares[i];
2165
- const next = composed;
2166
- composed = (context) => mw(context, next);
2167
- }
2168
- return composed;
2169
- };
2170
- }
2171
- /**
2172
- * Helper function to generate unique request ID
2173
- */
2174
- function generateRequestId() {
2175
- return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
2176
- }
2177
-
2178
- /**
2179
- * Registry for managing entity storage middlewares
2180
- */
2181
- class AXPEntityStorageRegistry {
2196
+ class AXPMiddlewareEntityStorageService extends AXPEntityStorageService {
2182
2197
  constructor() {
2183
- this.globalMiddlewares = [];
2184
- this.entitySpecificMiddlewares = new Map();
2185
- this.operationSpecificMiddlewares = new Map();
2186
- }
2187
- /**
2188
- * Add a global middleware that applies to all operations
2189
- */
2190
- useGlobal(middleware) {
2191
- this.globalMiddlewares.push(middleware);
2192
- }
2193
- /**
2194
- * Add middleware for specific entity
2195
- */
2196
- useForEntity(entityName, middleware) {
2197
- if (!this.entitySpecificMiddlewares.has(entityName)) {
2198
- this.entitySpecificMiddlewares.set(entityName, []);
2199
- }
2200
- this.entitySpecificMiddlewares.get(entityName).push(middleware);
2201
- }
2202
- /**
2203
- * Add middleware for specific operation (getOne, insertOne, etc.)
2204
- */
2205
- useForOperation(operation, middleware) {
2206
- if (!this.operationSpecificMiddlewares.has(operation)) {
2207
- this.operationSpecificMiddlewares.set(operation, []);
2208
- }
2209
- this.operationSpecificMiddlewares.get(operation).push(middleware);
2210
- }
2211
- /**
2212
- * Get all applicable middlewares for a given context
2213
- */
2214
- getMiddlewares(entityName, operation) {
2215
- const middlewares = [];
2216
- // Add global middlewares
2217
- middlewares.push(...this.globalMiddlewares);
2218
- // Add entity-specific middlewares
2219
- const entityMiddlewares = this.entitySpecificMiddlewares.get(entityName);
2220
- if (entityMiddlewares) {
2221
- middlewares.push(...entityMiddlewares);
2222
- }
2223
- // Add operation-specific middlewares
2224
- const operationMiddlewares = this.operationSpecificMiddlewares.get(operation);
2225
- if (operationMiddlewares) {
2226
- middlewares.push(...operationMiddlewares);
2227
- }
2228
- return middlewares;
2229
- }
2230
- /**
2231
- * Get all global middlewares
2232
- */
2233
- getGlobalMiddlewares() {
2234
- return [...this.globalMiddlewares];
2235
- }
2236
- /**
2237
- * Remove middleware from global middlewares
2238
- */
2239
- removeGlobalMiddleware(middleware) {
2240
- const index = this.globalMiddlewares.indexOf(middleware);
2241
- if (index > -1) {
2242
- this.globalMiddlewares.splice(index, 1);
2243
- return true;
2244
- }
2245
- return false;
2246
- }
2247
- /**
2248
- * Clear all middlewares
2249
- */
2250
- clear() {
2251
- this.globalMiddlewares.length = 0;
2252
- this.entitySpecificMiddlewares.clear();
2253
- this.operationSpecificMiddlewares.clear();
2254
- }
2255
- /**
2256
- * Get registered entity names that have specific middlewares
2257
- */
2258
- getRegisteredEntityNames() {
2259
- return Array.from(this.entitySpecificMiddlewares.keys());
2260
- }
2261
- /**
2262
- * Get registered operation names that have specific middlewares
2263
- */
2264
- getRegisteredOperations() {
2265
- return Array.from(this.operationSpecificMiddlewares.keys());
2266
- }
2267
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2268
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageRegistry, providedIn: 'root' }); }
2269
- }
2270
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageRegistry, decorators: [{
2271
- type: Injectable,
2272
- args: [{ providedIn: 'root' }]
2273
- }] });
2274
-
2275
- /**
2276
- * Executor that wraps entity storage operations with middleware pipeline
2277
- */
2278
- class AXPEntityStorageExecutor {
2279
- constructor(storageService) {
2280
- this.storageService = storageService;
2198
+ super(...arguments);
2199
+ this.backend = inject(AXP_ENTITY_STORAGE_BACKEND);
2200
+ this.allMiddlewares = (inject(AXP_ENTITY_STORAGE_MIDDLEWARE, { optional: true }) || []).slice();
2281
2201
  this.injector = inject(EnvironmentInjector);
2282
- this.registry = inject(AXPEntityStorageRegistry);
2283
- }
2284
- /**
2285
- * Execute getOne operation with middleware pipeline
2286
- */
2287
- async getOne(entityName, id) {
2288
- const context = {
2289
- operation: 'getOne',
2290
- entityName,
2291
- dbName: this.storageService.dbName,
2292
- input: { id },
2293
- metadata: {
2294
- startTime: Date.now(),
2295
- requestId: generateRequestId(),
2296
- },
2297
- };
2298
- const handler = async (ctx) => {
2299
- return this.storageService.getOne(ctx.entityName, ctx.input.id);
2300
- };
2301
- return this.executeWithMiddleware(context, handler);
2302
- }
2303
- /**
2304
- * Execute getAll operation with middleware pipeline
2305
- */
2306
- async getAll(entityName) {
2307
- const context = {
2308
- operation: 'getAll',
2309
- entityName,
2310
- dbName: this.storageService.dbName,
2311
- input: {},
2312
- metadata: {
2313
- startTime: Date.now(),
2314
- requestId: generateRequestId(),
2315
- },
2316
- };
2317
- const handler = async (ctx) => {
2318
- return this.storageService.getAll(ctx.entityName);
2319
- };
2320
- return this.executeWithMiddleware(context, handler);
2321
- }
2322
- /**
2323
- * Execute insertOne operation with middleware pipeline
2324
- */
2325
- async insertOne(entityName, entity) {
2326
- const context = {
2327
- operation: 'insertOne',
2328
- entityName,
2329
- dbName: this.storageService.dbName,
2330
- input: { entity },
2331
- metadata: {
2332
- startTime: Date.now(),
2333
- requestId: generateRequestId(),
2334
- },
2335
- };
2336
- const handler = async (ctx) => {
2337
- return this.storageService.insertOne(ctx.entityName, ctx.input.entity);
2338
- };
2339
- return this.executeWithMiddleware(context, handler);
2340
- }
2341
- /**
2342
- * Execute updateOne operation with middleware pipeline
2343
- */
2344
- async updateOne(entityName, id, keyValues) {
2345
- const context = {
2346
- operation: 'updateOne',
2347
- entityName,
2348
- dbName: this.storageService.dbName,
2349
- input: { id, keyValues },
2350
- metadata: {
2351
- startTime: Date.now(),
2352
- requestId: generateRequestId(),
2353
- },
2354
- };
2355
- const handler = async (ctx) => {
2356
- return this.storageService.updateOne(ctx.entityName, ctx.input.id, ctx.input.keyValues);
2357
- };
2358
- return this.executeWithMiddleware(context, handler);
2359
- }
2360
- /**
2361
- * Execute deleteOne operation with middleware pipeline
2362
- */
2363
- async deleteOne(entityName, id) {
2364
- const context = {
2365
- operation: 'deleteOne',
2366
- entityName,
2367
- dbName: this.storageService.dbName,
2368
- input: { id },
2369
- metadata: {
2370
- startTime: Date.now(),
2371
- requestId: generateRequestId(),
2372
- },
2373
- };
2374
- const handler = async (ctx) => {
2375
- return this.storageService.deleteOne(ctx.entityName, ctx.input.id);
2376
- };
2377
- return this.executeWithMiddleware(context, handler);
2378
- }
2379
- /**
2380
- * Execute query operation with middleware pipeline
2381
- */
2382
- async query(entityName, request) {
2383
- const context = {
2384
- operation: 'query',
2385
- entityName,
2386
- dbName: this.storageService.dbName,
2387
- input: { request },
2388
- metadata: {
2389
- startTime: Date.now(),
2390
- requestId: generateRequestId(),
2391
- },
2392
- };
2393
- const handler = async (ctx) => {
2394
- return this.storageService.query(ctx.entityName, ctx.input.request);
2395
- };
2396
- return this.executeWithMiddleware(context, handler);
2397
2202
  }
2398
- /**
2399
- * Execute initial operation with middleware pipeline
2400
- */
2401
- async initial(entityName, collection, options) {
2402
- const context = {
2403
- operation: 'initial',
2203
+ get dbName() {
2204
+ return this.backend.dbName;
2205
+ }
2206
+ filterMiddlewares(ctx) {
2207
+ return this.allMiddlewares
2208
+ .filter((mw) => {
2209
+ const t = mw.target;
2210
+ if (!t)
2211
+ return true;
2212
+ if (t.ops && !t.ops.includes(ctx.op))
2213
+ return false;
2214
+ if (t.entity) {
2215
+ if (typeof t.entity === 'string' && t.entity !== ctx.entityName)
2216
+ return false;
2217
+ if (t.entity instanceof RegExp && !t.entity.test(ctx.entityName))
2218
+ return false;
2219
+ }
2220
+ if (t.predicate && !t.predicate(ctx))
2221
+ return false;
2222
+ return true;
2223
+ })
2224
+ .sort((a, b) => (a.target?.order ?? 0) - (b.target?.order ?? 0));
2225
+ }
2226
+ compose(mws, leaf, ctx) {
2227
+ return mws
2228
+ .slice()
2229
+ .reverse()
2230
+ .reduce((next, mw) => {
2231
+ return async () => runInInjectionContext(this.injector, () => mw.execute(ctx, next));
2232
+ }, leaf);
2233
+ }
2234
+ async run(ctx, delegate) {
2235
+ const chain = this.compose(this.filterMiddlewares(ctx), async () => {
2236
+ ctx.result = await delegate();
2237
+ }, ctx);
2238
+ await chain();
2239
+ return ctx.result;
2240
+ }
2241
+ createCtx(op, entityName, init) {
2242
+ return {
2243
+ op,
2404
2244
  entityName,
2405
- dbName: this.storageService.dbName,
2406
- input: { collection, options },
2407
- metadata: {
2408
- startTime: Date.now(),
2409
- requestId: generateRequestId(),
2245
+ locals: new Map(),
2246
+ backend: {
2247
+ getOneRaw: (name, id) => this.backend.getOne(name, id),
2248
+ insertOneRaw: (name, e) => this.backend.insertOne(name, e),
2410
2249
  },
2250
+ ...init,
2411
2251
  };
2412
- const handler = async (ctx) => {
2413
- return this.storageService.initial(ctx.entityName, ctx.input.collection, ctx.input.options);
2414
- };
2415
- return this.executeWithMiddleware(context, handler);
2416
- }
2417
- /**
2418
- * Execute operation with middleware pipeline
2419
- */
2420
- async executeWithMiddleware(context, handler) {
2421
- const middlewares = this.registry.getMiddlewares(context.entityName, context.operation);
2422
- // Wrap middlewares with injection context
2423
- const wrappedMiddlewares = middlewares.map(middleware => {
2424
- return (ctx, next) => runInInjectionContext(this.injector, () => middleware(ctx, next));
2425
- });
2426
- const composed = composeEntityStorageMiddlewares(wrappedMiddlewares)(handler);
2427
- return composed(context);
2428
- }
2429
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageExecutor, deps: [{ token: AXPEntityStorageService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2430
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageExecutor, providedIn: 'root' }); }
2431
- }
2432
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageExecutor, decorators: [{
2433
- type: Injectable,
2434
- args: [{ providedIn: 'root' }]
2435
- }], ctorParameters: () => [{ type: AXPEntityStorageService }] });
2436
-
2437
- /**
2438
- * Entity Storage Service with middleware support
2439
- *
2440
- * This service wraps the original AXPEntityStorageService and adds middleware pipeline support.
2441
- * It delegates all operations to the middleware executor which applies the middleware chain.
2442
- */
2443
- class AXPEntityStorageWithMiddlewareService extends AXPEntityStorageService {
2444
- constructor(originalStorageService, registry) {
2445
- super();
2446
- this.originalStorageService = originalStorageService;
2447
- this.registry = registry;
2448
- this.executor = new AXPEntityStorageExecutor(originalStorageService);
2449
- }
2450
- get dbName() {
2451
- return this.originalStorageService.dbName;
2452
- }
2453
- // Middleware Management Methods
2454
- /**
2455
- * Add a global middleware that applies to all operations
2456
- */
2457
- useGlobal(middleware) {
2458
- this.registry.useGlobal(middleware);
2459
2252
  }
2460
- /**
2461
- * Add middleware for specific entity
2462
- */
2463
- useForEntity(entityName, middleware) {
2464
- this.registry.useForEntity(entityName, middleware);
2465
- }
2466
- /**
2467
- * Add middleware for specific operation
2468
- */
2469
- useForOperation(operation, middleware) {
2470
- this.registry.useForOperation(operation, middleware);
2471
- }
2472
- // Storage Operations with Middleware Pipeline
2473
2253
  async initial(entityName, collection, options) {
2474
- return this.executor.initial(entityName, collection, options);
2254
+ const ctx = this.createCtx('initial', entityName, { data: collection });
2255
+ return this.run(ctx, () => this.backend.initial(entityName, ctx.data, options));
2475
2256
  }
2476
2257
  async getOne(entityName, id) {
2477
- return this.executor.getOne(entityName, id);
2258
+ const ctx = this.createCtx('getOne', entityName, { id });
2259
+ return this.run(ctx, () => this.backend.getOne(entityName, id));
2478
2260
  }
2479
2261
  async updateOne(entityName, id, keyValues) {
2480
- return this.executor.updateOne(entityName, id, keyValues);
2262
+ const ctx = this.createCtx('update', entityName, { id, data: keyValues });
2263
+ return this.run(ctx, () => this.backend.updateOne(entityName, id, ctx.data));
2481
2264
  }
2482
2265
  async deleteOne(entityName, id) {
2483
- return this.executor.deleteOne(entityName, id);
2266
+ const ctx = this.createCtx('delete', entityName, { id });
2267
+ return this.run(ctx, () => this.backend.deleteOne(entityName, id));
2484
2268
  }
2485
2269
  async insertOne(entityName, entity) {
2486
- return this.executor.insertOne(entityName, entity);
2270
+ const ctx = this.createCtx('create', entityName, { data: entity });
2271
+ return this.run(ctx, () => this.backend.insertOne(entityName, ctx.data));
2487
2272
  }
2488
2273
  async getAll(entityName) {
2489
- return this.executor.getAll(entityName);
2274
+ const ctx = this.createCtx('getAll', entityName);
2275
+ return this.run(ctx, () => this.backend.getAll(entityName));
2490
2276
  }
2491
2277
  async query(entityName, request) {
2492
- return this.executor.query(entityName, request);
2493
- }
2494
- // Direct access to original service (bypass middleware)
2495
- get originalService() {
2496
- return this.originalStorageService;
2497
- }
2498
- // Access to registry for advanced middleware management
2499
- get middlewareRegistry() {
2500
- return this.registry;
2278
+ const ctx = this.createCtx('query', entityName, { request });
2279
+ return this.run(ctx, () => this.backend.query(entityName, request));
2501
2280
  }
2502
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageWithMiddlewareService, deps: [{ token: AXPEntityStorageService }, { token: AXPEntityStorageRegistry }], target: i0.ɵɵFactoryTarget.Injectable }); }
2503
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageWithMiddlewareService }); }
2281
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMiddlewareEntityStorageService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
2282
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMiddlewareEntityStorageService }); }
2504
2283
  }
2505
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityStorageWithMiddlewareService, decorators: [{
2284
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPMiddlewareEntityStorageService, decorators: [{
2506
2285
  type: Injectable
2507
- }], ctorParameters: () => [{ type: AXPEntityStorageService }, { type: AXPEntityStorageRegistry }] });
2508
-
2509
- /**
2510
- * Injection token for entity storage middleware setup
2511
- */
2512
- const AXP_ENTITY_STORAGE_MIDDLEWARE_SETUP = new InjectionToken('AXP_ENTITY_STORAGE_MIDDLEWARE_SETUP');
2513
- /**
2514
- * Injection token for entity storage middleware extensions
2515
- */
2516
- const AXP_ENTITY_STORAGE_EXTENSION = new InjectionToken('AXP_ENTITY_STORAGE_EXTENSION');
2517
- /**
2518
- * Provide entity storage middleware configuration
2519
- */
2520
- function provideEntityStorageMiddleware(config) {
2521
- const providers = [];
2522
- // Register extension middlewares
2523
- if (config.extensions) {
2524
- providers.push(...config.extensions.map(ext => ({
2525
- provide: AXP_ENTITY_STORAGE_EXTENSION,
2526
- useValue: ext,
2527
- multi: true,
2528
- })));
2529
- }
2530
- // Main setup provider
2531
- providers.push({
2532
- provide: AXP_ENTITY_STORAGE_MIDDLEWARE_SETUP,
2533
- useFactory: () => {
2534
- const registry = inject(AXPEntityStorageRegistry);
2535
- // Register global middlewares
2536
- if (config.global) {
2537
- for (const middleware of config.global) {
2538
- registry.useGlobal(middleware);
2539
- }
2540
- }
2541
- // Register entity-specific middlewares
2542
- if (config.entities) {
2543
- for (const [entityName, middlewares] of Object.entries(config.entities)) {
2544
- for (const middleware of middlewares) {
2545
- registry.useForEntity(entityName, middleware);
2546
- }
2547
- }
2548
- }
2549
- // Register operation-specific middlewares
2550
- if (config.operations) {
2551
- for (const [operation, middlewares] of Object.entries(config.operations)) {
2552
- for (const middleware of middlewares) {
2553
- registry.useForOperation(operation, middleware);
2554
- }
2555
- }
2556
- }
2557
- return true;
2558
- },
2559
- multi: true,
2560
- });
2561
- return makeEnvironmentProviders(providers);
2562
- }
2563
- /**
2564
- * Simplified provider for global middleware only
2565
- */
2566
- function provideGlobalEntityStorageMiddleware(middlewares) {
2567
- return provideEntityStorageMiddleware({ global: middlewares });
2568
- }
2569
- /**
2570
- * Provider for entity-specific middlewares
2571
- */
2572
- function provideEntitySpecificMiddleware(entityName, middlewares) {
2573
- return provideEntityStorageMiddleware({
2574
- entities: { [entityName]: middlewares }
2575
- });
2576
- }
2577
- /**
2578
- * Provider for operation-specific middlewares
2579
- */
2580
- function provideOperationSpecificMiddleware(operation, middlewares) {
2581
- return provideEntityStorageMiddleware({
2582
- operations: { [operation]: middlewares }
2583
- });
2584
- }
2286
+ }] });
2585
2287
 
2586
2288
  /**
2587
- * Logging middleware for entity storage operations
2289
+ * Entity Event Dispatcher - A wrapper for entity-specific events
2290
+ * Handles pattern-based dispatching for entity operations with wildcard support
2588
2291
  */
2589
- const loggingMiddleware = async (context, next) => {
2590
- const startTime = Date.now();
2591
- console.group(`🔄 Entity Storage Operation: ${context.operation}`);
2592
- console.log('📋 Entity:', context.entityName);
2593
- console.log('🗄️ Database:', context.dbName);
2594
- console.log('📨 Input:', context.input);
2595
- console.log('🆔 Request ID:', context.metadata.requestId);
2596
- try {
2597
- const result = await next(context);
2598
- const duration = Date.now() - startTime;
2599
- console.log('✅ Success');
2600
- console.log('⏱️ Duration:', `${duration}ms`);
2601
- console.log('📤 Result:', result);
2602
- console.groupEnd();
2603
- return result;
2604
- }
2605
- catch (error) {
2606
- const duration = Date.now() - startTime;
2607
- console.error('❌ Error');
2608
- console.error('⏱️ Duration:', `${duration}ms`);
2609
- console.error('💥 Error:', error);
2610
- console.groupEnd();
2611
- throw error;
2292
+ class AXPEntityEventDispatcherService {
2293
+ constructor() {
2294
+ this.eventService = inject(AXPDistributedEventListenerService);
2612
2295
  }
2613
- };
2614
- /**
2615
- * Performance monitoring middleware
2616
- */
2617
- const performanceMiddleware = async (context, next) => {
2618
- const startTime = performance.now();
2619
- try {
2620
- const result = await next(context);
2621
- const duration = performance.now() - startTime;
2622
- // Log slow operations (> 1000ms)
2623
- if (duration > 1000) {
2624
- console.warn(`⚠️ Slow operation detected: ${context.operation} on ${context.entityName} took ${duration.toFixed(2)}ms`);
2625
- }
2626
- // Add performance metrics to context
2627
- context.metadata['performanceMetrics'] = {
2628
- duration,
2629
- operation: context.operation,
2630
- entityName: context.entityName,
2296
+ async dispatchEntityEvent(operation, entityName, data) {
2297
+ const enhancedData = {
2298
+ ...data,
2299
+ entityName,
2300
+ operation,
2301
+ timestamp: new Date(),
2302
+ source: 'entity-dispatcher',
2631
2303
  };
2632
- return result;
2633
- }
2634
- catch (error) {
2635
- const duration = performance.now() - startTime;
2636
- console.error(`❌ Failed operation: ${context.operation} on ${context.entityName} failed after ${duration.toFixed(2)}ms`);
2637
- throw error;
2638
- }
2639
- };
2640
- /**
2641
- * Error handling middleware with retry logic
2642
- */
2643
- const errorHandlingMiddleware = async (context, next) => {
2644
- const maxRetries = 3;
2645
- let attempt = 0;
2646
- while (attempt < maxRetries) {
2647
- try {
2648
- const result = await next(context);
2649
- if (attempt > 0) {
2650
- console.log(`✅ Operation succeeded on retry ${attempt}/${maxRetries}`);
2651
- }
2652
- return result;
2653
- }
2654
- catch (error) {
2655
- attempt++;
2656
- // Don't retry for certain operations or error types
2657
- if (context.operation === 'deleteOne' ||
2658
- error?.code === 'VALIDATION_ERROR' ||
2659
- attempt >= maxRetries) {
2660
- console.error(`❌ Operation failed after ${attempt} attempts:`, error);
2661
- throw error;
2304
+ const eventKeysToDispatch = await this.getAllMatchingEventKeys(operation, entityName);
2305
+ const dispatchPromises = eventKeysToDispatch.map((key) => this.eventService.dispatch(key, enhancedData));
2306
+ await Promise.all(dispatchPromises);
2307
+ }
2308
+ async getAllMatchingEventKeys(operation, entityName) {
2309
+ const eventKeys = new Set();
2310
+ const exactKeys = this.generateEventKeys(operation, entityName);
2311
+ exactKeys.forEach((key) => eventKeys.add(key));
2312
+ const wildcardKeys = await this.findMatchingWildcardKeys(operation, entityName);
2313
+ wildcardKeys.forEach((key) => eventKeys.add(key));
2314
+ return Array.from(eventKeys);
2315
+ }
2316
+ async findMatchingWildcardKeys(operation, entityName) {
2317
+ const matchingKeys = [];
2318
+ const allListenerKeys = await this.eventService.getRegisteredKeys();
2319
+ const actualEventKey = `entity.${operation}.${entityName}`;
2320
+ for (const listenerKey of allListenerKeys) {
2321
+ if (listenerKey.includes('*') && this.matchesEntityPattern(actualEventKey, listenerKey)) {
2322
+ matchingKeys.push(listenerKey);
2662
2323
  }
2663
- console.warn(`⚠️ Attempt ${attempt}/${maxRetries} failed, retrying...`, error.message);
2664
- // Wait before retry (exponential backoff)
2665
- await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
2666
2324
  }
2325
+ return matchingKeys;
2667
2326
  }
2668
- throw new Error('Max retries exceeded');
2669
- };
2670
- /**
2671
- * Validation middleware
2672
- */
2673
- const validationMiddleware = async (context, next) => {
2674
- // Validate input based on operation
2675
- switch (context.operation) {
2676
- case 'insertOne':
2677
- if (!context.input.entity) {
2678
- throw new Error('Entity is required for insertOne operation');
2679
- }
2680
- break;
2681
- case 'updateOne':
2682
- if (!context.input.id) {
2683
- throw new Error('ID is required for updateOne operation');
2684
- }
2685
- if (!context.input.keyValues) {
2686
- throw new Error('Key values are required for updateOne operation');
2687
- }
2688
- break;
2689
- case 'deleteOne':
2690
- case 'getOne':
2691
- if (!context.input.id) {
2692
- throw new Error(`ID is required for ${context.operation} operation`);
2693
- }
2694
- break;
2695
- case 'query':
2696
- if (!context.input.request) {
2697
- throw new Error('Request is required for query operation');
2698
- }
2699
- break;
2700
- case 'initial':
2701
- if (!context.input.collection || !Array.isArray(context.input.collection)) {
2702
- throw new Error('Collection array is required for initial operation');
2703
- }
2704
- break;
2705
- }
2706
- return next(context);
2707
- };
2708
- /**
2709
- * Caching middleware (simple in-memory cache)
2710
- */
2711
- const cachingMiddleware = (() => {
2712
- const cache = new Map();
2713
- const DEFAULT_TTL = 5 * 60 * 1000; // 5 minutes
2714
- return async (context, next) => {
2715
- // Only cache read operations
2716
- if (!['getOne', 'getAll', 'query'].includes(context.operation)) {
2717
- // Clear cache for write operations on the same entity
2718
- const keysToDelete = Array.from(cache.keys()).filter(key => key.includes(`${context.entityName}:`));
2719
- keysToDelete.forEach(key => cache.delete(key));
2720
- return next(context);
2327
+ matchesEntityPattern(eventKey, pattern) {
2328
+ if (!pattern.startsWith('entity.') || !pattern.includes('*')) {
2329
+ return false;
2721
2330
  }
2722
- // Generate cache key
2723
- const cacheKey = `${context.entityName}:${context.operation}:${JSON.stringify(context.input)}`;
2724
- // Check cache
2725
- const cached = cache.get(cacheKey);
2726
- if (cached && Date.now() - cached.timestamp < cached.ttl) {
2727
- console.log(`💾 Cache hit for ${cacheKey}`);
2728
- return cached.data;
2331
+ const regexPattern = pattern.replace(/\./g, '\\.').replace(/\*/g, '.*');
2332
+ const regex = new RegExp(`^${regexPattern}$`);
2333
+ return regex.test(eventKey);
2334
+ }
2335
+ generateEventKeys(operation, entityName) {
2336
+ const keys = [];
2337
+ keys.push(`entity.${operation}`);
2338
+ keys.push(`entity.${operation}.${entityName}`);
2339
+ const entityParts = entityName.split('.');
2340
+ if (entityParts.length > 1) {
2341
+ const moduleName = entityParts[0];
2342
+ keys.push(`entity.${operation}.${moduleName}`);
2729
2343
  }
2730
- // Execute and cache result
2731
- const result = await next(context);
2732
- cache.set(cacheKey, {
2733
- data: result,
2734
- timestamp: Date.now(),
2735
- ttl: DEFAULT_TTL,
2736
- });
2737
- console.log(`💾 Cached result for ${cacheKey}`);
2738
- return result;
2739
- };
2740
- })();
2741
-
2742
- /**
2743
- * Simple in-memory audit storage (for demo purposes)
2744
- */
2745
- class InMemoryAuditStorage {
2746
- constructor() {
2747
- this.entries = [];
2748
- }
2749
- async save(entry) {
2750
- this.entries.push(entry);
2751
- console.log('📋 Audit entry saved:', entry);
2344
+ return keys;
2752
2345
  }
2753
- getEntries() {
2754
- return [...this.entries];
2346
+ async dispatchInserted(entityName, data) {
2347
+ await this.dispatchEntityEvent('inserted', entityName, data);
2755
2348
  }
2756
- getEntriesForEntity(entityName) {
2757
- return this.entries.filter(entry => entry.entityName === entityName);
2349
+ async dispatchUpdated(entityName, data) {
2350
+ await this.dispatchEntityEvent('updated', entityName, data);
2758
2351
  }
2759
- clear() {
2760
- this.entries.length = 0;
2352
+ async dispatchDeleted(entityName, data) {
2353
+ await this.dispatchEntityEvent('deleted', entityName, data);
2761
2354
  }
2355
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityEventDispatcherService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2356
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityEventDispatcherService, providedIn: 'root' }); }
2762
2357
  }
2763
- // Global audit storage instance
2764
- const auditStorage = new InMemoryAuditStorage();
2765
- /**
2766
- * Audit middleware that tracks all entity operations
2767
- */
2768
- const auditMiddleware = async (context, next) => {
2769
- const auditEntry = {
2770
- id: `audit_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
2771
- entityName: context.entityName,
2772
- operation: context.operation,
2773
- user: context.metadata.user?.id || 'system',
2774
- timestamp: new Date(),
2775
- requestId: context.metadata.requestId,
2358
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityEventDispatcherService, decorators: [{
2359
+ type: Injectable,
2360
+ args: [{
2361
+ providedIn: 'root',
2362
+ }]
2363
+ }] });
2364
+
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) ?? [];
2776
2379
  };
2777
- // Add operation-specific data
2778
- switch (context.operation) {
2779
- case 'insertOne':
2780
- auditEntry.changes = { created: context.input.entity };
2781
- break;
2782
- case 'updateOne':
2783
- auditEntry.entityId = context.input.id;
2784
- auditEntry.changes = { updated: context.input.keyValues };
2785
- break;
2786
- case 'deleteOne':
2787
- auditEntry.entityId = context.input.id;
2788
- auditEntry.changes = { deleted: true };
2789
- break;
2790
- case 'getOne':
2791
- auditEntry.entityId = context.input.id;
2792
- break;
2793
- case 'query':
2794
- auditEntry.metadata = { queryRequest: context.input.request };
2795
- break;
2796
- case 'initial':
2797
- auditEntry.metadata = {
2798
- collectionSize: context.input.collection?.length,
2799
- options: context.input.options
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: {
2388
+ commands: {
2389
+ reject: {
2390
+ title: 't("discard")',
2391
+ color: 'default',
2392
+ visible: '{{context.isDirty()}}',
2393
+ command: {
2394
+ name: 'discard',
2395
+ },
2396
+ },
2397
+ accept: {
2398
+ title: 't("confirm")',
2399
+ color: 'secondary',
2400
+ visible: '{{context.isDirty()}}',
2401
+ command: {
2402
+ name: 'update-entity',
2403
+ },
2404
+ },
2405
+ },
2406
+ },
2407
+ load: async (context) => {
2408
+ const fn = entityDef?.queries.byKey?.execute;
2409
+ const conditionNames = relatedEntity.conditions?.map((c) => c.name) ?? [];
2410
+ const id = getSmart(context, conditionNames[0]);
2411
+ const result = await fn(id);
2412
+ return {
2413
+ success: true,
2414
+ result: result,
2800
2415
  };
2801
- break;
2802
- }
2803
- try {
2804
- const result = await next(context);
2805
- // For insert operations, capture the generated ID
2806
- if (context.operation === 'insertOne' && result) {
2807
- auditEntry.entityId = result;
2808
- }
2809
- // Save audit entry
2810
- await auditStorage.save(auditEntry);
2811
- return result;
2812
- }
2813
- catch (error) {
2814
- // Save audit entry even for failed operations
2815
- auditEntry.metadata = {
2816
- ...auditEntry.metadata,
2817
- error: error instanceof Error ? error.message : 'Unknown error'
2818
- };
2819
- await auditStorage.save(auditEntry);
2820
- throw error;
2821
- }
2822
- };
2823
- /**
2824
- * User context middleware - adds user information to context
2825
- */
2826
- const userContextMiddleware = async (context, next) => {
2827
- // In a real application, you would inject your auth service here
2828
- // const authService = inject(AuthService);
2829
- // const user = authService.getCurrentUser();
2830
- // For demo purposes, we'll use a mock user
2831
- const mockUser = {
2832
- id: 'user123',
2833
- name: 'John Doe',
2834
- role: 'admin',
2416
+ },
2417
+ execute: async (e, context) => {
2418
+ if (e.name == 'update-entity') {
2419
+ const fn = entityDef?.commands?.update?.execute;
2420
+ const result = await fn(context);
2421
+ return {
2422
+ success: true,
2423
+ result: result,
2424
+ };
2425
+ }
2426
+ else {
2427
+ return {
2428
+ success: false,
2429
+ error: {
2430
+ code: 'invalid_command',
2431
+ message: 'Invalid command',
2432
+ },
2433
+ };
2434
+ }
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
+ },
2447
+ },
2448
+ },
2449
+ children: singleInterface?.sections.map((s) => {
2450
+ console.log('s', s);
2451
+ 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,
2458
+ },
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
+ };
2517
+ }),
2518
+ },
2519
+ ],
2835
2520
  };
2836
- context.metadata.user = mockUser;
2837
- return next(context);
2838
- };
2839
- /**
2840
- * Data sanitization middleware - removes sensitive data from logs
2841
- */
2842
- const dataSanitizationMiddleware = async (context, next) => {
2843
- const sensitiveFields = ['password', 'ssn', 'creditCard', 'apiKey', 'token'];
2844
- // Sanitize input data
2845
- if (context.input.entity) {
2846
- context.input.entity = sanitizeObject(context.input.entity, sensitiveFields);
2847
- }
2848
- if (context.input.keyValues) {
2849
- context.input.keyValues = sanitizeObject(context.input.keyValues, sensitiveFields);
2850
- }
2851
- const result = await next(context);
2852
- // Sanitize result data if needed
2853
- if (result && typeof result === 'object') {
2854
- return sanitizeObject(result, sensitiveFields);
2855
- }
2856
- return result;
2857
- };
2858
- /**
2859
- * Helper function to sanitize objects by removing sensitive fields
2860
- */
2861
- function sanitizeObject(obj, sensitiveFields) {
2862
- if (!obj || typeof obj !== 'object') {
2863
- return obj;
2864
- }
2865
- if (Array.isArray(obj)) {
2866
- return obj.map(item => sanitizeObject(item, sensitiveFields));
2867
- }
2868
- const sanitized = { ...obj };
2869
- for (const field of sensitiveFields) {
2870
- if (field in sanitized) {
2871
- sanitized[field] = '[REDACTED]';
2872
- }
2521
+ }
2522
+
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`);
2873
2529
  }
2874
- // Recursively sanitize nested objects
2875
- for (const [key, value] of Object.entries(sanitized)) {
2876
- if (value && typeof value === 'object') {
2877
- sanitized[key] = sanitizeObject(value, sensitiveFields);
2878
- }
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,
2540
+ },
2541
+ },
2542
+ ],
2543
+ };
2544
+ }
2545
+
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',
2578
+ },
2579
+ },
2580
+ },
2581
+ children: singleInterface?.sections.map((s) => {
2582
+ console.log('s', s);
2583
+ return {
2584
+ type: 'grid-item-layout',
2585
+ name: s.id,
2586
+ options: {
2587
+ colSpan: s.layout?.positions?.lg?.colSpan ?? 12,
2588
+ colStart: s.layout?.positions?.lg?.colStart,
2589
+ colEnd: s.layout?.positions?.lg?.colEnd,
2590
+ },
2591
+ children: [
2592
+ {
2593
+ type: 'fieldset-layout',
2594
+ options: {
2595
+ title: getGroupById(s.id)?.title ?? '',
2596
+ collapsible: true,
2597
+ },
2598
+ children: [
2599
+ {
2600
+ type: 'grid-layout',
2601
+ options: {
2602
+ grid: {
2603
+ default: {
2604
+ gridTemplateColumns: 'repeat(12, 1fr)',
2605
+ gridTemplateRows: 'repeat(1, 1fr)',
2606
+ gap: '20px',
2607
+ },
2608
+ },
2609
+ },
2610
+ children: getPropertyByGroupId(s.id)
2611
+ .filter((property) => !property.schema.hidden)
2612
+ .map((p) => {
2613
+ const layout = getPropertyLayout(p.name);
2614
+ return {
2615
+ type: 'grid-item-layout',
2616
+ name: p.name,
2617
+ options: {
2618
+ colSpan: layout?.positions?.lg?.colSpan ?? 12,
2619
+ colStart: layout?.positions?.lg?.colStart,
2620
+ colEnd: layout?.positions?.lg?.colEnd,
2621
+ },
2622
+ children: [
2623
+ {
2624
+ type: 'form-field',
2625
+ options: {
2626
+ label: p.title,
2627
+ },
2628
+ children: [
2629
+ {
2630
+ type: p.schema.interface?.type ?? '',
2631
+ path: p.name,
2632
+ name: p.name,
2633
+ defaultValue: p.schema.defaultValue,
2634
+ children: p.schema.interface?.children,
2635
+ options: p.schema.interface?.options,
2636
+ triggers: p.schema.interface?.triggers,
2637
+ valueTransforms: p.schema.interface?.valueTransforms,
2638
+ },
2639
+ ],
2640
+ },
2641
+ ],
2642
+ };
2643
+ }),
2644
+ },
2645
+ ],
2646
+ },
2647
+ ],
2648
+ };
2649
+ }),
2650
+ },
2651
+ ],
2652
+ };
2653
+ }
2654
+
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`);
2879
2661
  }
2880
- return sanitized;
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
+ };
2881
2676
  }
2882
2677
 
2883
- // Core middleware types and utilities
2678
+ const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver = inject(AXPEntityResolver), session = inject(AXPSessionService)) => {
2679
+ const moduleName = route.parent?.paramMap.get('module');
2680
+ const entityName = route.paramMap.get('entity');
2681
+ const entity = await entityResolver.get(moduleName, entityName);
2682
+ 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
+ ],
2871
+ };
2872
+ //
2873
+ return new Promise((resolve) => {
2874
+ setTimeout(() => {
2875
+ resolve(adapter);
2876
+ }, 200);
2877
+ });
2878
+ };
2884
2879
 
2885
2880
  class AXPEntityCommandSearchDefinitionProvider {
2886
2881
  async provide(context) {
@@ -2922,7 +2917,849 @@ class AXPEntitySearchDefinitionProvider {
2922
2917
  });
2923
2918
  });
2924
2919
  }
2925
- }
2920
+ }
2921
+
2922
+ class AXPEntityListConverterService {
2923
+ constructor() {
2924
+ //#region ---- Services & Dependencies ----
2925
+ this.entityResolver = inject(AXPEntityResolver);
2926
+ this.workflow = inject(AXPWorkflowService);
2927
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
2928
+ this.widgetResolver = inject(AXPWidgetRegistryService);
2929
+ this.evaluateExpressions = async (options, data) => {
2930
+ const scope = {
2931
+ context: {
2932
+ eval: (path) => {
2933
+ return get(data, path);
2934
+ },
2935
+ },
2936
+ };
2937
+ return await this.expressionEvaluator.evaluate(options, scope);
2938
+ };
2939
+ }
2940
+ //#endregion
2941
+ //#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
+ /**
2951
+ * Convert Entity to List Widget Options
2952
+ */
2953
+ async convertEntityToListOptions(entity, options) {
2954
+ const allActions = entity.interfaces?.master?.list?.actions?.map((tr) => new AXPEntityCommandTriggerViewModel(entity, tr)) ?? [];
2955
+ const listOptions = {
2956
+ // 📊 Data Source
2957
+ dataSource: this.createDataSource(entity),
2958
+ // 📋 Columns from Properties
2959
+ columns: this.createColumnsFromProperties(entity, options),
2960
+ // 🎯 Row Commands from Actions
2961
+ primaryCommands: this.createRowCommands(allActions, 'primary'),
2962
+ secondaryCommands: this.createRowCommands(allActions, 'secondary'),
2963
+ // ⚙️ Table Features
2964
+ showIndex: entity.interfaces?.master?.list?.views?.[0]?.indexCol ?? false,
2965
+ allowSelection: this.hasSelectedScopeActions(entity),
2966
+ paging: true,
2967
+ showHeader: true,
2968
+ showFooter: false,
2969
+ // 🔗 Entity Configuration
2970
+ parentField: entity.parentKey,
2971
+ // 🎪 Events
2972
+ ...this.createDefaultEvents(entity, allActions),
2973
+ };
2974
+ return listOptions;
2975
+ }
2976
+ //#endregion
2977
+ //#region ---- Private Methods ----
2978
+ /**
2979
+ * Create DataSource for Entity
2980
+ */
2981
+ createDataSource(entity) {
2982
+ return new AXDataSource({
2983
+ byKey: (key) => {
2984
+ const func = entity.queries.byKey.execute;
2985
+ return func(key);
2986
+ },
2987
+ load: (e) => {
2988
+ const func = entity.queries.list?.execute;
2989
+ if (!func) {
2990
+ throw new Error(`Entity ${entity.name} does not have a list query`);
2991
+ }
2992
+ return func(e);
2993
+ },
2994
+ pageSize: entity.interfaces?.master?.list?.views?.[0]?.pageSize || 10,
2995
+ key: 'id',
2996
+ });
2997
+ }
2998
+ /**
2999
+ * Convert Properties to Columns
3000
+ */
3001
+ createColumnsFromProperties(entity, options) {
3002
+ const excludeColumns = options?.excludeColumns || [];
3003
+ const includeColumns = options?.includeColumns || [];
3004
+ let columns = [];
3005
+ // If columns are defined, use them
3006
+ if (entity.columns && entity.columns.length > 0) {
3007
+ columns = entity.columns.map((col) => this.mapEntityColumnToWidgetColumn(entity, col));
3008
+ }
3009
+ else {
3010
+ // Otherwise use properties
3011
+ columns = entity.properties
3012
+ .filter((prop) => !prop.schema.hidden) // Only visible properties
3013
+ .map((prop) => ({
3014
+ name: prop.name,
3015
+ title: prop.title,
3016
+ visible: true,
3017
+ widget: prop.schema.interface
3018
+ ? {
3019
+ type: prop.schema.interface.type || 'text-editor',
3020
+ path: prop.name,
3021
+ options: {
3022
+ readonly: true,
3023
+ ...prop.schema.interface.options,
3024
+ },
3025
+ }
3026
+ : {
3027
+ type: 'text-editor',
3028
+ path: prop.name,
3029
+ options: { readonly: true },
3030
+ },
3031
+ }));
3032
+ }
3033
+ // Apply include/exclude filters
3034
+ if (includeColumns.length > 0) {
3035
+ // If includeColumns is specified, only include those columns
3036
+ columns = columns.filter((col) => includeColumns.includes(col.name));
3037
+ }
3038
+ if (excludeColumns.length > 0) {
3039
+ // If excludeColumns is specified, exclude those columns
3040
+ columns = columns.filter((col) => !excludeColumns.includes(col.name));
3041
+ }
3042
+ return columns;
3043
+ }
3044
+ /**
3045
+ * Map EntityTableColumn to ListWidgetColumn
3046
+ */
3047
+ mapEntityColumnToWidgetColumn(entity, column) {
3048
+ // Find corresponding property
3049
+ const property = entity.properties.find((p) => p.name === column.name);
3050
+ return {
3051
+ name: column.name,
3052
+ title: column.title || property?.title || column.name,
3053
+ width: column.options?.width,
3054
+ visible: column.options?.visible !== false,
3055
+ widget: property?.schema.interface
3056
+ ? {
3057
+ type: property.schema.interface.type || 'text-editor',
3058
+ path: column.options?.dataPath || column.name,
3059
+ options: {
3060
+ readonly: true,
3061
+ ...property.schema.interface.options,
3062
+ },
3063
+ }
3064
+ : {
3065
+ type: 'text-editor',
3066
+ path: column.options?.dataPath || column.name,
3067
+ options: { readonly: true },
3068
+ },
3069
+ };
3070
+ }
3071
+ /**
3072
+ * Convert Entity Actions to Row Commands
3073
+ */
3074
+ createRowCommands(actions, priority) {
3075
+ return actions
3076
+ .filter((action) => action.scope === AXPEntityCommandScope.Individual && // Only individual actions
3077
+ action.priority === priority && // Matching priority
3078
+ !action.hidden)
3079
+ .map((action) => ({
3080
+ name: action.name,
3081
+ text: action.title,
3082
+ icon: action.icon,
3083
+ color: action.color,
3084
+ look: 'outline',
3085
+ visible: action.hidden,
3086
+ disabled: action.disabled,
3087
+ }));
3088
+ }
3089
+ /**
3090
+ * Check if entity has Selected Scope Actions
3091
+ */
3092
+ hasSelectedScopeActions(entity) {
3093
+ const actions = entity.interfaces?.master?.list?.actions || [];
3094
+ return actions.some((action) => action.scope === AXPEntityCommandScope.Selected);
3095
+ }
3096
+ /**
3097
+ * Create default events
3098
+ */
3099
+ createDefaultEvents(entity, allActions) {
3100
+ return {
3101
+ onRowClick: (row) => {
3102
+ console.log('Entity List - Row clicked:', row);
3103
+ },
3104
+ onRowDoubleClick: (row) => {
3105
+ console.log('Entity List - Row double clicked:', row);
3106
+ },
3107
+ onSelectionChange: (selectedRows) => {
3108
+ console.log('Entity List - Selection changed:', selectedRows);
3109
+ },
3110
+ onRowCommand: async (e, selectedRows) => {
3111
+ const data = e.data;
3112
+ const commandName = e.name;
3113
+ const action = allActions.find((c) => {
3114
+ return (c.name == e.name &&
3115
+ ((selectedRows?.length
3116
+ ? c.scope == AXPEntityCommandScope.Selected
3117
+ : c.scope == AXPEntityCommandScope.Individual) ||
3118
+ c.scope == AXPEntityCommandScope.TypeLevel));
3119
+ });
3120
+ const command = commandName.split('&')[0];
3121
+ const options = await this.evaluateExpressions(action?.options, data);
3122
+ await this.workflow.execute(command, {
3123
+ entity: getEntityInfo(entity).source,
3124
+ entityInfo: {
3125
+ name: entity.name,
3126
+ module: entity.module,
3127
+ title: entity.title,
3128
+ parentKey: entity.parentKey,
3129
+ source: entity.source,
3130
+ },
3131
+ data: action?.scope == AXPEntityCommandScope.Selected ? selectedRows : data,
3132
+ options: options,
3133
+ metadata: action?.metadata,
3134
+ });
3135
+ console.log('Entity List - Row command:', e.name, e.data);
3136
+ },
3137
+ };
3138
+ }
3139
+ createFilterDefinitions(entity) {
3140
+ const props = entity.properties.filter((c) => c.options?.filter?.advance?.enabled || c.options?.filter?.inline?.enabled);
3141
+ return props.map((e) => {
3142
+ const widgetConfig = this.widgetResolver.resolve(e.schema.interface?.type);
3143
+ const type = (e.options?.filter?.advance?.widgetType ||
3144
+ widgetConfig?.defaultFilterWidgetName ||
3145
+ e.schema.interface?.type);
3146
+ return {
3147
+ title: e.title,
3148
+ field: e.name,
3149
+ operator: {
3150
+ type: 'contains',
3151
+ },
3152
+ widget: { ...e.schema.interface, path: e.name, type },
3153
+ filters: [],
3154
+ isParametric: false,
3155
+ icon: widgetConfig?.icon,
3156
+ filterType: {
3157
+ advance: e.options?.filter?.advance?.enabled ?? false,
3158
+ inline: e.options?.filter?.inline?.enabled ?? false,
3159
+ },
3160
+ };
3161
+ });
3162
+ }
3163
+ createColumnDefinitions(entity, options) {
3164
+ const { columns = [], properties } = entity;
3165
+ const excludeColumns = options?.excludeColumns || [];
3166
+ const includeColumns = options?.includeColumns || [];
3167
+ const visibleProperties = properties.filter(({ schema }) => !schema?.hidden);
3168
+ const visiblePropNames = new Set(visibleProperties.map(({ name }) => name));
3169
+ let filteredColumns = columns.filter(({ name }) => visiblePropNames.has(name));
3170
+ // Apply include/exclude filters
3171
+ if (includeColumns.length > 0) {
3172
+ // If includeColumns is specified, only include those columns
3173
+ filteredColumns = filteredColumns.filter((col) => includeColumns.includes(col.name));
3174
+ }
3175
+ if (excludeColumns.length > 0) {
3176
+ // If excludeColumns is specified, exclude those columns
3177
+ filteredColumns = filteredColumns.filter((col) => !excludeColumns.includes(col.name));
3178
+ }
3179
+ return filteredColumns.map((column) => {
3180
+ const property = visibleProperties.find(({ name }) => name === column.name);
3181
+ return {
3182
+ name: column.name,
3183
+ title: property?.title,
3184
+ visible: column?.options?.visible ?? true,
3185
+ };
3186
+ });
3187
+ }
3188
+ createSortDefinitions(entity) {
3189
+ const props = entity.properties.filter((c) => c.options?.sort?.enabled);
3190
+ return props.map((e) => {
3191
+ return {
3192
+ name: e.name,
3193
+ title: e.title,
3194
+ };
3195
+ });
3196
+ }
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 }); }
3199
+ }
3200
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListConverterService, decorators: [{
3201
+ type: Injectable
3202
+ }] });
3203
+
3204
+ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
3205
+ constructor() {
3206
+ super(...arguments);
3207
+ this.entityResolver = inject(AXPEntityResolver);
3208
+ this.workflow = inject(AXPWorkflowService);
3209
+ this.entityListService = inject(AXPEntityListConverterService);
3210
+ this.layoutThemeService = inject(AXPLayoutThemeService);
3211
+ this.entity = signal(null, ...(ngDevMode ? [{ debugName: "entity" }] : []));
3212
+ this.listNode = signal(null, ...(ngDevMode ? [{ debugName: "listNode" }] : []));
3213
+ this.list = viewChild('list', ...(ngDevMode ? [{ debugName: "list" }] : []));
3214
+ this.allWidgets = viewChildren(AXPWidgetRendererDirective, ...(ngDevMode ? [{ debugName: "allWidgets" }] : []));
3215
+ this.listWidget = computed(() => this.allWidgets().find((widget) => widget.node()?.type === AXPWidgetsCatalog.list), ...(ngDevMode ? [{ debugName: "listWidget" }] : []));
3216
+ 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" }] : []));
3218
+ this.toolbarNode = signal(null, ...(ngDevMode ? [{ debugName: "toolbarNode" }] : []));
3219
+ this.destroyed = new Subject();
3220
+ //options
3221
+ this.entitySource = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entitySource" }] : []));
3222
+ this.excludeColumns = computed(() => this.options()['excludeColumns'], ...(ngDevMode ? [{ debugName: "excludeColumns" }] : []));
3223
+ this.includeColumns = computed(() => this.options()['includeColumns'], ...(ngDevMode ? [{ debugName: "includeColumns" }] : []));
3224
+ //actions
3225
+ this.allActions = computed(() => {
3226
+ const list = this.entity()?.interfaces?.master?.list?.actions ?? [];
3227
+ return list.map((tr) => new AXPEntityCommandTriggerViewModel(this.entity(), tr)) ?? [];
3228
+ }, ...(ngDevMode ? [{ debugName: "allActions" }] : []));
3229
+ this.primaryActions = computed(() => {
3230
+ const actions = this.allActions()
3231
+ .filter((a) => a.priority == 'primary' &&
3232
+ ((a.scope == AXPEntityCommandScope.Selected && this.selectedItems().length) ||
3233
+ (a.scope == AXPEntityCommandScope.TypeLevel && !this.selectedItems().length)))
3234
+ .map((tr) => ({
3235
+ name: tr.name,
3236
+ title: tr.title,
3237
+ icon: tr.icon,
3238
+ color: tr.color,
3239
+ disabled: tr.disabled,
3240
+ command: {
3241
+ name: tr.name,
3242
+ options: tr.options,
3243
+ metadata: tr.metadata,
3244
+ },
3245
+ }));
3246
+ return actions;
3247
+ }, ...(ngDevMode ? [{ debugName: "primaryActions" }] : []));
3248
+ this.secondaryActions = computed(() => {
3249
+ const actions = this.allActions()
3250
+ .filter((a) => a.priority == 'secondary' && a.scope == AXPEntityCommandScope.TypeLevel)
3251
+ .map((tr) => ({
3252
+ name: tr.name,
3253
+ title: tr.title,
3254
+ icon: tr.icon,
3255
+ color: tr.color,
3256
+ disabled: tr.disabled,
3257
+ separated: tr.separated,
3258
+ command: {
3259
+ name: tr.name,
3260
+ options: tr.options,
3261
+ metadata: tr.metadata,
3262
+ },
3263
+ }));
3264
+ return actions;
3265
+ }, ...(ngDevMode ? [{ debugName: "secondaryActions" }] : []));
3266
+ this.context = {};
3267
+ this.previousQueries = null;
3268
+ }
3269
+ handleActionClick(item) {
3270
+ if (item.command && (item.items?.length ?? 0) == 0) {
3271
+ this.execute(item.command.name, null);
3272
+ }
3273
+ }
3274
+ handleSecondaryActionClick(item) {
3275
+ if (item.command) {
3276
+ this.execute(item.command.name, null);
3277
+ }
3278
+ }
3279
+ async execute(commandName, data) {
3280
+ const action = this.allActions().find((c) => {
3281
+ return (c.name == commandName &&
3282
+ ((this.selectedItems().length
3283
+ ? c.scope == AXPEntityCommandScope.Selected
3284
+ : c.scope == AXPEntityCommandScope.Individual) ||
3285
+ c.scope == AXPEntityCommandScope.TypeLevel));
3286
+ });
3287
+ const command = commandName.split('&')[0];
3288
+ // const options = await this.evaluateExpressions(action?.options, data);
3289
+ await this.workflow.execute(command, {
3290
+ entity: this.entitySource(),
3291
+ entityInfo: {
3292
+ name: this.entity()?.name,
3293
+ module: this.entity()?.module,
3294
+ title: this.entity()?.title,
3295
+ parentKey: this.entity()?.parentKey,
3296
+ source: this.entity()?.source,
3297
+ },
3298
+ data: action?.scope == AXPEntityCommandScope.Selected ? this.selectedItems() : data,
3299
+ options: action?.options,
3300
+ metadata: action?.metadata,
3301
+ });
3302
+ }
3303
+ onContextChanged(context) {
3304
+ const queries = context.data.list.toolbar;
3305
+ 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');
3323
+ }
3324
+ // if(isColumnsChanged){
3325
+ // }
3326
+ });
3327
+ }
3328
+ async ngOnInit() {
3329
+ super.ngOnInit();
3330
+ const [moduleName, entityName] = this.entitySource().split('.');
3331
+ if (!moduleName || !entityName) {
3332
+ throw new Error('Invalid entity source');
3333
+ }
3334
+ // Resolve entity and set it in the signal
3335
+ const resolvedEntity = await this.entityResolver.get(moduleName, entityName);
3336
+ if (!resolvedEntity) {
3337
+ throw new Error(`Entity not found: ${this.entitySource()}`);
3338
+ }
3339
+ this.entity.set(resolvedEntity);
3340
+ const options = {
3341
+ excludeColumns: this.excludeColumns(),
3342
+ includeColumns: this.includeColumns(),
3343
+ };
3344
+ const listOptions = await this.entityListService.convertEntityToListOptions(resolvedEntity, options);
3345
+ const toolbarOptions = await this.entityListService.convertEntityToolbarOptions(resolvedEntity, options);
3346
+ this.listNode.set({
3347
+ type: AXPWidgetsCatalog.list,
3348
+ options: listOptions,
3349
+ path: `table`,
3350
+ mode: 'view',
3351
+ defaultValue: this.getValue(),
3352
+ });
3353
+ this.toolbarNode.set({
3354
+ type: AXPWidgetsCatalog.listToolbar,
3355
+ path: `toolbar`,
3356
+ options: toolbarOptions,
3357
+ mode: 'view',
3358
+ defaultValue: this.getValue(),
3359
+ });
3360
+ }
3361
+ ngAfterViewInit() {
3362
+ this.workflow.events$
3363
+ .pipe(ofType(AXPRefreshEvent))
3364
+ .pipe(takeUntil(this.destroyed))
3365
+ .subscribe((event) => {
3366
+ if (event.payload.entity == this.entitySource()) {
3367
+ this.listWidget()?.instance.call('refresh');
3368
+ }
3369
+ });
3370
+ }
3371
+ destroy() {
3372
+ this.destroyed.next();
3373
+ this.destroyed.complete();
3374
+ }
3375
+ 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)">
3378
+ <div class="ax-flex ax-gap-2 ax-justify-end ax-mb-4">
3379
+ @for (action of primaryActions(); track $index) {
3380
+ @if (action.visible != false) {
3381
+ <ax-button
3382
+ [class.ax-sm]="layoutThemeService.isSmall()"
3383
+ [iconOnly]="layoutThemeService.isSmall()"
3384
+ [disabled]="action.disabled"
3385
+ [text]="action.title"
3386
+ [look]="'solid'"
3387
+ [color]="action.color"
3388
+ (onClick)="handleActionClick(action)"
3389
+ >
3390
+ <ax-prefix>
3391
+ <i class="{{ action.icon }}"></i>
3392
+ </ax-prefix>
3393
+ @if (action?.items) {
3394
+ <ax-dropdown-panel #panel>
3395
+ <ax-button-item-list>
3396
+ @for (sub of action?.items; track $index) {
3397
+ @if (sub.visible != false) {
3398
+ <ax-button-item
3399
+ [text]="sub.title"
3400
+ [color]="sub.color"
3401
+ [disabled]="sub.disabled"
3402
+ (onClick)="handleActionClick(sub)"
3403
+ >
3404
+ <ax-prefix>
3405
+ <ax-icon icon="fa-light {{ sub.icon }}"></ax-icon>
3406
+ </ax-prefix>
3407
+ </ax-button-item>
3408
+ @if (sub.break) {
3409
+ <ax-divider></ax-divider>
3410
+ }
3411
+ }
3412
+ }
3413
+ </ax-button-item-list>
3414
+ </ax-dropdown-panel>
3415
+ }
3416
+ </ax-button>
3417
+ }
3418
+ }
3419
+ @if (secondaryActions().length) {
3420
+ <ax-button
3421
+ [class.ax-sm]="layoutThemeService.isSmall()"
3422
+ [iconOnly]="layoutThemeService.isSmall()"
3423
+ [text]="'actions'"
3424
+ [look]="layoutThemeService.isSmall() ? 'blank' : 'solid'"
3425
+ [color]="'default'"
3426
+ >
3427
+ <ax-prefix>
3428
+ <i class="fa-solid fa-ellipsis-vertical"></i>
3429
+ </ax-prefix>
3430
+ <ax-dropdown-panel #panel>
3431
+ <ax-button-item-list>
3432
+ @for (item of secondaryActions(); track $index) {
3433
+ @if (item.visible != false) {
3434
+ <ax-button-item
3435
+ [text]="item.title"
3436
+ [color]="item.color"
3437
+ [disabled]="item.disabled"
3438
+ (onClick)="handleSecondaryActionClick(item)"
3439
+ >
3440
+ <ax-prefix>
3441
+ <ax-icon icon="fa-light {{ item.icon }}"></ax-icon>
3442
+ </ax-prefix>
3443
+ </ax-button-item>
3444
+ @if (item.break) {
3445
+ <ax-divider></ax-divider>
3446
+ }
3447
+ }
3448
+ }
3449
+ </ax-button-item-list>
3450
+ </ax-dropdown-panel>
3451
+ </ax-button>
3452
+ }
3453
+ </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 }); }
3479
+ }
3480
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityListWidgetViewComponent, decorators: [{
3481
+ type: Component,
3482
+ args: [{
3483
+ template: `
3484
+ <axp-widgets-container [context]="context" (onContextChanged)="onContextChanged($event)">
3485
+ <div class="ax-flex ax-gap-2 ax-justify-end ax-mb-4">
3486
+ @for (action of primaryActions(); track $index) {
3487
+ @if (action.visible != false) {
3488
+ <ax-button
3489
+ [class.ax-sm]="layoutThemeService.isSmall()"
3490
+ [iconOnly]="layoutThemeService.isSmall()"
3491
+ [disabled]="action.disabled"
3492
+ [text]="action.title"
3493
+ [look]="'solid'"
3494
+ [color]="action.color"
3495
+ (onClick)="handleActionClick(action)"
3496
+ >
3497
+ <ax-prefix>
3498
+ <i class="{{ action.icon }}"></i>
3499
+ </ax-prefix>
3500
+ @if (action?.items) {
3501
+ <ax-dropdown-panel #panel>
3502
+ <ax-button-item-list>
3503
+ @for (sub of action?.items; track $index) {
3504
+ @if (sub.visible != false) {
3505
+ <ax-button-item
3506
+ [text]="sub.title"
3507
+ [color]="sub.color"
3508
+ [disabled]="sub.disabled"
3509
+ (onClick)="handleActionClick(sub)"
3510
+ >
3511
+ <ax-prefix>
3512
+ <ax-icon icon="fa-light {{ sub.icon }}"></ax-icon>
3513
+ </ax-prefix>
3514
+ </ax-button-item>
3515
+ @if (sub.break) {
3516
+ <ax-divider></ax-divider>
3517
+ }
3518
+ }
3519
+ }
3520
+ </ax-button-item-list>
3521
+ </ax-dropdown-panel>
3522
+ }
3523
+ </ax-button>
3524
+ }
3525
+ }
3526
+ @if (secondaryActions().length) {
3527
+ <ax-button
3528
+ [class.ax-sm]="layoutThemeService.isSmall()"
3529
+ [iconOnly]="layoutThemeService.isSmall()"
3530
+ [text]="'actions'"
3531
+ [look]="layoutThemeService.isSmall() ? 'blank' : 'solid'"
3532
+ [color]="'default'"
3533
+ >
3534
+ <ax-prefix>
3535
+ <i class="fa-solid fa-ellipsis-vertical"></i>
3536
+ </ax-prefix>
3537
+ <ax-dropdown-panel #panel>
3538
+ <ax-button-item-list>
3539
+ @for (item of secondaryActions(); track $index) {
3540
+ @if (item.visible != false) {
3541
+ <ax-button-item
3542
+ [text]="item.title"
3543
+ [color]="item.color"
3544
+ [disabled]="item.disabled"
3545
+ (onClick)="handleSecondaryActionClick(item)"
3546
+ >
3547
+ <ax-prefix>
3548
+ <ax-icon icon="fa-light {{ item.icon }}"></ax-icon>
3549
+ </ax-prefix>
3550
+ </ax-button-item>
3551
+ @if (item.break) {
3552
+ <ax-divider></ax-divider>
3553
+ }
3554
+ }
3555
+ }
3556
+ </ax-button-item-list>
3557
+ </ax-dropdown-panel>
3558
+ </ax-button>
3559
+ }
3560
+ </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>
3585
+ `,
3586
+ standalone: true,
3587
+ changeDetection: ChangeDetectionStrategy.OnPush,
3588
+ providers: [AXPEntityListConverterService],
3589
+ imports: [CommonModule, AXDecoratorModule, AXPLayoutBuilderModule, AXButtonModule, AXDropdownModule],
3590
+ }]
3591
+ }] });
3592
+
3593
+ var entityListWidgetView_component = /*#__PURE__*/Object.freeze({
3594
+ __proto__: null,
3595
+ AXPEntityListWidgetViewComponent: AXPEntityListWidgetViewComponent
3596
+ });
3597
+
3598
+ const AXPEntityListWidget = {
3599
+ name: 'entity-list',
3600
+ title: 'Entity List',
3601
+ description: 'Displays entity data in a table format',
3602
+ type: 'view',
3603
+ categories: [],
3604
+ groups: [AXPWidgetGroupEnum.EntityWidget],
3605
+ icon: 'fa-solid fa-square',
3606
+ properties: [AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY],
3607
+ components: {
3608
+ view: {
3609
+ component: () => Promise.resolve().then(function () { return entityListWidgetView_component; }).then((c) => c.AXPEntityListWidgetViewComponent),
3610
+ },
3611
+ edit: {
3612
+ component: () => Promise.resolve().then(function () { return entityListWidgetView_component; }).then((c) => c.AXPEntityListWidgetViewComponent),
3613
+ },
3614
+ print: {
3615
+ component: () => Promise.resolve().then(function () { return entityListWidgetView_component; }).then((c) => c.AXPEntityListWidgetViewComponent),
3616
+ },
3617
+ designer: {
3618
+ component: () => Promise.resolve().then(function () { return entityListWidgetView_component; }).then((c) => c.AXPEntityListWidgetViewComponent),
3619
+ },
3620
+ },
3621
+ };
3622
+
3623
+ class AXPEntityReferenceWidgetViewComponent extends AXPLayoutWidgetComponent {
3624
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3625
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3626
+ }
3627
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetViewComponent, decorators: [{
3628
+ type: Component,
3629
+ args: [{
3630
+ template: ``,
3631
+ standalone: true,
3632
+ changeDetection: ChangeDetectionStrategy.OnPush,
3633
+ imports: [CommonModule]
3634
+ }]
3635
+ }] });
3636
+
3637
+ var entityReferenceWidgetView_component = /*#__PURE__*/Object.freeze({
3638
+ __proto__: null,
3639
+ AXPEntityReferenceWidgetViewComponent: AXPEntityReferenceWidgetViewComponent
3640
+ });
3641
+
3642
+ class AXPEntityReferenceWidgetEditComponent extends AXPLayoutWidgetComponent {
3643
+ constructor() {
3644
+ super(...arguments);
3645
+ this.injector = inject(Injector);
3646
+ this.entityResolver = inject(AXPEntityResolver);
3647
+ this.entity = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entity" }] : []));
3648
+ this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : []));
3649
+ this.#efEntity = effect(async () => {
3650
+ const [module, entity] = this.entity().split('.');
3651
+ this.entityDef.set(await this.entityResolver.get(module, entity));
3652
+ console.log(this.entityDef());
3653
+ }, ...(ngDevMode ? [{ debugName: "#efEntity" }] : []));
3654
+ }
3655
+ #efEntity;
3656
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3657
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetEditComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3658
+ }
3659
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetEditComponent, decorators: [{
3660
+ type: Component,
3661
+ args: [{
3662
+ template: ``,
3663
+ standalone: true,
3664
+ changeDetection: ChangeDetectionStrategy.OnPush,
3665
+ imports: [CommonModule, FormsModule],
3666
+ }]
3667
+ }] });
3668
+
3669
+ var entityReferenceWidgetEdit_component = /*#__PURE__*/Object.freeze({
3670
+ __proto__: null,
3671
+ AXPEntityReferenceWidgetEditComponent: AXPEntityReferenceWidgetEditComponent
3672
+ });
3673
+
3674
+ class AXPEntityReferenceWidgetColumnComponent extends AXPColumnWidgetComponent {
3675
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetColumnComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3676
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetColumnComponent, isStandalone: true, selector: "ng-component", inputs: { rawValue: "rawValue" }, usesInheritance: true, ngImport: i0, template: `{{rawValue}}`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3677
+ }
3678
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetColumnComponent, decorators: [{
3679
+ type: Component,
3680
+ args: [{
3681
+ template: `{{rawValue}}`,
3682
+ standalone: true,
3683
+ changeDetection: ChangeDetectionStrategy.OnPush,
3684
+ imports: [CommonModule],
3685
+ inputs: ['rawValue']
3686
+ }]
3687
+ }] });
3688
+
3689
+ var entityReferenceWidgetColumn_component = /*#__PURE__*/Object.freeze({
3690
+ __proto__: null,
3691
+ AXPEntityReferenceWidgetColumnComponent: AXPEntityReferenceWidgetColumnComponent
3692
+ });
3693
+
3694
+ class AXPEntityReferenceWidgetPrintComponent extends AXPLayoutWidgetComponent {
3695
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetPrintComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3696
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetPrintComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3697
+ }
3698
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetPrintComponent, decorators: [{
3699
+ type: Component,
3700
+ args: [{
3701
+ template: ``,
3702
+ standalone: true,
3703
+ changeDetection: ChangeDetectionStrategy.OnPush,
3704
+ imports: [CommonModule],
3705
+ inputs: []
3706
+ }]
3707
+ }] });
3708
+
3709
+ var entityReferenceWidgetPrint_component = /*#__PURE__*/Object.freeze({
3710
+ __proto__: null,
3711
+ AXPEntityReferenceWidgetPrintComponent: AXPEntityReferenceWidgetPrintComponent
3712
+ });
3713
+
3714
+ class AXPEntityReferenceWidgetDesignerComponent extends AXPLayoutWidgetComponent {
3715
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetDesignerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3716
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetDesignerComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3717
+ }
3718
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetDesignerComponent, decorators: [{
3719
+ type: Component,
3720
+ args: [{
3721
+ template: ``,
3722
+ standalone: true,
3723
+ changeDetection: ChangeDetectionStrategy.OnPush,
3724
+ imports: [CommonModule]
3725
+ }]
3726
+ }] });
3727
+
3728
+ var entityReferenceWidgetDesigner_component = /*#__PURE__*/Object.freeze({
3729
+ __proto__: null,
3730
+ AXPEntityReferenceWidgetDesignerComponent: AXPEntityReferenceWidgetDesignerComponent
3731
+ });
3732
+
3733
+ const AXPEntityReferenceWidget = {
3734
+ name: "entity-reference",
3735
+ title: "Entity Reference",
3736
+ description: '',
3737
+ type: 'view',
3738
+ categories: [],
3739
+ groups: [AXPWidgetGroupEnum.FormElement],
3740
+ icon: "fa-solid fa-square",
3741
+ properties: [
3742
+ AXP_NAME_PROPERTY,
3743
+ AXP_DATA_PATH_PROPERTY,
3744
+ ],
3745
+ components: {
3746
+ view: {
3747
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetView_component; }).then((c) => c.AXPEntityReferenceWidgetViewComponent),
3748
+ },
3749
+ edit: {
3750
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetEdit_component; }).then((c) => c.AXPEntityReferenceWidgetEditComponent),
3751
+ },
3752
+ column: {
3753
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetColumn_component; }).then((c) => c.AXPEntityReferenceWidgetColumnComponent),
3754
+ },
3755
+ print: {
3756
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetPrint_component; }).then((c) => c.AXPEntityReferenceWidgetPrintComponent),
3757
+ },
3758
+ designer: {
3759
+ component: () => Promise.resolve().then(function () { return entityReferenceWidgetDesigner_component; }).then((c) => c.AXPEntityReferenceWidgetDesignerComponent),
3760
+ },
3761
+ }
3762
+ };
2926
3763
 
2927
3764
  class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
2928
3765
  constructor() {
@@ -3169,7 +4006,7 @@ class AXPLookupWidgetSelectorComponent extends AXBasePageComponent {
3169
4006
  }
3170
4007
  </ax-suffix>
3171
4008
  </ax-footer>
3172
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXCommonModule }, { kind: "directive", type: i1$2.AXAutoFocusDirective, selector: "[axAutoFocus]", inputs: ["axAutoFocus", "axAutoFocusTime"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDataTableModule }, { kind: "component", type: i4.AXDataTableComponent, selector: "ax-data-table", inputs: ["dataSource", "selectedRows", "parentField", "rowTemplate", "emptyTemplate", "noDataTemplate", "alternative", "showHeader", "fixedHeader", "showFooter", "fixedFooter", "itemHeight", "allowReordering", "paging", "fetchDataMode", "loading", "focusedRow"], outputs: ["selectedRowsChange", "focusedRowChange", "onRowClick", "onRowDbClick", "onColumnsOrderChanged", "onColumnSizeChanged", "onPageChanged"] }, { kind: "component", type: i4.AXRowSelectColumnComponent, selector: "ax-select-column", inputs: ["width", "caption", "fixed"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i5.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXPLayoutBuilderModule }, { kind: "component", type: i6.AXPWidgetColumnRendererComponent, selector: "axp-widget-column-renderer", inputs: ["caption", "customExpandIcon", "customCollapseIcon", "customWidth", "node", "footerTemplate", "expandHandler", "cellTemplate", "headerTemplate"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i8.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4009
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXCommonModule }, { kind: "directive", type: i1$2.AXAutoFocusDirective, selector: "[axAutoFocus]", inputs: ["axAutoFocus", "axAutoFocusTime"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDataTableModule }, { kind: "component", type: i4$1.AXDataTableComponent, selector: "ax-data-table", inputs: ["dataSource", "selectedRows", "parentField", "rowTemplate", "emptyTemplate", "noDataTemplate", "alternative", "showHeader", "fixedHeader", "showFooter", "fixedFooter", "itemHeight", "allowReordering", "paging", "fetchDataMode", "loading", "focusedRow"], outputs: ["selectedRowsChange", "focusedRowChange", "onRowClick", "onRowDbClick", "onColumnsOrderChanged", "onColumnSizeChanged", "onPageChanged"] }, { kind: "component", type: i4$1.AXRowSelectColumnComponent, selector: "ax-select-column", inputs: ["width", "caption", "fixed"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i5.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXPLayoutBuilderModule }, { kind: "component", type: i2.AXPWidgetColumnRendererComponent, selector: "axp-widget-column-renderer", inputs: ["caption", "customExpandIcon", "customCollapseIcon", "customWidth", "node", "footerTemplate", "expandHandler", "cellTemplate", "headerTemplate"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i8.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3173
4010
  }
3174
4011
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLookupWidgetSelectorComponent, decorators: [{
3175
4012
  type: Component,
@@ -3418,6 +4255,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
3418
4255
  this.customFilter = computed(() => this.options()['filter'], ...(ngDevMode ? [{ debugName: "customFilter" }] : []));
3419
4256
  this.multiple = computed(() => (this.options()['multiple'] ?? false), ...(ngDevMode ? [{ debugName: "multiple" }] : []));
3420
4257
  this.look = computed(() => this.options()['look'] ?? 'lookup', ...(ngDevMode ? [{ debugName: "look" }] : []));
4258
+ this.allowClear = computed(() => (this.options()['allowClear'] ?? false), ...(ngDevMode ? [{ debugName: "allowClear" }] : []));
3421
4259
  this.textField = computed(() => {
3422
4260
  return (this.entityDef()?.formats.lookup ?? this.entityDef()?.properties.find((c) => c.name != 'id')?.name ?? 'title');
3423
4261
  }, ...(ngDevMode ? [{ debugName: "textField" }] : []));
@@ -3485,11 +4323,11 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
3485
4323
  }
3486
4324
  showSelector() {
3487
4325
  this.isOpen.set(true);
3488
- const columnsCount = this.columns().length > 0 ? this.columns().length : this.vm()?.columns().length ?? 0;
4326
+ const columnsCount = this.columns().length > 0 ? this.columns().length : (this.vm()?.columns().length ?? 0);
3489
4327
  this.popupService
3490
4328
  .open(AXPLookupWidgetSelectorComponent, {
3491
4329
  title: `${this.translateService.translateSync('widget.lookup.search')} ${this.translateService.translateSync(this.entityDef()?.formats.plural ?? '')}`,
3492
- size: columnsCount < 4 ? 'md' : 'lg',
4330
+ size: columnsCount < 3 ? 'md' : 'lg',
3493
4331
  data: {
3494
4332
  vm: new AXPLookupWidgetSelectorViewModel(this.injector, this.entityDef(), {
3495
4333
  customFilter: this.customFilter(),
@@ -3621,47 +4459,56 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
3621
4459
  [multiple]="multiple()"
3622
4460
  (onValueChanged)="selectBoxValueChange($event)"
3623
4461
  >
3624
- <ax-search-box>
3625
- </ax-search-box>
3626
- </ax-select-box>
4462
+ <ax-search-box>
4463
+ <ax-clear-button></ax-clear-button>
4464
+ </ax-search-box>
4465
+ @if (allowClear()) {
4466
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
4467
+ }
4468
+ </ax-select-box>
3627
4469
  } @else {
3628
- <ax-tag-box
3629
- [ngModel]="selectedItems()"
3630
- [textField]="textField()"
3631
- [valueField]="valueField()"
3632
- (onValueChanged)="handleValueChange($event)"
3633
- [placeholder]="placeholder() | translate | async"
3634
- [addOnEnter]="false"
3635
- [addOnComma]="false"
3636
- [disabled]="disabled()"
3637
- (onKeyUp)="handleKeyUp($event)"
3638
- (onBlur)="handleOnBlur($event)"
3639
- >
3640
- @for (validation of validationRules(); track $index) {
3641
- <ax-validation-rule
3642
- [rule]="validation.rule"
3643
- [message]="validation.options?.message"
3644
- [options]="validation.options"
3645
- ></ax-validation-rule>
3646
- }
3647
- @if (selectedItems().length > 1) {
3648
- <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
3649
- }
4470
+ <ax-tag-box
4471
+ [ngModel]="selectedItems()"
4472
+ [textField]="textField()"
4473
+ [valueField]="valueField()"
4474
+ (onValueChanged)="handleValueChange($event)"
4475
+ [placeholder]="placeholder() | translate | async"
4476
+ [addOnEnter]="false"
4477
+ [addOnComma]="false"
4478
+ [disabled]="disabled()"
4479
+ (onKeyUp)="handleKeyUp($event)"
4480
+ (onBlur)="handleOnBlur($event)"
4481
+ >
4482
+ @for (validation of validationRules(); track $index) {
4483
+ <ax-validation-rule
4484
+ [rule]="validation.rule"
4485
+ [message]="validation.options?.message"
4486
+ [options]="validation.options"
4487
+ ></ax-validation-rule>
4488
+ }
4489
+ @if (selectedItems().length > 1 || allowClear()) {
4490
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
4491
+ }
3650
4492
 
3651
- <ax-suffix>
3652
- <ax-button color="ghost" look="blank" [disabled]="isLoading() || disabled()" (onClick)="handleOnClick($event)">
3653
- @if (isLoading()) {
3654
- <ax-loading></ax-loading>
3655
- } @else {
3656
- <ax-icon icon="far fa-search"> </ax-icon>
3657
- }
3658
- </ax-button>
3659
- </ax-suffix>
3660
- </ax-tag-box>
3661
- }
4493
+ <ax-suffix>
4494
+ <ax-button
4495
+ color="ghost"
4496
+ look="blank"
4497
+ [disabled]="isLoading() || disabled()"
4498
+ (onClick)="handleOnClick($event)"
4499
+ >
4500
+ @if (isLoading()) {
4501
+ <ax-loading></ax-loading>
4502
+ } @else {
4503
+ <ax-icon icon="far fa-search"> </ax-icon>
4504
+ }
4505
+ </ax-button>
4506
+ </ax-suffix>
4507
+ </ax-tag-box>
4508
+ }
3662
4509
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type:
3663
4510
  //
3664
- AXButtonModule }, { kind: "component", type: i2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i1.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$1.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXTagBoxModule }, { kind: "component", type: i6$1.AXTagBoxComponent, selector: "ax-tag-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "allowNull", "type", "look", "addOnComma", "addOnEnter", "valueField", "textField", "readonlyField", "allowDuplicateValues"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i7$1.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed"] }, { kind: "component", type: AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i8.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4511
+ AXButtonModule }, { kind: "component", type: i3$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i1.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$1.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXTagBoxModule }, { kind: "component", type: i6.AXTagBoxComponent, selector: "ax-tag-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "allowNull", "type", "look", "addOnComma", "addOnEnter", "valueField", "textField", "readonlyField", "allowDuplicateValues"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i7$1.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed"] }, { kind: "component", type: AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i8.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3665
4512
  }
3666
4513
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPLookupWidgetEditComponent, decorators: [{
3667
4514
  type: Component,
@@ -3678,44 +4525,53 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
3678
4525
  [multiple]="multiple()"
3679
4526
  (onValueChanged)="selectBoxValueChange($event)"
3680
4527
  >
3681
- <ax-search-box>
3682
- </ax-search-box>
3683
- </ax-select-box>
4528
+ <ax-search-box>
4529
+ <ax-clear-button></ax-clear-button>
4530
+ </ax-search-box>
4531
+ @if (allowClear()) {
4532
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
4533
+ }
4534
+ </ax-select-box>
3684
4535
  } @else {
3685
- <ax-tag-box
3686
- [ngModel]="selectedItems()"
3687
- [textField]="textField()"
3688
- [valueField]="valueField()"
3689
- (onValueChanged)="handleValueChange($event)"
3690
- [placeholder]="placeholder() | translate | async"
3691
- [addOnEnter]="false"
3692
- [addOnComma]="false"
3693
- [disabled]="disabled()"
3694
- (onKeyUp)="handleKeyUp($event)"
3695
- (onBlur)="handleOnBlur($event)"
3696
- >
3697
- @for (validation of validationRules(); track $index) {
3698
- <ax-validation-rule
3699
- [rule]="validation.rule"
3700
- [message]="validation.options?.message"
3701
- [options]="validation.options"
3702
- ></ax-validation-rule>
3703
- }
3704
- @if (selectedItems().length > 1) {
3705
- <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
3706
- }
4536
+ <ax-tag-box
4537
+ [ngModel]="selectedItems()"
4538
+ [textField]="textField()"
4539
+ [valueField]="valueField()"
4540
+ (onValueChanged)="handleValueChange($event)"
4541
+ [placeholder]="placeholder() | translate | async"
4542
+ [addOnEnter]="false"
4543
+ [addOnComma]="false"
4544
+ [disabled]="disabled()"
4545
+ (onKeyUp)="handleKeyUp($event)"
4546
+ (onBlur)="handleOnBlur($event)"
4547
+ >
4548
+ @for (validation of validationRules(); track $index) {
4549
+ <ax-validation-rule
4550
+ [rule]="validation.rule"
4551
+ [message]="validation.options?.message"
4552
+ [options]="validation.options"
4553
+ ></ax-validation-rule>
4554
+ }
4555
+ @if (selectedItems().length > 1 || allowClear()) {
4556
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
4557
+ }
3707
4558
 
3708
- <ax-suffix>
3709
- <ax-button color="ghost" look="blank" [disabled]="isLoading() || disabled()" (onClick)="handleOnClick($event)">
3710
- @if (isLoading()) {
3711
- <ax-loading></ax-loading>
3712
- } @else {
3713
- <ax-icon icon="far fa-search"> </ax-icon>
3714
- }
3715
- </ax-button>
3716
- </ax-suffix>
3717
- </ax-tag-box>
3718
- }
4559
+ <ax-suffix>
4560
+ <ax-button
4561
+ color="ghost"
4562
+ look="blank"
4563
+ [disabled]="isLoading() || disabled()"
4564
+ (onClick)="handleOnClick($event)"
4565
+ >
4566
+ @if (isLoading()) {
4567
+ <ax-loading></ax-loading>
4568
+ } @else {
4569
+ <ax-icon icon="far fa-search"> </ax-icon>
4570
+ }
4571
+ </ax-button>
4572
+ </ax-suffix>
4573
+ </ax-tag-box>
4574
+ }
3719
4575
  `,
3720
4576
  changeDetection: ChangeDetectionStrategy.OnPush,
3721
4577
  imports: [
@@ -3730,7 +4586,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
3730
4586
  AXTagBoxModule,
3731
4587
  AXTranslationModule,
3732
4588
  AXSelectBoxModule,
3733
- AXSearchBoxComponent
4589
+ AXSearchBoxComponent,
3734
4590
  ],
3735
4591
  }]
3736
4592
  }] });
@@ -3809,6 +4665,7 @@ const AXPLookupWidget = {
3809
4665
  type: 'editor',
3810
4666
  properties: [
3811
4667
  AXP_DISABLED_PROPERTY,
4668
+ AXP_ALLOW_CLEAR_PROPERTY,
3812
4669
  AXP_DATA_PATH_PROPERTY,
3813
4670
  {
3814
4671
  name: 'expose',
@@ -3992,7 +4849,7 @@ class AXPTagableBoxWidgetEditComponent extends AXPValueWidgetComponent {
3992
4849
  </ax-prefix>
3993
4850
  </ax-button>
3994
4851
  </div>
3995
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXTextBoxModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$1.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i7$1.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i5.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4852
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXTextBoxModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$1.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i7$1.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i5.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3996
4853
  }
3997
4854
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPTagableBoxWidgetEditComponent, decorators: [{
3998
4855
  type: Component,
@@ -4288,7 +5145,7 @@ class AXPWidgetSelectorWidgetEditComponent extends AXPValueWidgetComponent {
4288
5145
  <axp-widget-property-viewer [widget]="selectedWidgetNode()!" (onChanged)="handleChangeWidget($event)">
4289
5146
  </axp-widget-property-viewer>
4290
5147
  }
4291
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "component", type: i2$1.AXTextBoxComponent, selector: "ax-text-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "maxLength", "allowNull", "type", "autoComplete", "look", "mask-options", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$1.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "component", type: AXPWidgetPropertyViewerComponent, selector: "axp-widget-property-viewer", inputs: ["widget", "mode"], outputs: ["onChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5148
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "component", type: i2$1.AXTextBoxComponent, selector: "ax-text-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "maxLength", "allowNull", "type", "autoComplete", "look", "mask-options", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$1.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "component", type: AXPWidgetPropertyViewerComponent, selector: "axp-widget-property-viewer", inputs: ["widget", "mode"], outputs: ["onChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4292
5149
  }
4293
5150
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPWidgetSelectorWidgetEditComponent, decorators: [{
4294
5151
  type: Component,
@@ -4730,147 +5587,6 @@ const AXPShowListViewWorkflow = {
4730
5587
  },
4731
5588
  };
4732
5589
 
4733
- class AXPEntityReferenceWidgetViewComponent extends AXPLayoutWidgetComponent {
4734
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4735
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4736
- }
4737
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetViewComponent, decorators: [{
4738
- type: Component,
4739
- args: [{
4740
- template: ``,
4741
- standalone: true,
4742
- changeDetection: ChangeDetectionStrategy.OnPush,
4743
- imports: [CommonModule]
4744
- }]
4745
- }] });
4746
-
4747
- var entityReferenceWidgetView_component = /*#__PURE__*/Object.freeze({
4748
- __proto__: null,
4749
- AXPEntityReferenceWidgetViewComponent: AXPEntityReferenceWidgetViewComponent
4750
- });
4751
-
4752
- class AXPEntityReferenceWidgetEditComponent extends AXPLayoutWidgetComponent {
4753
- constructor() {
4754
- super(...arguments);
4755
- this.injector = inject(Injector);
4756
- this.entityResolver = inject(AXPEntityResolver);
4757
- this.entity = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entity" }] : []));
4758
- this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : []));
4759
- this.#efEntity = effect(async () => {
4760
- const [module, entity] = this.entity().split('.');
4761
- this.entityDef.set(await this.entityResolver.get(module, entity));
4762
- console.log(this.entityDef());
4763
- }, ...(ngDevMode ? [{ debugName: "#efEntity" }] : []));
4764
- }
4765
- #efEntity;
4766
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4767
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetEditComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4768
- }
4769
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetEditComponent, decorators: [{
4770
- type: Component,
4771
- args: [{
4772
- template: ``,
4773
- standalone: true,
4774
- changeDetection: ChangeDetectionStrategy.OnPush,
4775
- imports: [CommonModule, FormsModule],
4776
- }]
4777
- }] });
4778
-
4779
- var entityReferenceWidgetEdit_component = /*#__PURE__*/Object.freeze({
4780
- __proto__: null,
4781
- AXPEntityReferenceWidgetEditComponent: AXPEntityReferenceWidgetEditComponent
4782
- });
4783
-
4784
- class AXPEntityReferenceWidgetColumnComponent extends AXPColumnWidgetComponent {
4785
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetColumnComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4786
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetColumnComponent, isStandalone: true, selector: "ng-component", inputs: { rawValue: "rawValue" }, usesInheritance: true, ngImport: i0, template: `{{rawValue}}`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4787
- }
4788
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetColumnComponent, decorators: [{
4789
- type: Component,
4790
- args: [{
4791
- template: `{{rawValue}}`,
4792
- standalone: true,
4793
- changeDetection: ChangeDetectionStrategy.OnPush,
4794
- imports: [CommonModule],
4795
- inputs: ['rawValue']
4796
- }]
4797
- }] });
4798
-
4799
- var entityReferenceWidgetColumn_component = /*#__PURE__*/Object.freeze({
4800
- __proto__: null,
4801
- AXPEntityReferenceWidgetColumnComponent: AXPEntityReferenceWidgetColumnComponent
4802
- });
4803
-
4804
- class AXPEntityReferenceWidgetPrintComponent extends AXPLayoutWidgetComponent {
4805
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetPrintComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4806
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetPrintComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4807
- }
4808
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetPrintComponent, decorators: [{
4809
- type: Component,
4810
- args: [{
4811
- template: ``,
4812
- standalone: true,
4813
- changeDetection: ChangeDetectionStrategy.OnPush,
4814
- imports: [CommonModule],
4815
- inputs: []
4816
- }]
4817
- }] });
4818
-
4819
- var entityReferenceWidgetPrint_component = /*#__PURE__*/Object.freeze({
4820
- __proto__: null,
4821
- AXPEntityReferenceWidgetPrintComponent: AXPEntityReferenceWidgetPrintComponent
4822
- });
4823
-
4824
- class AXPEntityReferenceWidgetDesignerComponent extends AXPLayoutWidgetComponent {
4825
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetDesignerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4826
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: AXPEntityReferenceWidgetDesignerComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4827
- }
4828
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityReferenceWidgetDesignerComponent, decorators: [{
4829
- type: Component,
4830
- args: [{
4831
- template: ``,
4832
- standalone: true,
4833
- changeDetection: ChangeDetectionStrategy.OnPush,
4834
- imports: [CommonModule]
4835
- }]
4836
- }] });
4837
-
4838
- var entityReferenceWidgetDesigner_component = /*#__PURE__*/Object.freeze({
4839
- __proto__: null,
4840
- AXPEntityReferenceWidgetDesignerComponent: AXPEntityReferenceWidgetDesignerComponent
4841
- });
4842
-
4843
- const AXPEntityReferenceWidget = {
4844
- name: "entity-reference",
4845
- title: "Entity Reference",
4846
- description: '',
4847
- type: 'view',
4848
- categories: [],
4849
- groups: [AXPWidgetGroupEnum.FormElement],
4850
- icon: "fa-solid fa-square",
4851
- properties: [
4852
- AXP_NAME_PROPERTY,
4853
- AXP_DATA_PATH_PROPERTY,
4854
- ],
4855
- components: {
4856
- view: {
4857
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetView_component; }).then((c) => c.AXPEntityReferenceWidgetViewComponent),
4858
- },
4859
- edit: {
4860
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetEdit_component; }).then((c) => c.AXPEntityReferenceWidgetEditComponent),
4861
- },
4862
- column: {
4863
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetColumn_component; }).then((c) => c.AXPEntityReferenceWidgetColumnComponent),
4864
- },
4865
- print: {
4866
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetPrint_component; }).then((c) => c.AXPEntityReferenceWidgetPrintComponent),
4867
- },
4868
- designer: {
4869
- component: () => Promise.resolve().then(function () { return entityReferenceWidgetDesigner_component; }).then((c) => c.AXPEntityReferenceWidgetDesignerComponent),
4870
- },
4871
- }
4872
- };
4873
-
4874
5590
  function routesFacory() {
4875
5591
  const config = inject(AXP_ENTITY_CONFIG_TOKEN);
4876
5592
  let routes = [];
@@ -4903,6 +5619,14 @@ function routesFacory() {
4903
5619
  },
4904
5620
  data: { reuse: false },
4905
5621
  },
5622
+ {
5623
+ path: 'e/:entity/:id/new-view',
5624
+ resolve: { adapter: AXPLayoutDetailsViewRouteResolver },
5625
+ loadComponent: () => {
5626
+ return config.viewers.master.details();
5627
+ },
5628
+ data: { reuse: false },
5629
+ },
4906
5630
  {
4907
5631
  path: 'e/:entity/:id',
4908
5632
  redirectTo: 'e/:entity/:id/view',
@@ -4934,7 +5658,7 @@ class AXPEntityModule {
4934
5658
  });
4935
5659
  }
4936
5660
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, deps: [{ token: i1$4.AXPAppStartUpService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.NgModule }); }
4937
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, imports: [RouterModule, i2$2.AXPWorkflowModule, i6.AXPLayoutBuilderModule] }); }
5661
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, imports: [RouterModule, i2$2.AXPWorkflowModule, i2.AXPLayoutBuilderModule] }); }
4938
5662
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, providers: [
4939
5663
  {
4940
5664
  provide: ROUTES,
@@ -4980,7 +5704,13 @@ class AXPEntityModule {
4980
5704
  functions: {},
4981
5705
  }),
4982
5706
  AXPLayoutBuilderModule.forChild({
4983
- widgets: [AXPLookupWidget, AXPWidgetSelectorWidget, AXPTagableBoxWidget, AXPEntityReferenceWidget],
5707
+ widgets: [
5708
+ AXPLookupWidget,
5709
+ AXPWidgetSelectorWidget,
5710
+ AXPTagableBoxWidget,
5711
+ AXPEntityListWidget,
5712
+ AXPEntityReferenceWidget,
5713
+ ],
4984
5714
  })] }); }
4985
5715
  }
4986
5716
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPEntityModule, decorators: [{
@@ -5016,7 +5746,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
5016
5746
  functions: {},
5017
5747
  }),
5018
5748
  AXPLayoutBuilderModule.forChild({
5019
- widgets: [AXPLookupWidget, AXPWidgetSelectorWidget, AXPTagableBoxWidget, AXPEntityReferenceWidget],
5749
+ widgets: [
5750
+ AXPLookupWidget,
5751
+ AXPWidgetSelectorWidget,
5752
+ AXPTagableBoxWidget,
5753
+ AXPEntityListWidget,
5754
+ AXPEntityReferenceWidget,
5755
+ ],
5020
5756
  }),
5021
5757
  ],
5022
5758
  exports: [],
@@ -5087,9 +5823,7 @@ function entityMasterCrudActions() {
5087
5823
  ];
5088
5824
  }
5089
5825
  function entityMasterRecordActions() {
5090
- return [
5091
- entityMasterDeleteAction(),
5092
- ];
5826
+ return [entityMasterDeleteAction()];
5093
5827
  }
5094
5828
  // #endregion
5095
5829
  // #region Details
@@ -5121,7 +5855,8 @@ function entityDetailsSimpleCondition(fk) {
5121
5855
  };
5122
5856
  }
5123
5857
  function entityDetailsReferenceCondition() {
5124
- return [{
5858
+ return [
5859
+ {
5125
5860
  name: 'reference.id',
5126
5861
  operator: { type: 'equal' },
5127
5862
  value: '{{context.eval("id")}}',
@@ -5130,7 +5865,7 @@ function entityDetailsReferenceCondition() {
5130
5865
  name: 'reference.type',
5131
5866
  operator: { type: 'equal' },
5132
5867
  value: '{{context.eval("entityName")}}',
5133
- }
5868
+ },
5134
5869
  ];
5135
5870
  }
5136
5871
  function entityDetailsEditAction() {
@@ -5153,11 +5888,7 @@ function entityOverrideDetailsViewAction() {
5153
5888
  };
5154
5889
  }
5155
5890
  function entityDetailsCrudActions(parentId) {
5156
- return [
5157
- entityDetailsCreateActions(parentId),
5158
- entityDetailsEditAction(),
5159
- entityOverrideDetailsViewAction(),
5160
- ];
5891
+ return [entityDetailsCreateActions(parentId), entityDetailsEditAction(), entityOverrideDetailsViewAction()];
5161
5892
  }
5162
5893
  function entityDetailsReferenceCreateActions() {
5163
5894
  return [
@@ -5170,10 +5901,10 @@ function entityDetailsReferenceCreateActions() {
5170
5901
  redirect: false,
5171
5902
  canCreateNewOne: true,
5172
5903
  data: {
5173
- 'reference': {
5174
- 'id': '{{context.eval("id")}}',
5175
- 'type': '{{context.eval("entityName")}}'
5176
- }
5904
+ reference: {
5905
+ id: '{{context.eval("id")}}',
5906
+ type: '{{context.eval("entityName")}}',
5907
+ },
5177
5908
  },
5178
5909
  },
5179
5910
  },
@@ -5186,11 +5917,66 @@ function entityDetailsReferenceCreateActions() {
5186
5917
  entityOverrideDetailsViewAction(),
5187
5918
  ];
5188
5919
  }
5189
- // #endregion
5920
+ /**
5921
+ * Computes a diff between two plain objects with array-aware semantics.
5922
+ * - For arrays of objects with an id field, computes added/removed by id.
5923
+ * - For arrays of primitives or objects without id, uses deep equality.
5924
+ * - For scalars/objects, reports oldValue/newValue when changed.
5925
+ */
5926
+ function detectEntityChanges(oldObj, newObj) {
5927
+ return transform(newObj, (result, value, key) => {
5928
+ if (!isEqual(value, oldObj[key])) {
5929
+ const oldValue = oldObj[key];
5930
+ if (Array.isArray(value) || Array.isArray(oldValue)) {
5931
+ const oldArray = Array.isArray(oldValue) ? oldValue : [];
5932
+ const newArray = Array.isArray(value) ? value : [];
5933
+ const hasId = newArray.length > 0 && typeof newArray[0] === 'object' && newArray[0] !== null && 'id' in newArray[0];
5934
+ if (hasId) {
5935
+ const added = newArray.filter((item) => !oldArray.some((oldItem) => oldItem.id === item.id));
5936
+ const removed = oldArray.filter((item) => !newArray.some((newItem) => newItem.id === item.id));
5937
+ result[key] = { oldValue, newValue: value, added, removed };
5938
+ }
5939
+ else {
5940
+ const added = newArray.filter((item) => !oldArray.some((oldItem) => isEqual(item, oldItem)));
5941
+ const removed = oldArray.filter((item) => !newArray.some((newItem) => isEqual(item, newItem)));
5942
+ result[key] = { oldValue, newValue: value, added, removed };
5943
+ }
5944
+ }
5945
+ else {
5946
+ result[key] = { oldValue, newValue: value };
5947
+ }
5948
+ }
5949
+ }, {});
5950
+ }
5951
+ //#endregion
5952
+
5953
+ const eventDispatchMiddleware = {
5954
+ target: { ops: ['create', 'update', 'delete'], order: 90 },
5955
+ execute: async (ctx, next) => {
5956
+ const dispatcher = inject(AXPEntityEventDispatcherService);
5957
+ console.log(ctx);
5958
+ await next();
5959
+ if (ctx.op === 'create') {
5960
+ const createdData = ctx.result ? { ...ctx.data, id: ctx.result } : ctx.data;
5961
+ await dispatcher.dispatchInserted(ctx.entityName, { refType: ctx.entityName, data: createdData });
5962
+ }
5963
+ else if (ctx.op === 'update') {
5964
+ await dispatcher.dispatchUpdated(ctx.entityName, {
5965
+ refType: ctx.entityName,
5966
+ data: ctx.result,
5967
+ changes: ctx.locals.get('changes'),
5968
+ });
5969
+ }
5970
+ else if (ctx.op === 'delete') {
5971
+ // For delete, prefer previous entity if available
5972
+ await dispatcher.dispatchDeleted(ctx.entityName, { refType: ctx.entityName, data: ctx.result ?? ctx.previous });
5973
+ }
5974
+ },
5975
+ };
5190
5976
 
5191
5977
  /**
5192
5978
  * Generated bundle index. Do not edit.
5193
5979
  */
5194
5980
 
5195
- export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntityApplyUpdatesAction, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityResolver, AXPEntityService, AXPEntityStorageExecutor, AXPEntityStorageRegistry, AXPEntityStorageService, AXPEntityStorageWithMiddlewareService, AXPModifyEntitySectionWorkflow, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_EXTENSION, AXP_ENTITY_STORAGE_MIDDLEWARE_SETUP, auditMiddleware, auditStorage, cachingMiddleware, composeEntityStorageMiddlewares, createModifierContext, dataSanitizationMiddleware, entityDetailsCreateActions, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, errorHandlingMiddleware, generateRequestId, loggingMiddleware, performanceMiddleware, provideEntitySpecificMiddleware, provideEntityStorageMiddleware, provideGlobalEntityStorageMiddleware, provideOperationSpecificMiddleware, userContextMiddleware, validationMiddleware };
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 };
5196
5982
  //# sourceMappingURL=acorex-platform-layout-entity.mjs.map