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