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