@acorex/platform 21.0.0-next.75 → 21.0.0-next.76
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/fesm2022/{acorex-platform-common-common-settings.provider-Ytey9uhY.mjs → acorex-platform-common-common-settings.provider-ChoT4m4k.mjs} +42 -1
- package/fesm2022/acorex-platform-common-common-settings.provider-ChoT4m4k.mjs.map +1 -0
- package/fesm2022/acorex-platform-common.mjs +1471 -606
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-contracts.mjs +1330 -1
- package/fesm2022/acorex-platform-contracts.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +208 -5
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +595 -439
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +372 -171
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +3 -103
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs +513 -0
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-widgets.mjs +11 -6
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs → acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs} +2 -3
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +643 -52
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/acorex-platform-workflow.mjs +5 -8
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/package.json +1 -1
- package/types/acorex-platform-common.d.ts +337 -1056
- package/types/acorex-platform-contracts.d.ts +1679 -4
- package/types/acorex-platform-core.d.ts +92 -181
- package/types/acorex-platform-layout-components.d.ts +2 -1
- package/types/acorex-platform-layout-entity.d.ts +68 -176
- package/types/acorex-platform-layout-views.d.ts +39 -5
- package/types/acorex-platform-layout-widget-core.d.ts +2 -3
- package/types/acorex-platform-layout-widgets.d.ts +11 -4
- package/types/acorex-platform-themes-default.d.ts +120 -57
- package/types/acorex-platform-workflow.d.ts +5 -18
- package/fesm2022/acorex-platform-common-common-settings.provider-Ytey9uhY.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs +0 -116
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs.map +0 -1
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import { AXToastService } from '@acorex/components/toast';
|
|
2
2
|
import * as i6 from '@acorex/core/translation';
|
|
3
|
-
import { AXTranslationService,
|
|
3
|
+
import { AXTranslationService, resolveMultiLanguageString, AXTranslationModule, translateSync } from '@acorex/core/translation';
|
|
4
4
|
import * as i4$3 from '@acorex/platform/common';
|
|
5
|
-
import { AXPNotFoundError, AXPEntityCommandScope, axpNavigateAppPath, AXPSettingsService, AXPCommonSettings, normalizeEntityDisplayTemplate, isUnresolvedEntityDisplayTemplate, AXPFilterOperatorMiddlewareService, isCardFieldBadgeDisplay, resolveCardFieldBadgeColor, getEntityInfo, resolveEnabledMasterListLayouts, resolveDefaultMasterListLayout, AXPRefreshEvent, AXPReloadEvent, axpRedirectToNotFound, ENTITY_ROW_POPUP_TITLE_OPTION, AXPCleanNestedFilters, AXPFileTypeProviderService, AXPFileStorageService, resolveEntityRowDisplayTitle, AXPFileActionsService, axpIsEntityRecordNotFound, AXPDefaultMultiLanguageConfigService, withDefaultMultiLanguageOnWidgetNodeTree, AXPEntityQueryType, buildEntitySearchTitleContext, AXPWorkflowNavigateAction, AXP_NOT_FOUND_ROUTE, AXP_PROTECTED_ROUTE_GUARDS, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER, AXPMenuItemsDataSourceDefinition } from '@acorex/platform/common';
|
|
5
|
+
import { AXPNotFoundError, AXPEntityCommandScope, axpNavigateAppPath, AXPSettingsService, AXPCommonSettings, resolveEntityModifyPopupTitle, resolveSearchableText, normalizeEntityDisplayTemplate, evaluateEntityDisplayTemplate, sanitizeResolvedEntityDisplayTitle, isUnresolvedEntityDisplayTemplate, AXPFilterOperatorMiddlewareService, isCardFieldBadgeDisplay, resolveCardFieldBadgeColor, getEntityInfo, resolveEnabledMasterListLayouts, resolveDefaultMasterListLayout, AXPRefreshEvent, AXPReloadEvent, axpRedirectToNotFound, ENTITY_ROW_POPUP_TITLE_OPTION, AXPCleanNestedFilters, AXPFileTypeProviderService, AXPFileStorageService, resolveEntityRowDisplayTitle, AXPFileActionsService, axpIsEntityRecordNotFound, AXPDefaultMultiLanguageConfigService, withDefaultMultiLanguageOnWidgetNodeTree, AXPEntityQueryType, buildEntitySearchTitleContext, AXPWorkflowNavigateAction, AXP_NOT_FOUND_ROUTE, AXP_PROTECTED_ROUTE_GUARDS, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER, AXP_SEARCH_DEFINITION_LAZY_RESOLVER, AXPMenuItemsDataSourceDefinition } from '@acorex/platform/common';
|
|
6
6
|
import * as i0 from '@angular/core';
|
|
7
|
-
import { InjectionToken, inject, Injector, runInInjectionContext, Injectable, input, viewChild, signal, computed, ElementRef, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent, NgModule, ChangeDetectorRef,
|
|
7
|
+
import { InjectionToken, inject, Injector, runInInjectionContext, Injectable, input, viewChild, signal, computed, effect, ElementRef, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent, NgModule, ChangeDetectorRef, Input, afterNextRender, untracked, ViewEncapsulation, viewChildren, linkedSignal, HostBinding, output, makeEnvironmentProviders } from '@angular/core';
|
|
8
|
+
import { cloneDeep, merge, get, castArray, set, orderBy, omit, isNil, isEmpty, isEqual as isEqual$1, isArray, isString } from 'lodash-es';
|
|
8
9
|
import { Subject, takeUntil } from 'rxjs';
|
|
9
10
|
import { AXPLayoutBuilderService, LayoutBuilderModule } from '@acorex/platform/layout/builder';
|
|
10
11
|
import * as i3 from '@acorex/platform/layout/widget-core';
|
|
11
12
|
import { AXPWidgetsCatalog, AXPWidgetCoreModule, AXPPageStatus, AXPWidgetRegistryService, AXPColumnWidgetComponent, AXPValueWidgetComponent, AXPWidgetGroupEnum, createBooleanProperty, AXPWidgetRendererDirective, AXPBaseWidgetComponent, AXPWidgetStatus, createStringProperty, createNumberProperty, AXP_WIDGETS_ADVANCE_SUB_MEDIA, AXP_WIDGETS_ADVANCE_CATEGORY, createSelectProperty, AXP_WIDGETS_EDITOR_CATEGORY, AXP_WIDGET_DEFINITION_PROVIDER } from '@acorex/platform/layout/widget-core';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
13
|
+
import { AXPDeviceService, AXPExpressionEvaluatorService, AXPContextEvalFactory, AXPBroadcastEventService, applyFilterArray, applySortArray, resolveActionLook, AXPDistributedEventListenerService, AXPPlatformScope, AXHighlightService, extractValue, setSmart, getChangedPaths, objectKeyValueTransforms, AXPHookService, AXPDataGenerator, AXPComponentSlotModule, AXPContextStore, AXPColumnWidthService, AXPModuleManifestRegistry, AXPSystemActionType, defaultColumnWidthProvider, AXP_COLUMN_WIDTH_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXPModuleManifestsDataSourceDefinition } from '@acorex/platform/core';
|
|
14
|
+
import { mergeForeignKeyFieldIntoCreateActions, collectNestedCreateHiddenProperties, AXPEntityDataSourceKeys } from '@acorex/platform/contracts';
|
|
15
|
+
export { AXPEntityDataSourceKeys, collectNestedCreateHiddenProperties, entityDetailsCreateActions, entityDetailsCreateActionsDeferredParent, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsNewEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterEditAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, mergeForeignKeyFieldIntoCreateActions } from '@acorex/platform/contracts';
|
|
14
16
|
import { transform, isEqual } from 'lodash';
|
|
15
17
|
import { AXPSessionService, AXPPermissionDefinitionsDataSourceDefinition } from '@acorex/platform/auth';
|
|
16
18
|
import { Router, ActivatedRoute, RouterModule, ROUTES } from '@angular/router';
|
|
17
19
|
import { defineCommand, AXP_COMMAND_DEFINITION_CATEGORY_ENTITY, AXPCommandService, AXPQueryService, AXPQueryExecutor, AXPCommandExecutor, provideCommandSetups, provideQuerySetups, AXPCommandRegistry, AXPQueryRegistry } from '@acorex/platform/runtime';
|
|
20
|
+
import { AXFormatService } from '@acorex/core/format';
|
|
18
21
|
import * as i1 from '@acorex/components/button';
|
|
19
22
|
import { AXButtonModule } from '@acorex/components/button';
|
|
20
23
|
import * as i4 from '@acorex/components/skeleton';
|
|
21
24
|
import { AXSkeletonModule } from '@acorex/components/skeleton';
|
|
22
25
|
import * as i2 from '@acorex/components/popover';
|
|
23
26
|
import { AXPopoverModule } from '@acorex/components/popover';
|
|
24
|
-
import { AXFormatService } from '@acorex/core/format';
|
|
25
27
|
import * as i5 from '@angular/common';
|
|
26
28
|
import { CommonModule, AsyncPipe, NgClass } from '@angular/common';
|
|
27
29
|
import { AXPThemeLayoutBlockComponent, AXPPreloadFiltersComponent, AXP_PAGE_COMPONENT_PROVIDER, AXPStateMessageComponent, AXPColumnItemListComponent, AXPDataSelectorService, AXPPageComponentRegistryService } from '@acorex/platform/layout/components';
|
|
@@ -37,6 +39,7 @@ import { AXDialogService } from '@acorex/components/dialog';
|
|
|
37
39
|
import { AXLoadingDialogService } from '@acorex/components/loading-dialog';
|
|
38
40
|
import { AXPopupService } from '@acorex/components/popup';
|
|
39
41
|
import { AXPlatform } from '@acorex/core/platform';
|
|
42
|
+
import { AXP_DISABLED_PROPERTY, AXP_ALLOW_CLEAR_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_DATA_PROPERTY_GROUP, AXP_ALLOW_MULTIPLE_PROPERTY, AXP_NAME_PROPERTY, AXP_READONLY_PROPERTY, AXP_PLACEHOLDER_PROPERTY, AXP_BEHAVIOR_PROPERTY_GROUP, AXPProviderSelectWidgetEditBase, AXP_ROW_EXPR_PREFIX, AXP_DOWNLOADABLE_PROPERTY, AXP_DESCRIPTION_PROPERTY, AXP_REPEATER_ENTITY_BY_KEY_LOOKUP } from '@acorex/platform/layout/widgets';
|
|
40
43
|
import * as i2$1 from '@acorex/components/badge';
|
|
41
44
|
import { AXBadgeModule } from '@acorex/components/badge';
|
|
42
45
|
import { AXCheckBoxModule } from '@acorex/components/check-box';
|
|
@@ -57,7 +60,6 @@ import { AXLoadingModule } from '@acorex/components/loading';
|
|
|
57
60
|
import * as i6$1 from '@acorex/components/tag-box';
|
|
58
61
|
import { AXTagBoxModule } from '@acorex/components/tag-box';
|
|
59
62
|
import { AXValidationModule } from '@acorex/core/validation';
|
|
60
|
-
import { AXP_DISABLED_PROPERTY, AXP_ALLOW_CLEAR_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_DATA_PROPERTY_GROUP, AXP_ALLOW_MULTIPLE_PROPERTY, AXP_NAME_PROPERTY, AXP_READONLY_PROPERTY, AXP_PLACEHOLDER_PROPERTY, AXP_BEHAVIOR_PROPERTY_GROUP, AXPProviderSelectWidgetEditBase, AXP_ROW_EXPR_PREFIX, AXP_DOWNLOADABLE_PROPERTY, AXP_DESCRIPTION_PROPERTY } from '@acorex/platform/layout/widgets';
|
|
61
63
|
import * as i2$2 from '@acorex/components/select-box';
|
|
62
64
|
import { AXSelectBoxModule } from '@acorex/components/select-box';
|
|
63
65
|
import * as i3$3 from '@acorex/components/dropdown';
|
|
@@ -852,276 +854,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
852
854
|
}]
|
|
853
855
|
}] });
|
|
854
856
|
|
|
855
|
-
// #region Master
|
|
856
|
-
function entityMasterCreateAction() {
|
|
857
|
-
return {
|
|
858
|
-
title: '@general:actions.create.title',
|
|
859
|
-
command: {
|
|
860
|
-
name: 'Entity:Create',
|
|
861
|
-
},
|
|
862
|
-
priority: 'primary',
|
|
863
|
-
type: AXPSystemActionType.Create,
|
|
864
|
-
scope: AXPEntityCommandScope.TypeLevel,
|
|
865
|
-
};
|
|
866
|
-
}
|
|
867
|
-
function entityMasterEditAction() {
|
|
868
|
-
return {
|
|
869
|
-
title: '@general:actions.edit.title',
|
|
870
|
-
command: 'Entity:Update',
|
|
871
|
-
priority: 'secondary',
|
|
872
|
-
type: AXPSystemActionType.Update,
|
|
873
|
-
scope: AXPEntityCommandScope.Individual,
|
|
874
|
-
default: true,
|
|
875
|
-
};
|
|
876
|
-
}
|
|
877
|
-
function entityMasterBulkDeleteAction() {
|
|
878
|
-
return {
|
|
879
|
-
title: '@general:actions.delete-items.title',
|
|
880
|
-
command: 'delete-entity',
|
|
881
|
-
priority: 'primary',
|
|
882
|
-
type: AXPSystemActionType.Delete,
|
|
883
|
-
scope: AXPEntityCommandScope.Selected,
|
|
884
|
-
order: 100,
|
|
885
|
-
};
|
|
886
|
-
}
|
|
887
|
-
function entityMasterViewAction() {
|
|
888
|
-
return {
|
|
889
|
-
title: '@general:actions.view.title',
|
|
890
|
-
command: 'open-entity',
|
|
891
|
-
priority: 'secondary',
|
|
892
|
-
type: AXPSystemActionType.View,
|
|
893
|
-
scope: AXPEntityCommandScope.Individual,
|
|
894
|
-
default: true,
|
|
895
|
-
};
|
|
896
|
-
}
|
|
897
|
-
function entityMasterDeleteAction() {
|
|
898
|
-
return {
|
|
899
|
-
title: '@general:actions.delete.title',
|
|
900
|
-
command: 'delete-entity',
|
|
901
|
-
priority: 'secondary',
|
|
902
|
-
type: AXPSystemActionType.Delete,
|
|
903
|
-
scope: AXPEntityCommandScope.Individual,
|
|
904
|
-
order: 100,
|
|
905
|
-
shortcuts: ['ctrl+shift+delete'],
|
|
906
|
-
};
|
|
907
|
-
}
|
|
908
|
-
function entityMasterCrudActions(options) {
|
|
909
|
-
const opts = {
|
|
910
|
-
create: true,
|
|
911
|
-
delete: true,
|
|
912
|
-
view: true,
|
|
913
|
-
edit: false,
|
|
914
|
-
...options,
|
|
915
|
-
};
|
|
916
|
-
const actions = [];
|
|
917
|
-
if (opts.create) {
|
|
918
|
-
actions.push(entityMasterCreateAction());
|
|
919
|
-
}
|
|
920
|
-
if (opts.delete) {
|
|
921
|
-
actions.push(entityMasterBulkDeleteAction());
|
|
922
|
-
actions.push(entityMasterDeleteAction());
|
|
923
|
-
}
|
|
924
|
-
if (opts.view) {
|
|
925
|
-
actions.push(entityMasterViewAction());
|
|
926
|
-
}
|
|
927
|
-
if (opts.edit) {
|
|
928
|
-
actions.push(entityMasterEditAction());
|
|
929
|
-
}
|
|
930
|
-
return actions;
|
|
931
|
-
}
|
|
932
|
-
function entityMasterRecordActions() {
|
|
933
|
-
return [entityMasterDeleteAction()];
|
|
934
|
-
}
|
|
935
|
-
// #endregion
|
|
936
|
-
// #region Details
|
|
937
|
-
function entityDetailsCreateActions(parentId) {
|
|
938
|
-
return {
|
|
939
|
-
title: '@general:actions.create.title',
|
|
940
|
-
command: {
|
|
941
|
-
name: 'Entity:Create',
|
|
942
|
-
options: {
|
|
943
|
-
process: {
|
|
944
|
-
redirect: false,
|
|
945
|
-
canCreateNewOne: true,
|
|
946
|
-
data: {
|
|
947
|
-
[parentId]: '{{context.eval("id")}}',
|
|
948
|
-
},
|
|
949
|
-
},
|
|
950
|
-
},
|
|
951
|
-
},
|
|
952
|
-
priority: 'primary',
|
|
953
|
-
type: AXPSystemActionType.Create,
|
|
954
|
-
scope: AXPEntityCommandScope.TypeLevel,
|
|
955
|
-
};
|
|
956
|
-
}
|
|
957
|
-
/**
|
|
958
|
-
* Type-level Create with empty `process.data`; the FK is supplied from `relatedEntity.persistence.foreignKeyField`
|
|
959
|
-
* when the related list is built (see `mergeForeignKeyFieldIntoCreateActions`).
|
|
960
|
-
*/
|
|
961
|
-
function entityDetailsCreateActionsDeferredParent() {
|
|
962
|
-
return {
|
|
963
|
-
title: '@general:actions.create.title',
|
|
964
|
-
command: {
|
|
965
|
-
name: 'Entity:Create',
|
|
966
|
-
options: {
|
|
967
|
-
process: {
|
|
968
|
-
redirect: false,
|
|
969
|
-
canCreateNewOne: true,
|
|
970
|
-
data: {},
|
|
971
|
-
},
|
|
972
|
-
},
|
|
973
|
-
},
|
|
974
|
-
priority: 'primary',
|
|
975
|
-
type: AXPSystemActionType.Create,
|
|
976
|
-
scope: AXPEntityCommandScope.TypeLevel,
|
|
977
|
-
};
|
|
978
|
-
}
|
|
979
|
-
/**
|
|
980
|
-
* Ensures each type-level `Entity:Create` action includes `process.data[foreignKeyField]` bound to the parent row id.
|
|
981
|
-
*/
|
|
982
|
-
function mergeForeignKeyFieldIntoCreateActions(foreignKeyField, actions) {
|
|
983
|
-
if (!foreignKeyField || !actions?.length) {
|
|
984
|
-
return actions ?? [];
|
|
985
|
-
}
|
|
986
|
-
return actions.map((a) => {
|
|
987
|
-
const cmd = a.command;
|
|
988
|
-
if (typeof cmd !== 'object' ||
|
|
989
|
-
!cmd ||
|
|
990
|
-
cmd.name !== 'Entity:Create' ||
|
|
991
|
-
a.scope !== AXPEntityCommandScope.TypeLevel) {
|
|
992
|
-
return a;
|
|
993
|
-
}
|
|
994
|
-
const opts = (cmd.options ?? {});
|
|
995
|
-
const proc = (opts['process'] ?? {});
|
|
996
|
-
const data = { ...(proc['data'] ?? {}) };
|
|
997
|
-
if (data[foreignKeyField] === undefined || data[foreignKeyField] === null || data[foreignKeyField] === '') {
|
|
998
|
-
data[foreignKeyField] = '{{ context.eval("id") }}';
|
|
999
|
-
}
|
|
1000
|
-
return {
|
|
1001
|
-
...a,
|
|
1002
|
-
command: {
|
|
1003
|
-
...cmd,
|
|
1004
|
-
options: { ...opts, process: { ...proc, data } },
|
|
1005
|
-
},
|
|
1006
|
-
};
|
|
1007
|
-
});
|
|
1008
|
-
}
|
|
1009
|
-
/** Property names hidden on nested Create from a related list (`excludeProperties` plus `foreignKeyField` when set). */
|
|
1010
|
-
function collectNestedCreateHiddenProperties(relatedEntity) {
|
|
1011
|
-
const fk = relatedEntity.persistence?.foreignKeyField;
|
|
1012
|
-
const merged = [...(relatedEntity.excludeProperties ?? [])];
|
|
1013
|
-
if (fk) {
|
|
1014
|
-
merged.push(fk);
|
|
1015
|
-
}
|
|
1016
|
-
const unique = [...new Set(merged)];
|
|
1017
|
-
return unique.length ? unique : undefined;
|
|
1018
|
-
}
|
|
1019
|
-
function entityDetailsSimpleCondition(fk) {
|
|
1020
|
-
return {
|
|
1021
|
-
name: fk,
|
|
1022
|
-
operator: { type: 'equal' },
|
|
1023
|
-
value: '{{context.eval("id")}}',
|
|
1024
|
-
};
|
|
1025
|
-
}
|
|
1026
|
-
function entityDetailsReferenceCondition(type) {
|
|
1027
|
-
return [
|
|
1028
|
-
{
|
|
1029
|
-
name: 'reference.id',
|
|
1030
|
-
operator: { type: 'equal' },
|
|
1031
|
-
value: '{{context.eval("id")}}',
|
|
1032
|
-
},
|
|
1033
|
-
{
|
|
1034
|
-
name: 'reference.type',
|
|
1035
|
-
operator: { type: 'equal' },
|
|
1036
|
-
value: type,
|
|
1037
|
-
},
|
|
1038
|
-
];
|
|
1039
|
-
}
|
|
1040
|
-
function entityDetailsEditAction() {
|
|
1041
|
-
return {
|
|
1042
|
-
title: '@general:actions.edit.title',
|
|
1043
|
-
// command: 'quick-modify-entity',
|
|
1044
|
-
command: 'Entity:Update',
|
|
1045
|
-
priority: 'secondary',
|
|
1046
|
-
type: AXPSystemActionType.Update,
|
|
1047
|
-
default: true,
|
|
1048
|
-
scope: AXPEntityCommandScope.Individual,
|
|
1049
|
-
};
|
|
1050
|
-
}
|
|
1051
|
-
function entityDetailsNewEditAction() {
|
|
1052
|
-
return {
|
|
1053
|
-
title: 'New Edit',
|
|
1054
|
-
command: {
|
|
1055
|
-
name: 'Entity:Update',
|
|
1056
|
-
},
|
|
1057
|
-
priority: 'secondary',
|
|
1058
|
-
type: AXPSystemActionType.Update,
|
|
1059
|
-
default: true,
|
|
1060
|
-
scope: AXPEntityCommandScope.Individual,
|
|
1061
|
-
};
|
|
1062
|
-
}
|
|
1063
|
-
function entityOverrideDetailsViewAction() {
|
|
1064
|
-
return {
|
|
1065
|
-
title: '@general:actions.view.title',
|
|
1066
|
-
command: 'open-entity',
|
|
1067
|
-
priority: 'secondary',
|
|
1068
|
-
hidden: true,
|
|
1069
|
-
type: AXPSystemActionType.View,
|
|
1070
|
-
scope: AXPEntityCommandScope.Individual,
|
|
1071
|
-
};
|
|
1072
|
-
}
|
|
1073
|
-
function entityDetailsCrudActions(parentId, options) {
|
|
1074
|
-
const opts = {
|
|
1075
|
-
create: true,
|
|
1076
|
-
delete: true,
|
|
1077
|
-
view: true,
|
|
1078
|
-
edit: true,
|
|
1079
|
-
...options,
|
|
1080
|
-
};
|
|
1081
|
-
const actions = [];
|
|
1082
|
-
if (opts.create) {
|
|
1083
|
-
if (parentId) {
|
|
1084
|
-
actions.push(entityDetailsCreateActions(parentId));
|
|
1085
|
-
}
|
|
1086
|
-
else {
|
|
1087
|
-
actions.push(entityDetailsCreateActionsDeferredParent());
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
if (opts.edit) {
|
|
1091
|
-
actions.push(entityDetailsEditAction());
|
|
1092
|
-
}
|
|
1093
|
-
if (opts.view) {
|
|
1094
|
-
actions.push(entityOverrideDetailsViewAction());
|
|
1095
|
-
}
|
|
1096
|
-
return actions;
|
|
1097
|
-
}
|
|
1098
|
-
function entityDetailsReferenceCreateActions(type) {
|
|
1099
|
-
return [
|
|
1100
|
-
{
|
|
1101
|
-
title: '@general:actions.create.title',
|
|
1102
|
-
command: {
|
|
1103
|
-
name: 'Entity:Create',
|
|
1104
|
-
options: {
|
|
1105
|
-
process: {
|
|
1106
|
-
redirect: false,
|
|
1107
|
-
canCreateNewOne: true,
|
|
1108
|
-
data: {
|
|
1109
|
-
reference: {
|
|
1110
|
-
id: '{{context.eval("id")}}',
|
|
1111
|
-
type: type,
|
|
1112
|
-
},
|
|
1113
|
-
},
|
|
1114
|
-
},
|
|
1115
|
-
},
|
|
1116
|
-
},
|
|
1117
|
-
priority: 'primary',
|
|
1118
|
-
type: AXPSystemActionType.Create,
|
|
1119
|
-
scope: AXPEntityCommandScope.TypeLevel,
|
|
1120
|
-
},
|
|
1121
|
-
entityDetailsEditAction(),
|
|
1122
|
-
entityOverrideDetailsViewAction(),
|
|
1123
|
-
];
|
|
1124
|
-
}
|
|
1125
857
|
/**
|
|
1126
858
|
* Computes a diff between two plain objects with array-aware semantics.
|
|
1127
859
|
* - For arrays of objects with an id field, computes added/removed by id.
|
|
@@ -1479,7 +1211,7 @@ class PropertyFilter {
|
|
|
1479
1211
|
const viewLayout = mainViewLayoutMap.get(prop.name);
|
|
1480
1212
|
const mergedProp = {
|
|
1481
1213
|
...prop,
|
|
1482
|
-
__layout: viewLayout?.layout,
|
|
1214
|
+
__layout: viewLayout?.layout ? cloneDeep(viewLayout.layout) : undefined,
|
|
1483
1215
|
__order: viewLayout?.layout?.order,
|
|
1484
1216
|
};
|
|
1485
1217
|
if (this.readonlyList?.has(prop.name)) {
|
|
@@ -1542,7 +1274,7 @@ class PropertyFilter {
|
|
|
1542
1274
|
const mergedProp = {
|
|
1543
1275
|
...prop,
|
|
1544
1276
|
__dataPath: dataPath,
|
|
1545
|
-
__layout: viewLayout?.layout,
|
|
1277
|
+
__layout: viewLayout?.layout ? cloneDeep(viewLayout.layout) : undefined,
|
|
1546
1278
|
__order: viewLayout?.layout?.order,
|
|
1547
1279
|
};
|
|
1548
1280
|
// Apply generic propertyOverrides extension (e.g. for identifier defaultValue on nested paths)
|
|
@@ -2051,6 +1783,9 @@ const GRID_COLUMNS = 12;
|
|
|
2051
1783
|
function getColSpanAt(layout, breakpoint) {
|
|
2052
1784
|
return layout?.positions?.[breakpoint]?.colSpan ?? GRID_COLUMNS;
|
|
2053
1785
|
}
|
|
1786
|
+
function getColStartAt(layout, breakpoint) {
|
|
1787
|
+
return layout?.positions?.[breakpoint]?.colStart;
|
|
1788
|
+
}
|
|
2054
1789
|
function setColSpanAt(layout, breakpoint, colSpan) {
|
|
2055
1790
|
if (!layout)
|
|
2056
1791
|
return;
|
|
@@ -2075,23 +1810,56 @@ function normalizeLayoutFillRowGaps(items, getLayout, getItemId) {
|
|
|
2075
1810
|
if (items.length === 0)
|
|
2076
1811
|
return scaleFactors;
|
|
2077
1812
|
for (const breakpoint of LAYOUT_BREAKPOINTS) {
|
|
2078
|
-
const colSpans = items.map((item) => getColSpanAt(getLayout(item), breakpoint));
|
|
2079
1813
|
let i = 0;
|
|
2080
|
-
while (i <
|
|
2081
|
-
let rowSum = 0;
|
|
1814
|
+
while (i < items.length) {
|
|
2082
1815
|
const rowStart = i;
|
|
2083
|
-
|
|
2084
|
-
|
|
1816
|
+
let rowHasExplicitColStart = false;
|
|
1817
|
+
let sequentialRowSum = 0;
|
|
1818
|
+
let explicitRowEnd = 0;
|
|
1819
|
+
while (i < items.length) {
|
|
1820
|
+
const layout = getLayout(items[i]);
|
|
1821
|
+
const colStart = getColStartAt(layout, breakpoint);
|
|
1822
|
+
const colSpan = getColSpanAt(layout, breakpoint);
|
|
1823
|
+
// colStart: 1 begins a new row (except for the first item in the current row)
|
|
1824
|
+
if (colStart === 1 && i > rowStart) {
|
|
1825
|
+
break;
|
|
1826
|
+
}
|
|
1827
|
+
if (colStart != null) {
|
|
1828
|
+
rowHasExplicitColStart = true;
|
|
1829
|
+
const end = colStart + colSpan;
|
|
1830
|
+
if (end - 1 > GRID_COLUMNS) {
|
|
1831
|
+
i++;
|
|
1832
|
+
break;
|
|
1833
|
+
}
|
|
1834
|
+
explicitRowEnd = Math.max(explicitRowEnd, end);
|
|
1835
|
+
i++;
|
|
1836
|
+
if (explicitRowEnd >= GRID_COLUMNS) {
|
|
1837
|
+
break;
|
|
1838
|
+
}
|
|
1839
|
+
continue;
|
|
1840
|
+
}
|
|
1841
|
+
if (sequentialRowSum + colSpan > GRID_COLUMNS && i > rowStart) {
|
|
1842
|
+
break;
|
|
1843
|
+
}
|
|
1844
|
+
if (sequentialRowSum + colSpan > GRID_COLUMNS && i === rowStart) {
|
|
1845
|
+
sequentialRowSum = colSpan;
|
|
1846
|
+
i++;
|
|
1847
|
+
break;
|
|
1848
|
+
}
|
|
1849
|
+
sequentialRowSum += colSpan;
|
|
2085
1850
|
i++;
|
|
1851
|
+
if (sequentialRowSum >= GRID_COLUMNS) {
|
|
1852
|
+
break;
|
|
1853
|
+
}
|
|
2086
1854
|
}
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
1855
|
+
// Rows with explicit colStart (e.g. 4+4+4 at columns 1/5/9) keep intentional gaps
|
|
1856
|
+
if (rowHasExplicitColStart) {
|
|
1857
|
+
continue;
|
|
2090
1858
|
}
|
|
2091
|
-
if (
|
|
1859
|
+
if (sequentialRowSum < GRID_COLUMNS && sequentialRowSum > 0 && i > rowStart) {
|
|
2092
1860
|
const lastIdx = i - 1;
|
|
2093
|
-
const oldColSpan =
|
|
2094
|
-
const fill = GRID_COLUMNS -
|
|
1861
|
+
const oldColSpan = getColSpanAt(getLayout(items[lastIdx]), breakpoint);
|
|
1862
|
+
const fill = GRID_COLUMNS - sequentialRowSum;
|
|
2095
1863
|
const newColSpan = Math.min(GRID_COLUMNS, oldColSpan + fill);
|
|
2096
1864
|
const layout = getLayout(items[lastIdx]);
|
|
2097
1865
|
if (layout) {
|
|
@@ -2586,7 +2354,7 @@ class AXPCreateEntityCommand {
|
|
|
2586
2354
|
}
|
|
2587
2355
|
const createFn = entityRef.commands?.create?.execute;
|
|
2588
2356
|
const updateFn = entityRef.commands?.update?.execute;
|
|
2589
|
-
const context = dialogRef.context();
|
|
2357
|
+
const context = merge({}, data, dialogRef.context());
|
|
2590
2358
|
console.log('context', context);
|
|
2591
2359
|
const hasPersistedId = hasPersistedRootId(context);
|
|
2592
2360
|
const persistFn = hasPersistedId ? updateFn : createFn;
|
|
@@ -2742,6 +2510,9 @@ class AXPUpdateEntityCommand {
|
|
|
2742
2510
|
this.entityService = inject(AXPEntityDefinitionRegistryService);
|
|
2743
2511
|
this.toastService = inject(AXToastService);
|
|
2744
2512
|
this.translationService = inject(AXTranslationService);
|
|
2513
|
+
this.formatService = inject(AXFormatService);
|
|
2514
|
+
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
2515
|
+
this.contextEvalFactory = inject(AXPContextEvalFactory);
|
|
2745
2516
|
this.eventService = inject(AXPBroadcastEventService);
|
|
2746
2517
|
}
|
|
2747
2518
|
//#endregion
|
|
@@ -2749,7 +2520,7 @@ class AXPUpdateEntityCommand {
|
|
|
2749
2520
|
async execute(input) {
|
|
2750
2521
|
const enableOperationToasts = await this.settingsService.get(AXPCommonSettings.EnableOperationToasts);
|
|
2751
2522
|
const dialogSize = input['dialogSize'];
|
|
2752
|
-
const { entity,
|
|
2523
|
+
const { entity, data, options } = input.__context__;
|
|
2753
2524
|
const excludeProperties = options?.excludeProperties;
|
|
2754
2525
|
const includeProperties = options?.includeProperties;
|
|
2755
2526
|
const decoration = options?.['decoration'];
|
|
@@ -2788,10 +2559,17 @@ class AXPUpdateEntityCommand {
|
|
|
2788
2559
|
if (headerTitle) {
|
|
2789
2560
|
chain = chain.title(headerTitle);
|
|
2790
2561
|
}
|
|
2791
|
-
else
|
|
2792
|
-
|
|
2793
|
-
const
|
|
2794
|
-
|
|
2562
|
+
else {
|
|
2563
|
+
let recordData = {};
|
|
2564
|
+
const recordId = typeof data === 'string' ? data : (data?.id ?? data?._id);
|
|
2565
|
+
if (recordId) {
|
|
2566
|
+
recordData = await this.entityForm.getRecordById(`${moduleName}.${entityName}`, String(recordId));
|
|
2567
|
+
}
|
|
2568
|
+
else if (typeof data === 'object' && data != null) {
|
|
2569
|
+
recordData = data;
|
|
2570
|
+
}
|
|
2571
|
+
const title = await resolveEntityModifyPopupTitle(entityRef, recordData, this.translationService, this.formatService, this.expressionEvaluator, this.contextEvalFactory, '@general:actions.edit.title');
|
|
2572
|
+
chain = chain.title(title);
|
|
2795
2573
|
}
|
|
2796
2574
|
const finalSize = layoutSize || dialogSize;
|
|
2797
2575
|
if (finalSize) {
|
|
@@ -2885,15 +2663,19 @@ var updateEntity_command = /*#__PURE__*/Object.freeze({
|
|
|
2885
2663
|
|
|
2886
2664
|
class AXPViewEntityDetailsCommand {
|
|
2887
2665
|
constructor() {
|
|
2888
|
-
//#region ----
|
|
2666
|
+
//#region ---- Services & Dependencies ----
|
|
2889
2667
|
this.entityForm = inject(AXPEntityFormBuilderService);
|
|
2890
2668
|
this.entityService = inject(AXPEntityDefinitionRegistryService);
|
|
2891
2669
|
this.translationService = inject(AXTranslationService);
|
|
2670
|
+
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
2671
|
+
this.contextEvalFactory = inject(AXPContextEvalFactory);
|
|
2892
2672
|
}
|
|
2893
2673
|
//#endregion
|
|
2894
|
-
//#region ----
|
|
2674
|
+
//#region ---- Command Execution ----
|
|
2895
2675
|
async execute(input) {
|
|
2896
|
-
const excludeProperties = input['excludeProperties']
|
|
2676
|
+
const excludeProperties = input['excludeProperties'] ??
|
|
2677
|
+
input?.options?.excludeProperties ??
|
|
2678
|
+
input?.__context__?.options?.excludeProperties;
|
|
2897
2679
|
const { entity, entityInfo, data } = input.__context__;
|
|
2898
2680
|
const [moduleName, entityName] = (entity || '').split('.');
|
|
2899
2681
|
if (!moduleName || !entityName) {
|
|
@@ -2904,10 +2686,9 @@ class AXPViewEntityDetailsCommand {
|
|
|
2904
2686
|
},
|
|
2905
2687
|
};
|
|
2906
2688
|
}
|
|
2907
|
-
await this.entityService.resolve(moduleName, entityName);
|
|
2689
|
+
const entityDef = await this.entityService.resolve(moduleName, entityName);
|
|
2908
2690
|
let dialogRef;
|
|
2909
2691
|
try {
|
|
2910
|
-
// Validate data type
|
|
2911
2692
|
if (!data || (typeof data !== 'string' && typeof data !== 'object')) {
|
|
2912
2693
|
return {
|
|
2913
2694
|
success: false,
|
|
@@ -2916,22 +2697,18 @@ class AXPViewEntityDetailsCommand {
|
|
|
2916
2697
|
},
|
|
2917
2698
|
};
|
|
2918
2699
|
}
|
|
2919
|
-
// Pass data directly to single() - it handles string | object internally
|
|
2920
2700
|
let chain = this.entityForm.entity(`${moduleName}.${entityName}`).single(data);
|
|
2921
2701
|
if (excludeProperties && excludeProperties.length > 0) {
|
|
2922
2702
|
chain = chain.exclude(...excludeProperties);
|
|
2923
2703
|
}
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
chain = chain.title(`${detailText}`);
|
|
2704
|
+
const dialogTitle = await this.resolveDialogTitle(entityDef, data);
|
|
2705
|
+
if (dialogTitle) {
|
|
2706
|
+
chain = chain.title(dialogTitle);
|
|
2928
2707
|
}
|
|
2929
2708
|
chain = chain.actions((actions) => {
|
|
2930
2709
|
actions.submit('@general:actions.ok.title');
|
|
2931
2710
|
});
|
|
2932
2711
|
dialogRef = await chain.show();
|
|
2933
|
-
// For single/view mode, only close action is available
|
|
2934
|
-
// No need to show any message when closing a read-only view
|
|
2935
2712
|
dialogRef.close();
|
|
2936
2713
|
return {
|
|
2937
2714
|
success: true,
|
|
@@ -2951,11 +2728,62 @@ class AXPViewEntityDetailsCommand {
|
|
|
2951
2728
|
};
|
|
2952
2729
|
}
|
|
2953
2730
|
finally {
|
|
2954
|
-
if (dialogRef) {
|
|
2731
|
+
if (dialogRef && typeof dialogRef === 'object' && dialogRef !== null && 'setLoading' in dialogRef) {
|
|
2955
2732
|
dialogRef.setLoading(false);
|
|
2956
2733
|
}
|
|
2957
2734
|
}
|
|
2958
2735
|
}
|
|
2736
|
+
//#endregion
|
|
2737
|
+
//#region ---- Title resolution ----
|
|
2738
|
+
async resolveDialogTitle(entityDef, data) {
|
|
2739
|
+
const titleTemplate = entityDef.interfaces?.master?.single?.title ??
|
|
2740
|
+
entityDef.formats?.searchResult?.title ??
|
|
2741
|
+
entityDef.formats?.individual;
|
|
2742
|
+
if (!titleTemplate || typeof titleTemplate !== 'string') {
|
|
2743
|
+
return this.translationService.translateAsync('@general:actions.detail.title');
|
|
2744
|
+
}
|
|
2745
|
+
if (!titleTemplate.includes('{{')) {
|
|
2746
|
+
const translated = await this.translationService.translateAsync(titleTemplate);
|
|
2747
|
+
return resolveMultiLanguageString(translated, this.translationService.getActiveLang()).trim() || translated;
|
|
2748
|
+
}
|
|
2749
|
+
const recordContext = await this.loadRecordContext(`${entityDef.module}.${entityDef.name}`, data);
|
|
2750
|
+
const scope = {
|
|
2751
|
+
context: this.contextEvalFactory.createScope(recordContext),
|
|
2752
|
+
};
|
|
2753
|
+
const evaluated = await this.expressionEvaluator.evaluate(titleTemplate, scope);
|
|
2754
|
+
const locale = this.translationService.getActiveLang();
|
|
2755
|
+
const text = resolveMultiLanguageString(evaluated, locale).trim() || String(evaluated ?? '').trim();
|
|
2756
|
+
if (text) {
|
|
2757
|
+
return text;
|
|
2758
|
+
}
|
|
2759
|
+
return this.translationService.translateAsync('@general:actions.detail.title');
|
|
2760
|
+
}
|
|
2761
|
+
async loadRecordContext(entityFullName, data) {
|
|
2762
|
+
if (typeof data === 'object' && data !== null && !Array.isArray(data)) {
|
|
2763
|
+
const hasNestedFields = get(data, 'subject.title') != null ||
|
|
2764
|
+
get(data, 'recordType.title') != null ||
|
|
2765
|
+
get(data, 'occurredDate') != null;
|
|
2766
|
+
if (hasNestedFields) {
|
|
2767
|
+
return data;
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
const recordId = typeof data === 'string' ? data : String(get(data, 'id') ?? '');
|
|
2771
|
+
if (!recordId) {
|
|
2772
|
+
return typeof data === 'object' && data !== null ? data : {};
|
|
2773
|
+
}
|
|
2774
|
+
try {
|
|
2775
|
+
const [moduleName, entityName] = entityFullName.split('.');
|
|
2776
|
+
const entity = await this.entityService.resolve(moduleName, entityName);
|
|
2777
|
+
const byKeyFn = entity?.queries?.byKey?.execute;
|
|
2778
|
+
if (typeof byKeyFn === 'function') {
|
|
2779
|
+
return (await byKeyFn(recordId)) ?? {};
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
catch {
|
|
2783
|
+
// Fall back to list row payload below.
|
|
2784
|
+
}
|
|
2785
|
+
return typeof data === 'object' && data !== null ? data : {};
|
|
2786
|
+
}
|
|
2959
2787
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPViewEntityDetailsCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2960
2788
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPViewEntityDetailsCommand, providedIn: 'root' }); }
|
|
2961
2789
|
}
|
|
@@ -2971,13 +2799,6 @@ var viewEntityDetails_command = /*#__PURE__*/Object.freeze({
|
|
|
2971
2799
|
AXPViewEntityDetailsCommand: AXPViewEntityDetailsCommand
|
|
2972
2800
|
});
|
|
2973
2801
|
|
|
2974
|
-
//#region ---- Datasource keys ----
|
|
2975
|
-
/** Platform entity layout datasource registry names. */
|
|
2976
|
-
const AXPEntityDataSourceKeys = {
|
|
2977
|
-
Entities: 'entities',
|
|
2978
|
-
};
|
|
2979
|
-
//#endregion
|
|
2980
|
-
|
|
2981
2802
|
const AXPEntityEventsKeys = {
|
|
2982
2803
|
REFRESH_LAYOUT: 'entity:refresh-layout',
|
|
2983
2804
|
REFRESH_DATA: 'entity:refresh-data',
|
|
@@ -3016,10 +2837,44 @@ function buildAXPRecordWorkflowInfo(params) {
|
|
|
3016
2837
|
...(params.pinnedVersion != null ? { pinnedVersion: params.pinnedVersion } : {}),
|
|
3017
2838
|
};
|
|
3018
2839
|
}
|
|
2840
|
+
//#endregion
|
|
3019
2841
|
|
|
3020
2842
|
//#region ---- Contracts barrel ----
|
|
3021
2843
|
//#endregion
|
|
3022
2844
|
|
|
2845
|
+
/** Common keys on denormalized expose stubs (e.g. `{ id, displayName }` from lookup expose). */
|
|
2846
|
+
const LOOKUP_EXPOSE_STUB_DISPLAY_FIELDS = ['displayName', 'title', 'name', 'fullName', 'code'];
|
|
2847
|
+
function resolveLookupItemFieldValue(item, field) {
|
|
2848
|
+
const direct = get(item, field);
|
|
2849
|
+
if (direct != null && direct !== '') {
|
|
2850
|
+
return direct;
|
|
2851
|
+
}
|
|
2852
|
+
if (!field.includes('.')) {
|
|
2853
|
+
return direct;
|
|
2854
|
+
}
|
|
2855
|
+
for (const fallback of LOOKUP_EXPOSE_STUB_DISPLAY_FIELDS) {
|
|
2856
|
+
const candidate = get(item, fallback);
|
|
2857
|
+
if (candidate != null && candidate !== '') {
|
|
2858
|
+
return candidate;
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
return direct;
|
|
2862
|
+
}
|
|
2863
|
+
function formatLookupFieldValue(raw, locale, translationService, resolveMultiLanguage) {
|
|
2864
|
+
if (raw == null || raw === '') {
|
|
2865
|
+
return '';
|
|
2866
|
+
}
|
|
2867
|
+
if (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') {
|
|
2868
|
+
return String(raw);
|
|
2869
|
+
}
|
|
2870
|
+
if (typeof raw === 'object' && !Array.isArray(raw)) {
|
|
2871
|
+
if (resolveMultiLanguage) {
|
|
2872
|
+
return resolveMultiLanguage(raw);
|
|
2873
|
+
}
|
|
2874
|
+
return resolveSearchableText(raw, locale, translationService);
|
|
2875
|
+
}
|
|
2876
|
+
return String(raw);
|
|
2877
|
+
}
|
|
3023
2878
|
//#region ---- Template resolution ----
|
|
3024
2879
|
/**
|
|
3025
2880
|
* Resolves the display template for a lookup item.
|
|
@@ -3061,9 +2916,9 @@ function resolveLookupDisplayField(entity, options) {
|
|
|
3061
2916
|
return found ?? 'title';
|
|
3062
2917
|
}
|
|
3063
2918
|
/**
|
|
3064
|
-
* Formats a lookup row for display using template and/or field resolution.
|
|
2919
|
+
* Formats a lookup row for display using template and/or field resolution (display tier).
|
|
3065
2920
|
*/
|
|
3066
|
-
function
|
|
2921
|
+
async function formatLookupItemDisplayAsync(item, entity, options, formatService, displayDeps, resolveMultiLanguage) {
|
|
3067
2922
|
if (item == null) {
|
|
3068
2923
|
return '';
|
|
3069
2924
|
}
|
|
@@ -3078,6 +2933,45 @@ function formatLookupItemDisplay(item, entity, options, formatService, resolveMu
|
|
|
3078
2933
|
}
|
|
3079
2934
|
const template = resolveLookupDisplayTemplate(entity, options);
|
|
3080
2935
|
if (template) {
|
|
2936
|
+
if (template.includes('{{') || template.includes('context.eval')) {
|
|
2937
|
+
const evaluated = await evaluateEntityDisplayTemplate(template, item, displayDeps.expressionEvaluator, displayDeps.locale, displayDeps.translationService, displayDeps.contextEvalFactory);
|
|
2938
|
+
const text = sanitizeResolvedEntityDisplayTitle(resolveSearchableText(evaluated, displayDeps.locale, displayDeps.translationService));
|
|
2939
|
+
if (text && !isUnresolvedEntityDisplayTemplate(text)) {
|
|
2940
|
+
return text;
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
else {
|
|
2944
|
+
const formatted = formatService.format(template, 'string', item);
|
|
2945
|
+
if (formatted) {
|
|
2946
|
+
const text = String(formatted);
|
|
2947
|
+
if (!isUnresolvedEntityDisplayTemplate(text)) {
|
|
2948
|
+
return text;
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
const field = resolveLookupDisplayField(entity, options);
|
|
2954
|
+
const raw = typeof item === 'object' && item != null ? resolveLookupItemFieldValue(item, field) : undefined;
|
|
2955
|
+
return formatLookupFieldValue(raw, displayDeps.locale, displayDeps.translationService, resolveMultiLanguage);
|
|
2956
|
+
}
|
|
2957
|
+
/**
|
|
2958
|
+
* @deprecated Prefer {@link formatLookupItemDisplayAsync} for expression templates with `context.eval`.
|
|
2959
|
+
*/
|
|
2960
|
+
function formatLookupItemDisplay(item, entity, options, formatService, resolveMultiLanguage) {
|
|
2961
|
+
if (item == null) {
|
|
2962
|
+
return '';
|
|
2963
|
+
}
|
|
2964
|
+
if (typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean') {
|
|
2965
|
+
return String(item);
|
|
2966
|
+
}
|
|
2967
|
+
if (typeof item !== 'object') {
|
|
2968
|
+
return '';
|
|
2969
|
+
}
|
|
2970
|
+
if (options.isMultiLanguage?.(item) && resolveMultiLanguage) {
|
|
2971
|
+
return resolveMultiLanguage(item);
|
|
2972
|
+
}
|
|
2973
|
+
const template = resolveLookupDisplayTemplate(entity, options);
|
|
2974
|
+
if (template && !template.includes('context.eval') && !template.includes('{{')) {
|
|
3081
2975
|
const formatted = formatService.format(template, 'string', item);
|
|
3082
2976
|
if (formatted) {
|
|
3083
2977
|
const text = String(formatted);
|
|
@@ -3087,8 +2981,8 @@ function formatLookupItemDisplay(item, entity, options, formatService, resolveMu
|
|
|
3087
2981
|
}
|
|
3088
2982
|
}
|
|
3089
2983
|
const field = resolveLookupDisplayField(entity, options);
|
|
3090
|
-
const raw =
|
|
3091
|
-
if (raw == null) {
|
|
2984
|
+
const raw = typeof item === 'object' && item != null ? resolveLookupItemFieldValue(item, field) : undefined;
|
|
2985
|
+
if (raw == null || raw === '') {
|
|
3092
2986
|
return '';
|
|
3093
2987
|
}
|
|
3094
2988
|
if (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') {
|
|
@@ -3111,6 +3005,8 @@ class AXPEntityDetailPopoverComponent {
|
|
|
3111
3005
|
this.queryService = inject(AXPQueryService);
|
|
3112
3006
|
this.formatService = inject(AXFormatService);
|
|
3113
3007
|
this.translation = inject(AXTranslationService);
|
|
3008
|
+
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
3009
|
+
this.contextEvalFactory = inject(AXPContextEvalFactory);
|
|
3114
3010
|
//#endregion
|
|
3115
3011
|
//#region ---- Inputs ----
|
|
3116
3012
|
this.entity = input.required(...(ngDevMode ? [{ debugName: "entity" }] : /* istanbul ignore next */ []));
|
|
@@ -3128,31 +3024,10 @@ class AXPEntityDetailPopoverComponent {
|
|
|
3128
3024
|
this.entityDetails = signal(null, ...(ngDevMode ? [{ debugName: "entityDetails" }] : /* istanbul ignore next */ []));
|
|
3129
3025
|
this.isLoadingDetails = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingDetails" }] : /* istanbul ignore next */ []));
|
|
3130
3026
|
this.isDetailPopoverOpen = signal(false, ...(ngDevMode ? [{ debugName: "isDetailPopoverOpen" }] : /* istanbul ignore next */ []));
|
|
3027
|
+
this.headerTitleVersion = 0;
|
|
3131
3028
|
/** Placeholder rows for the loading skeleton (matches typical property count). */
|
|
3132
3029
|
this.loadingSkeletonRows = [1, 2, 3, 4, 5];
|
|
3133
|
-
this.headerTitle =
|
|
3134
|
-
const details = this.entityDetails();
|
|
3135
|
-
const entityDefinition = details?.entityDefinition;
|
|
3136
|
-
const data = details?.entityData;
|
|
3137
|
-
if (data && entityDefinition) {
|
|
3138
|
-
const fromDetails = this.resolveLookupDisplayLabel(data, entityDefinition);
|
|
3139
|
-
if (fromDetails) {
|
|
3140
|
-
return fromDetails;
|
|
3141
|
-
}
|
|
3142
|
-
}
|
|
3143
|
-
const preset = this.displayTitle()?.trim();
|
|
3144
|
-
if (preset && !isUnresolvedEntityDisplayTemplate(preset)) {
|
|
3145
|
-
return preset;
|
|
3146
|
-
}
|
|
3147
|
-
const fallbackItem = this.item();
|
|
3148
|
-
if (fallbackItem) {
|
|
3149
|
-
const fromItem = this.resolveLookupDisplayLabel(fallbackItem, entityDefinition);
|
|
3150
|
-
if (fromItem) {
|
|
3151
|
-
return fromItem;
|
|
3152
|
-
}
|
|
3153
|
-
}
|
|
3154
|
-
return preset ?? '';
|
|
3155
|
-
}, ...(ngDevMode ? [{ debugName: "headerTitle" }] : /* istanbul ignore next */ []));
|
|
3030
|
+
this.headerTitle = signal('', ...(ngDevMode ? [{ debugName: "headerTitle" }] : /* istanbul ignore next */ []));
|
|
3156
3031
|
/**
|
|
3157
3032
|
* Stable list of property widgets for the template. Must be a signal (computed), not a method:
|
|
3158
3033
|
* calling a method from the template rebuilds nodes every CD cycle and can make the widget renderer loop.
|
|
@@ -3165,6 +3040,18 @@ class AXPEntityDetailPopoverComponent {
|
|
|
3165
3040
|
return [];
|
|
3166
3041
|
return this.buildEntityPropertiesWithWidgets(data, entityDefinition, this.textField(), this.valueField());
|
|
3167
3042
|
}, ...(ngDevMode ? [{ debugName: "entityPropertiesWithWidgets" }] : /* istanbul ignore next */ []));
|
|
3043
|
+
effect(() => {
|
|
3044
|
+
void this.translation.getActiveLang();
|
|
3045
|
+
const details = this.entityDetails();
|
|
3046
|
+
const preset = this.displayTitle();
|
|
3047
|
+
const fallbackItem = this.item();
|
|
3048
|
+
const version = ++this.headerTitleVersion;
|
|
3049
|
+
void this.resolveHeaderTitle(details?.entityDefinition, details?.entityData, preset, fallbackItem).then((title) => {
|
|
3050
|
+
if (version === this.headerTitleVersion) {
|
|
3051
|
+
this.headerTitle.set(title);
|
|
3052
|
+
}
|
|
3053
|
+
});
|
|
3054
|
+
});
|
|
3168
3055
|
}
|
|
3169
3056
|
//#endregion
|
|
3170
3057
|
//#region ---- Public Methods ----
|
|
@@ -3237,10 +3124,34 @@ class AXPEntityDetailPopoverComponent {
|
|
|
3237
3124
|
}
|
|
3238
3125
|
//#endregion
|
|
3239
3126
|
//#region ---- Helper Methods ----
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3127
|
+
async resolveHeaderTitle(entityDefinition, data, preset, fallbackItem) {
|
|
3128
|
+
if (data && entityDefinition) {
|
|
3129
|
+
const fromDetails = await this.resolveLookupDisplayLabelAsync(data, entityDefinition);
|
|
3130
|
+
if (fromDetails) {
|
|
3131
|
+
return fromDetails;
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
const presetTrimmed = preset?.trim();
|
|
3135
|
+
if (presetTrimmed && !isUnresolvedEntityDisplayTemplate(presetTrimmed)) {
|
|
3136
|
+
return presetTrimmed;
|
|
3137
|
+
}
|
|
3138
|
+
if (fallbackItem) {
|
|
3139
|
+
const fromItem = await this.resolveLookupDisplayLabelAsync(fallbackItem, entityDefinition);
|
|
3140
|
+
if (fromItem) {
|
|
3141
|
+
return fromItem;
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
return presetTrimmed ?? '';
|
|
3145
|
+
}
|
|
3146
|
+
async resolveLookupDisplayLabelAsync(item, entityDefinition) {
|
|
3147
|
+
const locale = this.translation.getActiveLang() ?? 'en-US';
|
|
3148
|
+
const label = await formatLookupItemDisplayAsync(item, entityDefinition ?? null, { textField: this.textField() }, this.formatService, {
|
|
3149
|
+
expressionEvaluator: this.expressionEvaluator,
|
|
3150
|
+
contextEvalFactory: this.contextEvalFactory,
|
|
3151
|
+
translationService: this.translation,
|
|
3152
|
+
locale,
|
|
3153
|
+
}, (value) => this.translation.resolve(value));
|
|
3154
|
+
return label && !isUnresolvedEntityDisplayTemplate(label) ? label : '';
|
|
3244
3155
|
}
|
|
3245
3156
|
/**
|
|
3246
3157
|
* Returns true if a value is meaningful for display (non-empty/non-null).
|
|
@@ -3405,14 +3316,24 @@ class AXPEntityDetailPopoverComponent {
|
|
|
3405
3316
|
resolveDataPath(prop, data) {
|
|
3406
3317
|
const iface = prop.schema?.interface;
|
|
3407
3318
|
const expose = iface?.options?.['expose'];
|
|
3319
|
+
const textField = iface?.options?.['textField']?.trim();
|
|
3408
3320
|
if (expose?.length) {
|
|
3409
|
-
// Try expanded path first (e.g. personTitle for personTitle.title)
|
|
3410
3321
|
const textTarget = expose.find((e) => e.source !== 'id');
|
|
3411
3322
|
if (textTarget) {
|
|
3412
3323
|
const expandedPath = textTarget.target.split('.')[0];
|
|
3413
3324
|
const expandedValue = get(data, expandedPath);
|
|
3414
3325
|
if (expandedValue != null && typeof expandedValue === 'object') {
|
|
3415
|
-
|
|
3326
|
+
if (textField) {
|
|
3327
|
+
if (this.hasMeaningfulValue(get(expandedValue, textField))) {
|
|
3328
|
+
return expandedPath;
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
else {
|
|
3332
|
+
const leaf = textTarget.target.split('.').pop();
|
|
3333
|
+
if (leaf && this.hasMeaningfulValue(get(expandedValue, leaf))) {
|
|
3334
|
+
return expandedPath;
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3416
3337
|
}
|
|
3417
3338
|
}
|
|
3418
3339
|
}
|
|
@@ -3424,7 +3345,7 @@ class AXPEntityDetailPopoverComponent {
|
|
|
3424
3345
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailPopoverComponent, decorators: [{
|
|
3425
3346
|
type: Component,
|
|
3426
3347
|
args: [{ selector: 'axp-entity-detail-popover', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, AXButtonModule, AXPopoverModule, AXPWidgetCoreModule, AXTranslationModule, AXSkeletonModule], template: "<ax-popover [openOn]=\"'manual'\" #detailPopover (openChange)=\"onDetailPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface dark:ax-dark-surface ax-p-4 ax-w-[min(600px,calc(100vw-2rem))]\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold ax-text-on-lightest-surface\">\n {{ headerTitle() }}\n </h3>\n @if (breadcrumb()) {\n <div class=\"ax-text-xs ax-text-neutral-500 ax-mt-1\">{{ breadcrumb() }}</div>\n }\n </div>\n @if (isLoadingDetails()) {\n <div class=\"ax-space-y-2 ax-mb-4\">\n @for (row of loadingSkeletonRows; track row) {\n <div class=\"ax-grid ax-grid-cols-[minmax(7rem,35%)_1fr] ax-gap-x-4 ax-items-start\">\n <ax-skeleton [animated]=\"true\" class=\"ax-h-4 ax-w-2/3 ax-rounded\"></ax-skeleton>\n @if (row === 2) {\n <ax-skeleton [animated]=\"true\" class=\"ax-h-16 ax-w-full ax-rounded\"></ax-skeleton>\n } @else {\n <ax-skeleton [animated]=\"true\" class=\"ax-h-4 ax-w-full ax-rounded\"></ax-skeleton>\n }\n </div>\n }\n </div>\n <div class=\"ax-flex ax-justify-end\">\n <ax-skeleton [animated]=\"true\" class=\"ax-h-9 ax-w-28 ax-rounded\"></ax-skeleton>\n </div>\n } @else if (entityDetails()) {\n <div class=\"ax-space-y-3 ax-mb-4\">\n <!-- Important Entity Data -->\n @if (entityDetails()?.entityData) {\n <axp-widgets-container [context]=\"entityDetails()?.entityData\">\n <div class=\"ax-space-y-2\">\n @for (item of entityPropertiesWithWidgets(); track item.name) {\n <div class=\"ax-grid ax-grid-cols-[minmax(7rem,35%)_1fr] ax-gap-x-4 ax-gap-y-1 ax-items-start\">\n <span class=\"ax-text-sm ax-font-medium ax-shrink-0\">{{ item.title | translate | async\n }}:</span>\n <div class=\"ax-min-w-0 ax-text-sm\">\n <ng-container axp-widget-renderer [node]=\"item.node\" [mode]=\"'view'\"></ng-container>\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n }\n </div>\n <div class=\"ax-flex ax-gap-2 ax-justify-end ax-sm\">\n <ax-button [color]=\"'primary'\" [look]=\"'solid'\" [text]=\"'@general:actions.open-details.title' | translate | async\"\n (click)=\"navigateToDetails()\">\n </ax-button>\n </div>\n }\n </div>\n</ax-popover>" }]
|
|
3427
|
-
}], propDecorators: { entity: [{ type: i0.Input, args: [{ isSignal: true, alias: "entity", required: true }] }], entityId: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityId", required: true }] }], textField: [{ type: i0.Input, args: [{ isSignal: true, alias: "textField", required: false }] }], valueField: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueField", required: false }] }], displayTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayTitle", required: false }] }], item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: false }] }], breadcrumb: [{ type: i0.Input, args: [{ isSignal: true, alias: "breadcrumb", required: false }] }], detailPopover: [{ type: i0.ViewChild, args: ['detailPopover', { isSignal: true }] }] } });
|
|
3348
|
+
}], ctorParameters: () => [], propDecorators: { entity: [{ type: i0.Input, args: [{ isSignal: true, alias: "entity", required: true }] }], entityId: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityId", required: true }] }], textField: [{ type: i0.Input, args: [{ isSignal: true, alias: "textField", required: false }] }], valueField: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueField", required: false }] }], displayTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayTitle", required: false }] }], item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: false }] }], breadcrumb: [{ type: i0.Input, args: [{ isSignal: true, alias: "breadcrumb", required: false }] }], detailPopover: [{ type: i0.ViewChild, args: ['detailPopover', { isSignal: true }] }] } });
|
|
3428
3349
|
|
|
3429
3350
|
class AXPEntityDetailPopoverService {
|
|
3430
3351
|
constructor() {
|
|
@@ -3976,7 +3897,6 @@ class AXPEntityPreloadFiltersContainerComponent extends AXPPageLayoutBaseCompone
|
|
|
3976
3897
|
super(...arguments);
|
|
3977
3898
|
//#region ---- Services & Dependencies ----
|
|
3978
3899
|
this.route = inject(ActivatedRoute);
|
|
3979
|
-
this.router = inject(Router);
|
|
3980
3900
|
this.entityService = inject(AXPEntityService);
|
|
3981
3901
|
this.filterOperatorMiddleware = inject(AXPFilterOperatorMiddlewareService);
|
|
3982
3902
|
//#endregion
|
|
@@ -4395,7 +4315,7 @@ class AXPEntityCommandTriggerViewModel {
|
|
|
4395
4315
|
this.priority = action.priority;
|
|
4396
4316
|
this.title = action.title;
|
|
4397
4317
|
this.separated = action.separated ?? false;
|
|
4398
|
-
this.color = action.color ?? resolvedLook.color;
|
|
4318
|
+
this.color = (action.color ?? resolvedLook.color);
|
|
4399
4319
|
this.icon = action.icon ?? resolvedLook.icon;
|
|
4400
4320
|
this.hidden = action.hidden ?? false;
|
|
4401
4321
|
this.disabled = action.disabled ?? false;
|
|
@@ -5265,7 +5185,7 @@ class AXPEntityMasterListViewModel {
|
|
|
5265
5185
|
}
|
|
5266
5186
|
}
|
|
5267
5187
|
//#endregion
|
|
5268
|
-
|
|
5188
|
+
createLogicExpressionScope(data) {
|
|
5269
5189
|
return {
|
|
5270
5190
|
context: {
|
|
5271
5191
|
eval: (path) => get(data, path),
|
|
@@ -5276,11 +5196,20 @@ class AXPEntityMasterListViewModel {
|
|
|
5276
5196
|
},
|
|
5277
5197
|
};
|
|
5278
5198
|
}
|
|
5199
|
+
createDisplayExpressionScope(data) {
|
|
5200
|
+
return {
|
|
5201
|
+
context: this.contextEvalFactory.createScope((data ?? {})),
|
|
5202
|
+
list: {
|
|
5203
|
+
view: () => this.view().name,
|
|
5204
|
+
views: () => this.views().map((v) => ({ name: v.name, title: v.title })),
|
|
5205
|
+
},
|
|
5206
|
+
};
|
|
5207
|
+
}
|
|
5279
5208
|
async resolveCommandNameExpression(commandName, data) {
|
|
5280
5209
|
if (!commandName || !commandName.includes('{{')) {
|
|
5281
5210
|
return commandName;
|
|
5282
5211
|
}
|
|
5283
|
-
const scope = this.
|
|
5212
|
+
const scope = this.createLogicExpressionScope(data);
|
|
5284
5213
|
const result = await this.expressionEvaluator.evaluate({ value: commandName }, scope);
|
|
5285
5214
|
const resolved = result?.value;
|
|
5286
5215
|
return typeof resolved === 'string' && resolved.trim() !== '' ? resolved : commandName;
|
|
@@ -5289,7 +5218,7 @@ class AXPEntityMasterListViewModel {
|
|
|
5289
5218
|
if (!title || !title.includes('{{')) {
|
|
5290
5219
|
return title;
|
|
5291
5220
|
}
|
|
5292
|
-
const scope = this.
|
|
5221
|
+
const scope = this.createDisplayExpressionScope(data);
|
|
5293
5222
|
const result = await this.expressionEvaluator.evaluate({ value: title }, scope);
|
|
5294
5223
|
const resolved = result?.value;
|
|
5295
5224
|
return typeof resolved === 'string' && resolved.trim() !== '' ? resolved : title;
|
|
@@ -5304,7 +5233,7 @@ class AXPEntityMasterListViewModel {
|
|
|
5304
5233
|
return '';
|
|
5305
5234
|
}
|
|
5306
5235
|
if (value.includes('{{')) {
|
|
5307
|
-
const scope = this.
|
|
5236
|
+
const scope = this.createDisplayExpressionScope(rowData);
|
|
5308
5237
|
const result = await this.expressionEvaluator.evaluate(value, scope);
|
|
5309
5238
|
if (result === false) {
|
|
5310
5239
|
return '';
|
|
@@ -5342,7 +5271,7 @@ class AXPEntityMasterListViewModel {
|
|
|
5342
5271
|
if (color == null || color === '') {
|
|
5343
5272
|
return 'default';
|
|
5344
5273
|
}
|
|
5345
|
-
const scope = this.
|
|
5274
|
+
const scope = this.createLogicExpressionScope(rowData);
|
|
5346
5275
|
const result = await this.expressionEvaluator.evaluate(color, scope);
|
|
5347
5276
|
if (result === false || result == null) {
|
|
5348
5277
|
return 'default';
|
|
@@ -5390,6 +5319,7 @@ class AXPEntityMasterListViewModel {
|
|
|
5390
5319
|
this.settings = this.injector.get(AXPSettingsService);
|
|
5391
5320
|
this.widgetResolver = this.injector.get(AXPWidgetRegistryService);
|
|
5392
5321
|
this.expressionEvaluator = this.injector.get(AXPExpressionEvaluatorService);
|
|
5322
|
+
this.contextEvalFactory = this.injector.get(AXPContextEvalFactory);
|
|
5393
5323
|
this.translation = this.injector.get(AXTranslationService);
|
|
5394
5324
|
this.commandService = this.injector.get(AXPCommandService);
|
|
5395
5325
|
this.eventService = this.injector.get(AXPBroadcastEventService);
|
|
@@ -5612,7 +5542,7 @@ class AXPEntityMasterListViewModel {
|
|
|
5612
5542
|
this.sortedFields = signal([], ...(ngDevMode ? [{ debugName: "sortedFields" }] : /* istanbul ignore next */ []));
|
|
5613
5543
|
//#endregion
|
|
5614
5544
|
this.evaluateExpressions = async (options, data) => {
|
|
5615
|
-
const scope = this.
|
|
5545
|
+
const scope = this.createLogicExpressionScope(data);
|
|
5616
5546
|
return await this.expressionEvaluator.evaluate(options, scope);
|
|
5617
5547
|
};
|
|
5618
5548
|
this.workflow.events$
|
|
@@ -6002,7 +5932,7 @@ class AXPEntityMasterListViewModel {
|
|
|
6002
5932
|
this.selectedCategory.set(category);
|
|
6003
5933
|
}
|
|
6004
5934
|
async getPrimaryActions() {
|
|
6005
|
-
const scope = this.
|
|
5935
|
+
const scope = this.createLogicExpressionScope(null);
|
|
6006
5936
|
const actions = await Promise.all(this.allActions()
|
|
6007
5937
|
.filter((a) => a.priority == 'primary' &&
|
|
6008
5938
|
((a.scope == AXPEntityCommandScope.Selected && this.hasSelectedItems()) ||
|
|
@@ -6019,7 +5949,7 @@ class AXPEntityMasterListViewModel {
|
|
|
6019
5949
|
return actions.filter(Boolean);
|
|
6020
5950
|
}
|
|
6021
5951
|
async getSecondaryActions() {
|
|
6022
|
-
const scope = this.
|
|
5952
|
+
const scope = this.createLogicExpressionScope(null);
|
|
6023
5953
|
const actions = await Promise.all(this.allActions()
|
|
6024
5954
|
.filter((a) => a.priority == 'secondary' &&
|
|
6025
5955
|
((a.scope == AXPEntityCommandScope.Selected && this.hasSelectedItems()) ||
|
|
@@ -6036,7 +5966,7 @@ class AXPEntityMasterListViewModel {
|
|
|
6036
5966
|
return actions.filter(Boolean);
|
|
6037
5967
|
}
|
|
6038
5968
|
async secondaryRowActions(rowData) {
|
|
6039
|
-
const scope = this.
|
|
5969
|
+
const scope = this.createLogicExpressionScope(rowData);
|
|
6040
5970
|
const actions = await Promise.all(this.allActions()
|
|
6041
5971
|
.filter((a) => a.scope === AXPEntityCommandScope.Individual && a.priority === 'secondary')
|
|
6042
5972
|
.map(async (a) => {
|
|
@@ -7059,6 +6989,9 @@ class AXPEntityModifySectionPopupAction extends AXPWorkflowAction {
|
|
|
7059
6989
|
this.popupService = inject(AXPopupService);
|
|
7060
6990
|
this.platform = inject(AXPlatform);
|
|
7061
6991
|
this.translateService = inject(AXTranslationService);
|
|
6992
|
+
this.formatService = inject(AXFormatService);
|
|
6993
|
+
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
6994
|
+
this.contextEvalFactory = inject(AXPContextEvalFactory);
|
|
7062
6995
|
this.entityRegistery = inject(AXPEntityDefinitionRegistryService);
|
|
7063
6996
|
this.config = inject(AXP_ENTITY_CONFIG_TOKEN);
|
|
7064
6997
|
this.factory = inject(AXPEntityMasterUpdateViewModelFactory);
|
|
@@ -7076,7 +7009,7 @@ class AXPEntityModifySectionPopupAction extends AXPWorkflowAction {
|
|
|
7076
7009
|
title: headerTitle
|
|
7077
7010
|
? headerTitle
|
|
7078
7011
|
: title ??
|
|
7079
|
-
|
|
7012
|
+
(await resolveEntityModifyPopupTitle(entityRef, vm.context(), this.translateService, this.formatService, this.expressionEvaluator, this.contextEvalFactory)),
|
|
7080
7013
|
size: this.platform.is('Mobile') || this.platform.is('SM') ? 'full' : 'md',
|
|
7081
7014
|
data: {
|
|
7082
7015
|
vm,
|
|
@@ -12313,6 +12246,7 @@ class AXPEntityListTableService {
|
|
|
12313
12246
|
const evaluatedOptions = await this.evaluateExpressions(action?.options, data);
|
|
12314
12247
|
const options = this.mergeRelatedListFormOptions(command, evaluatedOptions, relatedListExcludeProperties);
|
|
12315
12248
|
if (this.commandService.exists(command)) {
|
|
12249
|
+
const excludeProperties = options['excludeProperties'];
|
|
12316
12250
|
await this.commandService.execute(command, {
|
|
12317
12251
|
__context__: {
|
|
12318
12252
|
entity: getEntityInfo(entity).source,
|
|
@@ -12329,6 +12263,7 @@ class AXPEntityListTableService {
|
|
|
12329
12263
|
},
|
|
12330
12264
|
options,
|
|
12331
12265
|
metadata: action?.metadata,
|
|
12266
|
+
...(excludeProperties?.length ? { excludeProperties } : {}),
|
|
12332
12267
|
});
|
|
12333
12268
|
}
|
|
12334
12269
|
else {
|
|
@@ -12354,7 +12289,7 @@ class AXPEntityListTableService {
|
|
|
12354
12289
|
mergeRelatedListFormOptions(command, evaluatedOptions, relatedListExcludeProperties) {
|
|
12355
12290
|
const exclusions = relatedListExcludeProperties?.filter(Boolean);
|
|
12356
12291
|
if (!exclusions?.length ||
|
|
12357
|
-
(command !== 'Entity:Create' && command !== 'Entity:Update')) {
|
|
12292
|
+
(command !== 'Entity:Create' && command !== 'Entity:Update' && command !== 'Entity:View')) {
|
|
12358
12293
|
return evaluatedOptions;
|
|
12359
12294
|
}
|
|
12360
12295
|
return {
|
|
@@ -13898,6 +13833,8 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13898
13833
|
super(...arguments);
|
|
13899
13834
|
this.formatService = inject(AXFormatService);
|
|
13900
13835
|
this.translation = inject(AXTranslationService);
|
|
13836
|
+
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
13837
|
+
this.contextEvalFactory = inject(AXPContextEvalFactory);
|
|
13901
13838
|
this.entityResolver = inject(AXPEntityDefinitionRegistryService);
|
|
13902
13839
|
this.entity = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entity" }] : /* istanbul ignore next */ []));
|
|
13903
13840
|
this.multiple = computed(() => this.options()['multiple'], ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
|
|
@@ -13931,7 +13868,7 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13931
13868
|
if (typeof item == 'object') {
|
|
13932
13869
|
return {
|
|
13933
13870
|
id: item[this.valueField()],
|
|
13934
|
-
text: this.getDisplayRaw(item),
|
|
13871
|
+
text: await this.getDisplayRaw(item),
|
|
13935
13872
|
};
|
|
13936
13873
|
}
|
|
13937
13874
|
const def = this.entityDef();
|
|
@@ -13942,7 +13879,7 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13942
13879
|
this.loading.set(false);
|
|
13943
13880
|
return {
|
|
13944
13881
|
id: fetchedItem[this.valueField()],
|
|
13945
|
-
text: this.getDisplayRaw(fetchedItem),
|
|
13882
|
+
text: await this.getDisplayRaw(fetchedItem),
|
|
13946
13883
|
};
|
|
13947
13884
|
}
|
|
13948
13885
|
return {
|
|
@@ -13950,12 +13887,17 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13950
13887
|
text: item,
|
|
13951
13888
|
};
|
|
13952
13889
|
}
|
|
13953
|
-
getDisplayRaw(item) {
|
|
13954
|
-
const
|
|
13890
|
+
async getDisplayRaw(item) {
|
|
13891
|
+
const locale = this.translation.getActiveLang() ?? 'en-US';
|
|
13892
|
+
return formatLookupItemDisplayAsync(item, this.entityDef(), {
|
|
13955
13893
|
displayFormat: this.options()['displayFormat'],
|
|
13956
13894
|
textField: this.textField(),
|
|
13957
|
-
}, this.formatService,
|
|
13958
|
-
|
|
13895
|
+
}, this.formatService, {
|
|
13896
|
+
expressionEvaluator: this.expressionEvaluator,
|
|
13897
|
+
contextEvalFactory: this.contextEvalFactory,
|
|
13898
|
+
translationService: this.translation,
|
|
13899
|
+
locale,
|
|
13900
|
+
}, (value) => this.translation.resolve(value));
|
|
13959
13901
|
}
|
|
13960
13902
|
get __class() {
|
|
13961
13903
|
const cls = {};
|
|
@@ -15105,6 +15047,8 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
|
|
|
15105
15047
|
this.formatService = inject(AXFormatService);
|
|
15106
15048
|
this.translateService = inject(AXTranslationService);
|
|
15107
15049
|
this.entityDataSelectorService = inject(AXPEntityDataSelectorService);
|
|
15050
|
+
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
15051
|
+
this.contextEvalFactory = inject(AXPContextEvalFactory);
|
|
15108
15052
|
//#endregion
|
|
15109
15053
|
//#region ---- Inputs ----
|
|
15110
15054
|
this.selectedItems = input.required(...(ngDevMode ? [{ debugName: "selectedItems" }] : /* istanbul ignore next */ []));
|
|
@@ -15134,6 +15078,8 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
|
|
|
15134
15078
|
//#region ---- Internal State ----
|
|
15135
15079
|
this.searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : /* istanbul ignore next */ []));
|
|
15136
15080
|
this.isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
15081
|
+
this.itemLabels = signal({}, ...(ngDevMode ? [{ debugName: "itemLabels" }] : /* istanbul ignore next */ []));
|
|
15082
|
+
this.itemLabelsVersion = 0;
|
|
15137
15083
|
//#endregion
|
|
15138
15084
|
//#region ---- View Children ----
|
|
15139
15085
|
this.tagBox = viewChild('tagBoxComponent', ...(ngDevMode ? [{ debugName: "tagBox" }] : /* istanbul ignore next */ []));
|
|
@@ -15156,6 +15102,31 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
|
|
|
15156
15102
|
}
|
|
15157
15103
|
}
|
|
15158
15104
|
}, ...(ngDevMode ? [{ debugName: "#focusEffect" }] : /* istanbul ignore next */ []));
|
|
15105
|
+
this.#itemLabelsEffect = effect(() => {
|
|
15106
|
+
void this.translateService.getActiveLang();
|
|
15107
|
+
const items = this.selectedItemsValue();
|
|
15108
|
+
const entityDef = this.entityDef()();
|
|
15109
|
+
const valueField = this.valueFieldValue();
|
|
15110
|
+
const version = ++this.itemLabelsVersion;
|
|
15111
|
+
void Promise.all(items.map(async (item) => {
|
|
15112
|
+
const id = String(get(item, valueField) ?? '');
|
|
15113
|
+
const label = await formatLookupItemDisplayAsync(item, entityDef, {
|
|
15114
|
+
displayFormat: this.displayFormatValue(),
|
|
15115
|
+
textField: this.displayFieldValue(),
|
|
15116
|
+
}, this.formatService, {
|
|
15117
|
+
expressionEvaluator: this.expressionEvaluator,
|
|
15118
|
+
contextEvalFactory: this.contextEvalFactory,
|
|
15119
|
+
translationService: this.translateService,
|
|
15120
|
+
locale: this.translateService.getActiveLang() ?? 'en-US',
|
|
15121
|
+
}, (value) => this.translateService.resolve(value));
|
|
15122
|
+
return [id, label];
|
|
15123
|
+
})).then((entries) => {
|
|
15124
|
+
if (version !== this.itemLabelsVersion) {
|
|
15125
|
+
return;
|
|
15126
|
+
}
|
|
15127
|
+
this.itemLabels.set(Object.fromEntries(entries));
|
|
15128
|
+
});
|
|
15129
|
+
}, ...(ngDevMode ? [{ debugName: "#itemLabelsEffect" }] : /* istanbul ignore next */ []));
|
|
15159
15130
|
//#endregion
|
|
15160
15131
|
//#region ---- Computed Properties ----
|
|
15161
15132
|
this.tagBoxComponent = computed(() => this.tagBox(), ...(ngDevMode ? [{ debugName: "tagBoxComponent" }] : /* istanbul ignore next */ []));
|
|
@@ -15171,6 +15142,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
|
|
|
15171
15142
|
this.placeholderValue = computed(() => this.placeholder()?.() ?? '', ...(ngDevMode ? [{ debugName: "placeholderValue" }] : /* istanbul ignore next */ []));
|
|
15172
15143
|
}
|
|
15173
15144
|
#focusEffect;
|
|
15145
|
+
#itemLabelsEffect;
|
|
15174
15146
|
focus() {
|
|
15175
15147
|
this.shouldFocus.set(true);
|
|
15176
15148
|
}
|
|
@@ -15236,11 +15208,9 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
|
|
|
15236
15208
|
}
|
|
15237
15209
|
//#endregion
|
|
15238
15210
|
//#region ---- Utility Methods ----
|
|
15239
|
-
|
|
15240
|
-
|
|
15241
|
-
|
|
15242
|
-
textField: this.displayFieldValue(),
|
|
15243
|
-
}, this.formatService, (value) => this.translateService.resolve(value));
|
|
15211
|
+
getItemLabel(item) {
|
|
15212
|
+
const id = String(get(item, this.valueFieldValue()) ?? '');
|
|
15213
|
+
return this.itemLabels()[id] ?? '';
|
|
15244
15214
|
}
|
|
15245
15215
|
/**
|
|
15246
15216
|
* Get current input value from tag box
|
|
@@ -15387,7 +15357,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
|
|
|
15387
15357
|
</ax-tag-box>
|
|
15388
15358
|
<ng-template #tagTemplate let-item let-index="index">
|
|
15389
15359
|
<div class="ax-inline-flex ax-items-center ax-gap-1.5 ax-rounded-md ax-px-3 ax-py-1 ax-text-sm ax-surface">
|
|
15390
|
-
<span>{{
|
|
15360
|
+
<span>{{ getItemLabel(item) }}</span>
|
|
15391
15361
|
<button type="button" (click)="tagBoxComponent.removeItem(index)">
|
|
15392
15362
|
<ax-icon class="ax-icon ax-icon-close"></ax-icon>
|
|
15393
15363
|
</button>
|
|
@@ -15447,7 +15417,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
15447
15417
|
</ax-tag-box>
|
|
15448
15418
|
<ng-template #tagTemplate let-item let-index="index">
|
|
15449
15419
|
<div class="ax-inline-flex ax-items-center ax-gap-1.5 ax-rounded-md ax-px-3 ax-py-1 ax-text-sm ax-surface">
|
|
15450
|
-
<span>{{
|
|
15420
|
+
<span>{{ getItemLabel(item) }}</span>
|
|
15451
15421
|
<button type="button" (click)="tagBoxComponent.removeItem(index)">
|
|
15452
15422
|
<ax-icon class="ax-icon ax-icon-close"></ax-icon>
|
|
15453
15423
|
</button>
|
|
@@ -15925,6 +15895,8 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
15925
15895
|
this.entityService = inject(AXPEntityService);
|
|
15926
15896
|
this.entityResolver = inject(AXPEntityDefinitionRegistryService);
|
|
15927
15897
|
this.queryExecutor = inject(AXPQueryExecutor);
|
|
15898
|
+
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
15899
|
+
this.contextEvalFactory = inject(AXPContextEvalFactory);
|
|
15928
15900
|
//#endregion
|
|
15929
15901
|
//#region ---- View Children ----
|
|
15930
15902
|
this.moreButton = viewChild('moreButton', ...(ngDevMode ? [{ debugName: "moreButton" }] : /* istanbul ignore next */ []));
|
|
@@ -15962,11 +15934,16 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
15962
15934
|
this.resolveError = signal(null, ...(ngDevMode ? [{ debugName: "resolveError" }] : /* istanbul ignore next */ []));
|
|
15963
15935
|
this.summaryLabel = signal('', ...(ngDevMode ? [{ debugName: "summaryLabel" }] : /* istanbul ignore next */ []));
|
|
15964
15936
|
this.popoverHeader = signal('', ...(ngDevMode ? [{ debugName: "popoverHeader" }] : /* istanbul ignore next */ []));
|
|
15937
|
+
this.mainItemLabels = signal([], ...(ngDevMode ? [{ debugName: "mainItemLabels" }] : /* istanbul ignore next */ []));
|
|
15938
|
+
this.lazyPopoverItemLabels = signal([], ...(ngDevMode ? [{ debugName: "lazyPopoverItemLabels" }] : /* istanbul ignore next */ []));
|
|
15965
15939
|
this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : /* istanbul ignore next */ []));
|
|
15966
15940
|
this.hydratedDisplayItems = signal(null, ...(ngDevMode ? [{ debugName: "hydratedDisplayItems" }] : /* istanbul ignore next */ []));
|
|
15967
15941
|
this.hydrateRequestId = 0;
|
|
15942
|
+
this.mainLabelsVersion = 0;
|
|
15943
|
+
this.lazyPopoverLabelsVersion = 0;
|
|
15968
15944
|
//#endregion
|
|
15969
15945
|
//#region ---- Computed ----
|
|
15946
|
+
this.popoverItemLabels = computed(() => this.isHydratedStrategy() ? this.mainItemLabels() : this.lazyPopoverItemLabels(), ...(ngDevMode ? [{ debugName: "popoverItemLabels" }] : /* istanbul ignore next */ []));
|
|
15970
15947
|
this.displayItems = computed(() => isNil(this.rawValue)
|
|
15971
15948
|
? []
|
|
15972
15949
|
: castArray(this.rawValue)
|
|
@@ -16086,6 +16063,36 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
16086
16063
|
}
|
|
16087
16064
|
void this.hydrateScalarIds(entityKey, values);
|
|
16088
16065
|
});
|
|
16066
|
+
effect(() => {
|
|
16067
|
+
void this.translation.getActiveLang();
|
|
16068
|
+
this.entityDef();
|
|
16069
|
+
const items = this.allItems();
|
|
16070
|
+
const version = ++this.mainLabelsVersion;
|
|
16071
|
+
void this.resolveLabelsForItems(items).then((labels) => {
|
|
16072
|
+
if (version === this.mainLabelsVersion) {
|
|
16073
|
+
this.mainItemLabels.set(labels);
|
|
16074
|
+
}
|
|
16075
|
+
});
|
|
16076
|
+
});
|
|
16077
|
+
effect(() => {
|
|
16078
|
+
if (this.isHydratedStrategy()) {
|
|
16079
|
+
return;
|
|
16080
|
+
}
|
|
16081
|
+
void this.translation.getActiveLang();
|
|
16082
|
+
this.entityDef();
|
|
16083
|
+
const status = this.resolveStatus();
|
|
16084
|
+
const items = this.resolvedPopoverItems();
|
|
16085
|
+
if (status !== 'ready') {
|
|
16086
|
+
this.lazyPopoverItemLabels.set([]);
|
|
16087
|
+
return;
|
|
16088
|
+
}
|
|
16089
|
+
const version = ++this.lazyPopoverLabelsVersion;
|
|
16090
|
+
void this.resolveLabelsForItems(items).then((labels) => {
|
|
16091
|
+
if (version === this.lazyPopoverLabelsVersion) {
|
|
16092
|
+
this.lazyPopoverItemLabels.set(labels);
|
|
16093
|
+
}
|
|
16094
|
+
});
|
|
16095
|
+
});
|
|
16089
16096
|
}
|
|
16090
16097
|
//#endregion
|
|
16091
16098
|
//#region ---- Public methods ----
|
|
@@ -16140,7 +16147,9 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
16140
16147
|
let resolvedTitle = '';
|
|
16141
16148
|
if (headerItem != null && this.hasDisplayTextOnLookupValue(headerItem)) {
|
|
16142
16149
|
resolvedTitle =
|
|
16143
|
-
typeof headerItem === 'object'
|
|
16150
|
+
typeof headerItem === 'object'
|
|
16151
|
+
? await this.resolveItemLabel(headerItem)
|
|
16152
|
+
: this.formatDisplayValue(headerItem);
|
|
16144
16153
|
}
|
|
16145
16154
|
else if (!this.isMultiValueLookup()) {
|
|
16146
16155
|
const rowText = this.getRowDisplayTextFromTextField();
|
|
@@ -16149,8 +16158,7 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
16149
16158
|
}
|
|
16150
16159
|
}
|
|
16151
16160
|
if (!resolvedTitle) {
|
|
16152
|
-
|
|
16153
|
-
resolvedTitle = typeof displayTitle === 'string' ? displayTitle : this.translation.resolve(displayTitle);
|
|
16161
|
+
resolvedTitle = await this.resolveItemLabel(headerItem);
|
|
16154
16162
|
if (isUnresolvedEntityDisplayTemplate(resolvedTitle)) {
|
|
16155
16163
|
resolvedTitle = '';
|
|
16156
16164
|
}
|
|
@@ -16210,8 +16218,22 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
16210
16218
|
const values = castArray(raw).filter((value) => value != null && value !== '');
|
|
16211
16219
|
return values.length > 0 && values.every((value) => this.hasDisplayTextOnLookupValue(value));
|
|
16212
16220
|
}
|
|
16213
|
-
|
|
16214
|
-
|
|
16221
|
+
getItemLabel(index) {
|
|
16222
|
+
return this.mainItemLabels()[index] ?? '';
|
|
16223
|
+
}
|
|
16224
|
+
getPopoverItemLabel(index) {
|
|
16225
|
+
return this.popoverItemLabels()[index] ?? '';
|
|
16226
|
+
}
|
|
16227
|
+
//#endregion
|
|
16228
|
+
//#region ---- Private methods ----
|
|
16229
|
+
async resolveLabelsForItems(items) {
|
|
16230
|
+
return Promise.all(items.map((item) => this.resolveItemLabel(item)));
|
|
16231
|
+
}
|
|
16232
|
+
async resolveItemLabel(item) {
|
|
16233
|
+
if (item == null) {
|
|
16234
|
+
return '';
|
|
16235
|
+
}
|
|
16236
|
+
if (typeof item === 'object' && this.translation.isValidMultiLanguageObject(item)) {
|
|
16215
16237
|
return this.translation.resolve(item);
|
|
16216
16238
|
}
|
|
16217
16239
|
if (!this.isMultiValueLookup()) {
|
|
@@ -16220,16 +16242,19 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
16220
16242
|
return this.formatDisplayValue(rowText);
|
|
16221
16243
|
}
|
|
16222
16244
|
}
|
|
16223
|
-
if (
|
|
16224
|
-
if (typeof item
|
|
16225
|
-
return this.
|
|
16245
|
+
if (this.hasDisplayTextOnLookupValue(item)) {
|
|
16246
|
+
if (typeof item !== 'object') {
|
|
16247
|
+
return this.formatDisplayValue(item);
|
|
16226
16248
|
}
|
|
16227
|
-
return this.formatDisplayValue(item);
|
|
16228
16249
|
}
|
|
16229
|
-
|
|
16250
|
+
const locale = this.translation.getActiveLang() ?? 'en-US';
|
|
16251
|
+
return formatLookupItemDisplayAsync(item, this.entityDef(), this.lookupDisplayOptions(), this.formatService, {
|
|
16252
|
+
expressionEvaluator: this.expressionEvaluator,
|
|
16253
|
+
contextEvalFactory: this.contextEvalFactory,
|
|
16254
|
+
translationService: this.translation,
|
|
16255
|
+
locale,
|
|
16256
|
+
}, (value) => this.translation.resolve(value));
|
|
16230
16257
|
}
|
|
16231
|
-
//#endregion
|
|
16232
|
-
//#region ---- Private methods ----
|
|
16233
16258
|
async refreshSummaryLabel(count) {
|
|
16234
16259
|
const text = await this.translation.translateAsync('@general:widgets.lookup.column.items-count', {
|
|
16235
16260
|
params: { count: String(count) },
|
|
@@ -16522,10 +16547,6 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
16522
16547
|
return !isNil(candidate) && candidate !== '' && !this.isLikelyEntityId(candidate);
|
|
16523
16548
|
});
|
|
16524
16549
|
}
|
|
16525
|
-
renderLookupLabel(value) {
|
|
16526
|
-
const label = formatLookupItemDisplay(value, this.entityDef(), this.lookupDisplayOptions(), this.formatService, (item) => this.translation.resolve(item));
|
|
16527
|
-
return typeof label === 'string' ? label : this.translation.resolve(label);
|
|
16528
|
-
}
|
|
16529
16550
|
formatDisplayValue(value) {
|
|
16530
16551
|
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
16531
16552
|
return String(value);
|
|
@@ -16546,11 +16567,11 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
16546
16567
|
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value) || /^\d+$/.test(value);
|
|
16547
16568
|
}
|
|
16548
16569
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetColumnComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
16549
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLookupWidgetColumnComponent, isStandalone: true, selector: "ng-component", inputs: { rawValue: "rawValue", rowData: "rowData" }, viewQueries: [{ propertyName: "moreButton", first: true, predicate: ["moreButton"], descendants: true, isSignal: true }, { propertyName: "lazyTrigger", first: true, predicate: ["lazyTrigger"], descendants: true, isSignal: true }, { propertyName: "morePopover", first: true, predicate: ["morePopover"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@if (isHydratedStrategy()) {\n<div class=\"ax-relative ax-flex ax-min-w-0 ax-items-center ax-gap-1\">\n @for (item of visibleItems(); track $index) {\n
|
|
16570
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLookupWidgetColumnComponent, isStandalone: true, selector: "ng-component", inputs: { rawValue: "rawValue", rowData: "rowData" }, viewQueries: [{ propertyName: "moreButton", first: true, predicate: ["moreButton"], descendants: true, isSignal: true }, { propertyName: "lazyTrigger", first: true, predicate: ["lazyTrigger"], descendants: true, isSignal: true }, { propertyName: "morePopover", first: true, predicate: ["morePopover"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@if (isHydratedStrategy()) {\n<div class=\"ax-relative ax-flex ax-min-w-0 ax-items-center ax-gap-1\">\n @for (item of visibleItems(); track $index) {\n <span [class.ax-cursor-pointer]=\"detailPopoverEnabled()\" [class.hover:ax-text-primary]=\"detailPopoverEnabled()\"\n [class.hover:ax-underline]=\"detailPopoverEnabled()\" (click)=\"handleItemClick($index)\">\n {{ getItemLabel($index) }}\n </span>\n @if ($index < visibleItems().length - 1) { <span class=\"ax-text-muted\">\u2022</span>\n }\n } @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n @if (hasMoreItems()) {\n <span\n class=\"ax-absolute ax-end-0 ax-flex ax-h-full ax-cursor-pointer ax-items-center ax-px-1 hover:ax-primary-lighter\"\n (click)=\"showMoreItems(); $event.stopPropagation()\" #moreButton>\n <i class=\"fa-light fa-ellipsis-vertical\"></i>\n </span>\n }\n</div>\n} @else {\n<div class=\"ax-flex ax-min-w-0 ax-items-center ax-gap-1\">\n @if (displayCount() > 0) {\n <span class=\"ax-cursor-pointer ax-text-primary hover:ax-underline\"\n (click)=\"openLazyPopover(); $event.stopPropagation()\" #lazyTrigger>\n {{ summaryLabel() }}\n </span>\n } @else {\n <span class=\"ax-text-muted\">---</span>\n }\n</div>\n}\n\n<ax-popover [openOn]=\"'manual'\" #morePopover (openChange)=\"onPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface dark:ax-dark-surface ax-min-w-[280px] ax-rounded-lg ax-border ax-p-4 ax-shadow-lg\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold\">{{ popoverHeader() }}</h3>\n </div>\n\n @if (!isHydratedStrategy() && resolveStatus() === 'loading') {\n <div class=\"ax-flex ax-min-h-[120px] ax-items-center ax-justify-center\">\n <ax-loading></ax-loading>\n </div>\n } @else if (!isHydratedStrategy() && resolveStatus() === 'error') {\n <div class=\"ax-text-danger ax-text-sm\">{{ resolveError() }}</div>\n } @else {\n <div class=\"ax-flex ax-max-h-64 ax-flex-col ax-gap-3\">\n @for (item of popoverListItems(); track $index) {\n <span [class.ax-cursor-pointer]=\"detailPopoverEnabled()\" [class.hover:ax-text-primary]=\"detailPopoverEnabled()\"\n [class.hover:ax-underline]=\"detailPopoverEnabled()\" (click)=\"handlePopoverItemClick($index)\">\n {{ getPopoverItemLabel($index) }}\n </span>\n } @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n </div>\n }\n </div>\n</ax-popover>", dependencies: [{ kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i1$2.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "closeOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
16550
16571
|
}
|
|
16551
16572
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetColumnComponent, decorators: [{
|
|
16552
16573
|
type: Component,
|
|
16553
|
-
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, imports: [AXLoadingModule, AXPopoverModule], inputs: ['rawValue', 'rowData'], template: "@if (isHydratedStrategy()) {\n<div class=\"ax-relative ax-flex ax-min-w-0 ax-items-center ax-gap-1\">\n @for (item of visibleItems(); track $index) {\n
|
|
16574
|
+
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, imports: [AXLoadingModule, AXPopoverModule], inputs: ['rawValue', 'rowData'], template: "@if (isHydratedStrategy()) {\n<div class=\"ax-relative ax-flex ax-min-w-0 ax-items-center ax-gap-1\">\n @for (item of visibleItems(); track $index) {\n <span [class.ax-cursor-pointer]=\"detailPopoverEnabled()\" [class.hover:ax-text-primary]=\"detailPopoverEnabled()\"\n [class.hover:ax-underline]=\"detailPopoverEnabled()\" (click)=\"handleItemClick($index)\">\n {{ getItemLabel($index) }}\n </span>\n @if ($index < visibleItems().length - 1) { <span class=\"ax-text-muted\">\u2022</span>\n }\n } @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n @if (hasMoreItems()) {\n <span\n class=\"ax-absolute ax-end-0 ax-flex ax-h-full ax-cursor-pointer ax-items-center ax-px-1 hover:ax-primary-lighter\"\n (click)=\"showMoreItems(); $event.stopPropagation()\" #moreButton>\n <i class=\"fa-light fa-ellipsis-vertical\"></i>\n </span>\n }\n</div>\n} @else {\n<div class=\"ax-flex ax-min-w-0 ax-items-center ax-gap-1\">\n @if (displayCount() > 0) {\n <span class=\"ax-cursor-pointer ax-text-primary hover:ax-underline\"\n (click)=\"openLazyPopover(); $event.stopPropagation()\" #lazyTrigger>\n {{ summaryLabel() }}\n </span>\n } @else {\n <span class=\"ax-text-muted\">---</span>\n }\n</div>\n}\n\n<ax-popover [openOn]=\"'manual'\" #morePopover (openChange)=\"onPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface dark:ax-dark-surface ax-min-w-[280px] ax-rounded-lg ax-border ax-p-4 ax-shadow-lg\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold\">{{ popoverHeader() }}</h3>\n </div>\n\n @if (!isHydratedStrategy() && resolveStatus() === 'loading') {\n <div class=\"ax-flex ax-min-h-[120px] ax-items-center ax-justify-center\">\n <ax-loading></ax-loading>\n </div>\n } @else if (!isHydratedStrategy() && resolveStatus() === 'error') {\n <div class=\"ax-text-danger ax-text-sm\">{{ resolveError() }}</div>\n } @else {\n <div class=\"ax-flex ax-max-h-64 ax-flex-col ax-gap-3\">\n @for (item of popoverListItems(); track $index) {\n <span [class.ax-cursor-pointer]=\"detailPopoverEnabled()\" [class.hover:ax-text-primary]=\"detailPopoverEnabled()\"\n [class.hover:ax-underline]=\"detailPopoverEnabled()\" (click)=\"handlePopoverItemClick($index)\">\n {{ getPopoverItemLabel($index) }}\n </span>\n } @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n </div>\n }\n </div>\n</ax-popover>" }]
|
|
16554
16575
|
}], ctorParameters: () => [], propDecorators: { moreButton: [{ type: i0.ViewChild, args: ['moreButton', { isSignal: true }] }], lazyTrigger: [{ type: i0.ViewChild, args: ['lazyTrigger', { isSignal: true }] }], morePopover: [{ type: i0.ViewChild, args: ['morePopover', { isSignal: true }] }] } });
|
|
16555
16576
|
|
|
16556
16577
|
var lookupWidgetColumn_component = /*#__PURE__*/Object.freeze({
|
|
@@ -21813,13 +21834,20 @@ class AXPPageDetailsConverter extends AXPBaseRelatedEntityConverter {
|
|
|
21813
21834
|
const p = relatedEntity?.persistence || {};
|
|
21814
21835
|
const strategy = p.strategy || 'embedded';
|
|
21815
21836
|
const mappedTargets = Object.keys(p.map || {}).map((k) => (k || '').split('.')[0]);
|
|
21837
|
+
const excludeProperties = relatedEntity.excludeProperties && relatedEntity.excludeProperties.length > 0
|
|
21838
|
+
? new Set(relatedEntity.excludeProperties)
|
|
21839
|
+
: undefined;
|
|
21816
21840
|
const helpers = {
|
|
21817
21841
|
...baseHelpers,
|
|
21818
21842
|
getPropertyByGroupId: (groupId) => {
|
|
21819
|
-
|
|
21820
|
-
if (strategy
|
|
21821
|
-
|
|
21822
|
-
|
|
21843
|
+
let props = baseHelpers.getPropertyByGroupId(groupId) ?? [];
|
|
21844
|
+
if (strategy === 'referenced' && mappedTargets.length > 0) {
|
|
21845
|
+
props = props.filter((prop) => !mappedTargets.includes(prop?.name ?? ''));
|
|
21846
|
+
}
|
|
21847
|
+
if (excludeProperties) {
|
|
21848
|
+
props = props.filter((prop) => !excludeProperties.has(prop.name ?? ''));
|
|
21849
|
+
}
|
|
21850
|
+
return props;
|
|
21823
21851
|
},
|
|
21824
21852
|
};
|
|
21825
21853
|
const evaluateExpressions = async (actionData) => {
|
|
@@ -21937,18 +21965,70 @@ class AXPPageDetailsConverter extends AXPBaseRelatedEntityConverter {
|
|
|
21937
21965
|
}
|
|
21938
21966
|
createLoadFunction(entityDef, relatedEntity, evaluateExpressions) {
|
|
21939
21967
|
return async (context) => {
|
|
21940
|
-
const
|
|
21968
|
+
const conditions = relatedEntity.conditions ?? [];
|
|
21969
|
+
if (conditions.length > 0) {
|
|
21970
|
+
const evaluatedFilters = await Promise.all(conditions.map(async (c) => ({
|
|
21971
|
+
field: c.name,
|
|
21972
|
+
operator: c.operator,
|
|
21973
|
+
value: await evaluateExpressions(c.value),
|
|
21974
|
+
})));
|
|
21975
|
+
if (conditions.length === 1 && conditions[0].name === 'id') {
|
|
21976
|
+
const byKeyFn = entityDef?.queries?.byKey?.execute;
|
|
21977
|
+
const id = evaluatedFilters[0]?.value;
|
|
21978
|
+
const result = id ? await byKeyFn(id) : null;
|
|
21979
|
+
return { success: true, data: result ?? {} };
|
|
21980
|
+
}
|
|
21981
|
+
const listFn = entityDef?.queries?.list?.execute;
|
|
21982
|
+
const filter = evaluatedFilters.length === 1
|
|
21983
|
+
? evaluatedFilters[0]
|
|
21984
|
+
: { logic: 'and', filters: evaluatedFilters };
|
|
21985
|
+
const page = await listFn({ skip: 0, take: 1, filter });
|
|
21986
|
+
const item = page?.items?.[0];
|
|
21987
|
+
const data = item ? { ...item } : {};
|
|
21988
|
+
if (!item) {
|
|
21989
|
+
for (const evaluated of evaluatedFilters) {
|
|
21990
|
+
if (evaluated.field) {
|
|
21991
|
+
set(data, evaluated.field, evaluated.value);
|
|
21992
|
+
}
|
|
21993
|
+
}
|
|
21994
|
+
}
|
|
21995
|
+
return { success: true, data };
|
|
21996
|
+
}
|
|
21997
|
+
const fn = entityDef?.queries?.byKey?.execute;
|
|
21941
21998
|
const conditionValues = relatedEntity.conditions?.map((c) => c.value) ?? [];
|
|
21942
21999
|
const evaluatedConditionValues = await Promise.all(conditionValues.map((c) => evaluateExpressions(c)));
|
|
21943
22000
|
const id = evaluatedConditionValues[0];
|
|
21944
|
-
const result = await fn(id);
|
|
21945
|
-
return { success: true, data: result };
|
|
22001
|
+
const result = id ? await fn(id) : null;
|
|
22002
|
+
return { success: true, data: result ?? {} };
|
|
21946
22003
|
};
|
|
21947
22004
|
}
|
|
21948
22005
|
createExecuteFunction(entityDef, actions, evaluateExpressions, converterContext) {
|
|
21949
22006
|
return async (e, context) => {
|
|
21950
22007
|
try {
|
|
21951
22008
|
if (e.name === 'update-entity') {
|
|
22009
|
+
const recordId = context?.['id'];
|
|
22010
|
+
if (!recordId) {
|
|
22011
|
+
const createFn = entityDef?.commands?.create?.execute;
|
|
22012
|
+
const created = await createFn(context);
|
|
22013
|
+
if (created && typeof created === 'object' && 'success' in created) {
|
|
22014
|
+
const cmd = created;
|
|
22015
|
+
if (!cmd.success) {
|
|
22016
|
+
const errorText = commandMessageTextForError(cmd.message?.text) || 'Failed to create entity';
|
|
22017
|
+
return {
|
|
22018
|
+
success: false,
|
|
22019
|
+
message: cmd.message ?? { text: errorText },
|
|
22020
|
+
};
|
|
22021
|
+
}
|
|
22022
|
+
return {
|
|
22023
|
+
success: true,
|
|
22024
|
+
data: cmd.data ?? created,
|
|
22025
|
+
};
|
|
22026
|
+
}
|
|
22027
|
+
return {
|
|
22028
|
+
success: true,
|
|
22029
|
+
data: created,
|
|
22030
|
+
};
|
|
22031
|
+
}
|
|
21952
22032
|
const fn = entityDef?.commands?.update?.execute;
|
|
21953
22033
|
const result = await fn(context);
|
|
21954
22034
|
if (result && typeof result === 'object' && 'success' in result) {
|
|
@@ -22210,11 +22290,16 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
|
|
|
22210
22290
|
const excludeForUpdate = commandName === 'Entity:Update' &&
|
|
22211
22291
|
relatedEntity.excludeProperties &&
|
|
22212
22292
|
relatedEntity.excludeProperties.length > 0;
|
|
22293
|
+
const excludeForView = commandName === 'Entity:View' &&
|
|
22294
|
+
relatedEntity.excludeProperties &&
|
|
22295
|
+
relatedEntity.excludeProperties.length > 0;
|
|
22213
22296
|
const mergedOptions = excludeForCreate
|
|
22214
22297
|
? { ...evaluatedOptions, excludeProperties: createExcludes }
|
|
22215
22298
|
: excludeForUpdate
|
|
22216
22299
|
? { ...evaluatedOptions, excludeProperties: relatedEntity.excludeProperties }
|
|
22217
|
-
:
|
|
22300
|
+
: excludeForView
|
|
22301
|
+
? { ...evaluatedOptions, excludeProperties: relatedEntity.excludeProperties }
|
|
22302
|
+
: evaluatedOptions;
|
|
22218
22303
|
if (context.commandService.exists(commandName)) {
|
|
22219
22304
|
// check options for evaluation
|
|
22220
22305
|
await context.commandService.execute(commandName, {
|
|
@@ -22233,6 +22318,7 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
|
|
|
22233
22318
|
},
|
|
22234
22319
|
options: mergedOptions,
|
|
22235
22320
|
metadata: action.metadata,
|
|
22321
|
+
...(excludeForView ? { excludeProperties: relatedEntity.excludeProperties } : {}),
|
|
22236
22322
|
});
|
|
22237
22323
|
}
|
|
22238
22324
|
else {
|
|
@@ -23143,6 +23229,7 @@ class AXPLayoutAdapterFactory {
|
|
|
23143
23229
|
this.layoutAdapterBuilder = layoutAdapterBuilder;
|
|
23144
23230
|
this.filterOperatorMiddleware = filterOperatorMiddleware;
|
|
23145
23231
|
this.pageComponentConverter = inject(AXPPageComponentConverter);
|
|
23232
|
+
this.contextEvalFactory = inject(AXPContextEvalFactory);
|
|
23146
23233
|
}
|
|
23147
23234
|
async createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies) {
|
|
23148
23235
|
const entity = await entityResolver.resolve(moduleName, entityName);
|
|
@@ -23196,9 +23283,7 @@ class AXPLayoutAdapterFactory {
|
|
|
23196
23283
|
if (hidden && typeof hidden === 'string') {
|
|
23197
23284
|
try {
|
|
23198
23285
|
const scope = {
|
|
23199
|
-
context:
|
|
23200
|
-
eval: (path) => get(rootContext, path),
|
|
23201
|
-
},
|
|
23286
|
+
context: this.contextEvalFactory.createScope(rootContext),
|
|
23202
23287
|
};
|
|
23203
23288
|
const result = await dependencies.expressionEvaluator.evaluate({ hidden }, scope);
|
|
23204
23289
|
hidden = result.hidden;
|
|
@@ -23360,9 +23445,7 @@ class AXPLayoutAdapterFactory {
|
|
|
23360
23445
|
}
|
|
23361
23446
|
const scope = {
|
|
23362
23447
|
...rootContext,
|
|
23363
|
-
context:
|
|
23364
|
-
eval: (path) => get(rootContext, path),
|
|
23365
|
-
},
|
|
23448
|
+
context: this.contextEvalFactory.createScope(rootContext),
|
|
23366
23449
|
};
|
|
23367
23450
|
const title = await dependencies.expressionEvaluator.evaluate(titleTemplate, scope);
|
|
23368
23451
|
return title;
|
|
@@ -24171,7 +24254,7 @@ const AXPCrudModifier = {
|
|
|
24171
24254
|
queries.list = {
|
|
24172
24255
|
execute: async (e) => {
|
|
24173
24256
|
const res = await dataService.query(e);
|
|
24174
|
-
//
|
|
24257
|
+
//console.log('query', res, ctx.module.get() + '.' + ctx.name.get(), e);
|
|
24175
24258
|
return res;
|
|
24176
24259
|
},
|
|
24177
24260
|
type: AXPEntityQueryType.List,
|
|
@@ -24204,6 +24287,68 @@ class AXPEntityCommandSearchDefinitionProvider {
|
|
|
24204
24287
|
function moduleNameToI18nScope(moduleName) {
|
|
24205
24288
|
return moduleName.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');
|
|
24206
24289
|
}
|
|
24290
|
+
//#region ---- Entity search definition builder ----
|
|
24291
|
+
function buildEntitySearchDefinition(entity, manifestRegistry) {
|
|
24292
|
+
const manifest = manifestRegistry.get(entity.module);
|
|
24293
|
+
const i18nScope = manifest?.i18n ?? moduleNameToI18nScope(entity.module);
|
|
24294
|
+
const searchTitleTemplate = entity.formats.searchResult?.title;
|
|
24295
|
+
const titleContext = buildEntitySearchTitleContext(entity, searchTitleTemplate);
|
|
24296
|
+
return {
|
|
24297
|
+
name: `Module.${entity.module}.${entity.name}`,
|
|
24298
|
+
title: `@${i18nScope}:module.title`,
|
|
24299
|
+
group: `Module.${entity.module}`,
|
|
24300
|
+
icon: entity.icon ?? 'fa-solid fa-objects-column',
|
|
24301
|
+
order: 4,
|
|
24302
|
+
format: {
|
|
24303
|
+
title: searchTitleTemplate,
|
|
24304
|
+
description: entity.formats.searchResult?.description ?? `${entity.module} / ${entity.title}`,
|
|
24305
|
+
id: '{{data.id}}',
|
|
24306
|
+
titleFallbackTemplates: titleContext.fallbackTemplates,
|
|
24307
|
+
titleFallbackFields: titleContext.fallbackFields,
|
|
24308
|
+
},
|
|
24309
|
+
actions: [
|
|
24310
|
+
{
|
|
24311
|
+
name: 'open-entity',
|
|
24312
|
+
type: AXPSystemActionType.View,
|
|
24313
|
+
priority: 'primary',
|
|
24314
|
+
},
|
|
24315
|
+
],
|
|
24316
|
+
};
|
|
24317
|
+
}
|
|
24318
|
+
//#endregion
|
|
24319
|
+
//#region ---- Lazy resolver ----
|
|
24320
|
+
class AXPEntitySearchDefinitionLazyResolver {
|
|
24321
|
+
constructor() {
|
|
24322
|
+
this.entityResolver = inject(AXPEntityResolver);
|
|
24323
|
+
this.manifestRegistry = inject(AXPModuleManifestRegistry);
|
|
24324
|
+
this.resolved = new Map();
|
|
24325
|
+
}
|
|
24326
|
+
async resolve(definitionName) {
|
|
24327
|
+
const cached = this.resolved.get(definitionName);
|
|
24328
|
+
if (cached) {
|
|
24329
|
+
return cached;
|
|
24330
|
+
}
|
|
24331
|
+
const match = definitionName.match(/^Module\.([^.]+)\.(.+)$/);
|
|
24332
|
+
if (!match) {
|
|
24333
|
+
return null;
|
|
24334
|
+
}
|
|
24335
|
+
const [, moduleName, entityName] = match;
|
|
24336
|
+
await this.manifestRegistry.initialize();
|
|
24337
|
+
const entity = await this.entityResolver.get(moduleName, entityName);
|
|
24338
|
+
if (!entity) {
|
|
24339
|
+
return null;
|
|
24340
|
+
}
|
|
24341
|
+
const definition = buildEntitySearchDefinition(entity, this.manifestRegistry);
|
|
24342
|
+
this.resolved.set(definitionName, definition);
|
|
24343
|
+
return definition;
|
|
24344
|
+
}
|
|
24345
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntitySearchDefinitionLazyResolver, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
24346
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntitySearchDefinitionLazyResolver }); }
|
|
24347
|
+
}
|
|
24348
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntitySearchDefinitionLazyResolver, decorators: [{
|
|
24349
|
+
type: Injectable
|
|
24350
|
+
}] });
|
|
24351
|
+
|
|
24207
24352
|
class AXPEntitySearchDefinitionProvider {
|
|
24208
24353
|
constructor() {
|
|
24209
24354
|
this.entityRegister = inject(AXPEntityDefinitionRegistryService);
|
|
@@ -24211,28 +24356,13 @@ class AXPEntitySearchDefinitionProvider {
|
|
|
24211
24356
|
}
|
|
24212
24357
|
async provide(context) {
|
|
24213
24358
|
await this.manifestRegistry.initialize();
|
|
24214
|
-
this.entityRegister.getAll()
|
|
24215
|
-
const
|
|
24216
|
-
|
|
24217
|
-
|
|
24218
|
-
|
|
24219
|
-
context.addDefinition(`Module.${entity.module}.${entity.name}`, `@${i18nScope}:module.title`, `Module.${entity.module}`, entity.icon ?? 'fa-solid fa-objects-column', 4, {
|
|
24220
|
-
actions: [
|
|
24221
|
-
{
|
|
24222
|
-
name: 'open-entity',
|
|
24223
|
-
type: 'view',
|
|
24224
|
-
priority: 'primary',
|
|
24225
|
-
},
|
|
24226
|
-
],
|
|
24227
|
-
format: {
|
|
24228
|
-
title: searchTitleTemplate,
|
|
24229
|
-
description: (entity.formats.searchResult?.description) ?? `${entity.module} / ${entity.title}`,
|
|
24230
|
-
id: '{{data.id}}',
|
|
24231
|
-
titleFallbackTemplates: titleContext.fallbackTemplates,
|
|
24232
|
-
titleFallbackFields: titleContext.fallbackFields,
|
|
24233
|
-
},
|
|
24359
|
+
for (const entity of this.entityRegister.getAll()) {
|
|
24360
|
+
const definition = buildEntitySearchDefinition(entity, this.manifestRegistry);
|
|
24361
|
+
context.addDefinition(definition.name, definition.title, definition.group, definition.icon, definition.order, {
|
|
24362
|
+
actions: definition.actions,
|
|
24363
|
+
format: definition.format,
|
|
24234
24364
|
});
|
|
24235
|
-
}
|
|
24365
|
+
}
|
|
24236
24366
|
}
|
|
24237
24367
|
}
|
|
24238
24368
|
|
|
@@ -24338,9 +24468,9 @@ class AXPMiddlewareEntityStorageService extends AXPEntityStorageService {
|
|
|
24338
24468
|
...init,
|
|
24339
24469
|
};
|
|
24340
24470
|
}
|
|
24341
|
-
async initial(entityName, collection
|
|
24471
|
+
async initial(entityName, collection) {
|
|
24342
24472
|
const ctx = this.createCtx('initial', entityName, { data: collection });
|
|
24343
|
-
return this.run(ctx, () => this.backend.initial(ctx.entityName, ctx.data
|
|
24473
|
+
return this.run(ctx, () => this.backend.initial(ctx.entityName, ctx.data));
|
|
24344
24474
|
}
|
|
24345
24475
|
async getOne(entityName, id) {
|
|
24346
24476
|
const key = getDedupKey('getOne', entityName, { id });
|
|
@@ -24624,6 +24754,9 @@ class AXPQuickEntityModifyPopupAction extends AXPWorkflowAction {
|
|
|
24624
24754
|
this.popupService = inject(AXPopupService);
|
|
24625
24755
|
this.platform = inject(AXPlatform);
|
|
24626
24756
|
this.translateService = inject(AXTranslationService);
|
|
24757
|
+
this.formatService = inject(AXFormatService);
|
|
24758
|
+
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
24759
|
+
this.contextEvalFactory = inject(AXPContextEvalFactory);
|
|
24627
24760
|
this.entityRegistery = inject(AXPEntityDefinitionRegistryService);
|
|
24628
24761
|
this.config = inject(AXP_ENTITY_CONFIG_TOKEN);
|
|
24629
24762
|
this.factory = inject(AXPEntityMasterUpdateViewModelFactory);
|
|
@@ -24633,10 +24766,8 @@ class AXPQuickEntityModifyPopupAction extends AXPWorkflowAction {
|
|
|
24633
24766
|
const data = context.getVariable('data');
|
|
24634
24767
|
const entityRef = await this.entityRegistery.resolve(moduleName, entityName);
|
|
24635
24768
|
const { parentKey } = entityRef;
|
|
24636
|
-
console.log(data);
|
|
24637
24769
|
const { id } = data;
|
|
24638
|
-
const
|
|
24639
|
-
const properties = interfaces?.master?.update?.properties?.map((p) => p.name) || [];
|
|
24770
|
+
const properties = entityRef.interfaces?.master?.update?.properties?.map((p) => p.name) || [];
|
|
24640
24771
|
const vm = await this.factory.create(moduleName, entityName, id, properties);
|
|
24641
24772
|
const options = context.getVariable('options');
|
|
24642
24773
|
const decoration = options?.['decoration'];
|
|
@@ -24646,12 +24777,11 @@ class AXPQuickEntityModifyPopupAction extends AXPWorkflowAction {
|
|
|
24646
24777
|
if (parentKey) {
|
|
24647
24778
|
context.setVariable('parentKey', parentKey);
|
|
24648
24779
|
}
|
|
24649
|
-
console.log(`${this.translateService.translateSync('entity.modify')}`);
|
|
24650
24780
|
const com = await this.config.viewers.master.modify();
|
|
24651
24781
|
const popup = await this.popupService.open(com, {
|
|
24652
24782
|
title: headerTitle
|
|
24653
24783
|
? headerTitle
|
|
24654
|
-
:
|
|
24784
|
+
: await resolveEntityModifyPopupTitle(entityRef, vm.context(), this.translateService, this.formatService, this.expressionEvaluator, this.contextEvalFactory),
|
|
24655
24785
|
size: this.platform.is('Mobile') || this.platform.is('SM') ? 'full' : size ? size : 'md',
|
|
24656
24786
|
data: {
|
|
24657
24787
|
vm,
|
|
@@ -24958,7 +25088,7 @@ function routesFacory() {
|
|
|
24958
25088
|
const refreshChanged = from.queryParams['_ts'] !== to.queryParams['_ts'];
|
|
24959
25089
|
return entityChanged || idChanged || refreshChanged;
|
|
24960
25090
|
},
|
|
24961
|
-
data: { reuse:
|
|
25091
|
+
data: { reuse: 'queryParamsChange' },
|
|
24962
25092
|
},
|
|
24963
25093
|
{
|
|
24964
25094
|
path: 'e/:entity/:id',
|
|
@@ -24991,6 +25121,15 @@ class AXPEntityModule {
|
|
|
24991
25121
|
AXPAttachmentsPluginModule, i1$3.AXPWorkflowModule, AXPWidgetCoreModule,
|
|
24992
25122
|
LayoutBuilderModule] }); }
|
|
24993
25123
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityModule, providers: [
|
|
25124
|
+
{
|
|
25125
|
+
provide: AXP_REPEATER_ENTITY_BY_KEY_LOOKUP,
|
|
25126
|
+
useFactory: () => {
|
|
25127
|
+
const entityService = inject(AXPEntityService);
|
|
25128
|
+
return {
|
|
25129
|
+
byKey: (entityKey, id) => entityService.withEntity(entityKey).data().byKey(id),
|
|
25130
|
+
};
|
|
25131
|
+
},
|
|
25132
|
+
},
|
|
24994
25133
|
{ provide: AXP_WIDGET_DEFINITION_PROVIDER, useClass: AXPEntityWidgetsProvider, multi: true },
|
|
24995
25134
|
{
|
|
24996
25135
|
provide: ROUTES,
|
|
@@ -25007,6 +25146,10 @@ class AXPEntityModule {
|
|
|
25007
25146
|
useClass: AXPEntityCommandSearchDefinitionProvider,
|
|
25008
25147
|
multi: true,
|
|
25009
25148
|
},
|
|
25149
|
+
{
|
|
25150
|
+
provide: AXP_SEARCH_DEFINITION_LAZY_RESOLVER,
|
|
25151
|
+
useClass: AXPEntitySearchDefinitionLazyResolver,
|
|
25152
|
+
},
|
|
25010
25153
|
// Bind the middleware wrapper as the public storage service
|
|
25011
25154
|
{ provide: AXPEntityStorageService, useClass: AXPMiddlewareEntityStorageService },
|
|
25012
25155
|
{
|
|
@@ -25178,6 +25321,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
25178
25321
|
exports: [],
|
|
25179
25322
|
declarations: [],
|
|
25180
25323
|
providers: [
|
|
25324
|
+
{
|
|
25325
|
+
provide: AXP_REPEATER_ENTITY_BY_KEY_LOOKUP,
|
|
25326
|
+
useFactory: () => {
|
|
25327
|
+
const entityService = inject(AXPEntityService);
|
|
25328
|
+
return {
|
|
25329
|
+
byKey: (entityKey, id) => entityService.withEntity(entityKey).data().byKey(id),
|
|
25330
|
+
};
|
|
25331
|
+
},
|
|
25332
|
+
},
|
|
25181
25333
|
{ provide: AXP_WIDGET_DEFINITION_PROVIDER, useClass: AXPEntityWidgetsProvider, multi: true },
|
|
25182
25334
|
{
|
|
25183
25335
|
provide: ROUTES,
|
|
@@ -25194,6 +25346,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
25194
25346
|
useClass: AXPEntityCommandSearchDefinitionProvider,
|
|
25195
25347
|
multi: true,
|
|
25196
25348
|
},
|
|
25349
|
+
{
|
|
25350
|
+
provide: AXP_SEARCH_DEFINITION_LAZY_RESOLVER,
|
|
25351
|
+
useClass: AXPEntitySearchDefinitionLazyResolver,
|
|
25352
|
+
},
|
|
25197
25353
|
// Bind the middleware wrapper as the public storage service
|
|
25198
25354
|
{ provide: AXPEntityStorageService, useClass: AXPMiddlewareEntityStorageService },
|
|
25199
25355
|
{
|
|
@@ -25501,5 +25657,5 @@ var getEntityDetails_query = /*#__PURE__*/Object.freeze({
|
|
|
25501
25657
|
* Generated bundle index. Do not edit.
|
|
25502
25658
|
*/
|
|
25503
25659
|
|
|
25504
|
-
export { ATTACHMENTS_PAGE_COMPONENT_KEY, AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCategoryTreeService, AXPCreateEntityCommand, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEditFileUploaderCommand, AXPEntitiesListDataSourceDefinition, AXPEntityApplyUpdatesAction, AXPEntityCategoryTreeSelectorComponent, AXPEntityCategoryWidget, AXPEntityCategoryWidgetColumnComponent, AXPEntityCategoryWidgetEditComponent, AXPEntityCategoryWidgetViewComponent, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDataSelectorRowActionsService, AXPEntityDataSelectorService,
|
|
25660
|
+
export { ATTACHMENTS_PAGE_COMPONENT_KEY, AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCategoryTreeService, AXPCreateEntityCommand, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEditFileUploaderCommand, AXPEntitiesListDataSourceDefinition, AXPEntityApplyUpdatesAction, AXPEntityCategoryTreeSelectorComponent, AXPEntityCategoryWidget, AXPEntityCategoryWidgetColumnComponent, AXPEntityCategoryWidgetEditComponent, AXPEntityCategoryWidgetViewComponent, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDataSelectorRowActionsService, AXPEntityDataSelectorService, AXPEntityDefinitionProviderWidget, AXPEntityDefinitionProviderWidgetEditComponent, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailPopoverComponent, AXPEntityDetailPopoverService, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityEventsKeys, AXPEntityFormBuilderService, AXPEntityListPersistenceModeDefault, AXPEntityListTableService, AXPEntityListToolbarService, AXPEntityListViewCardFieldViewModel, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityListWidget, AXPEntityListWidgetViewComponent, AXPEntityMasterCreateViewModel, AXPEntityMasterListCardSelectActionName, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityPreloadFiltersContainerComponent, AXPEntityPreloadFiltersViewModel, AXPEntityPreloadFiltersViewModelResolver, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPEntityUpdateViewSectionViewModel, AXPFileListComponent, AXPFileUploaderLoadFilesQuery, AXPFileUploaderSaveFilesCommand, AXPFileUploaderWidget, AXPFileUploaderWidgetColumnComponent, AXPFileUploaderWidgetEditComponent, AXPFileUploaderWidgetService, AXPFileUploaderWidgetViewComponent, AXPGetEntityDetailsQuery, AXPLayoutOrderingConfigService, AXPLookupWidget, AXPLookupWidgetColumnComponent, AXPLookupWidgetEditComponent, AXPLookupWidgetViewComponent, AXPMiddlewareAbortError, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPMultiSourceDefinitionProviderContext, AXPMultiSourceDefinitionProviderService, AXPMultiSourceFederatedSearchService, AXPMultiSourceSelectorComponent, AXPMultiSourceSelectorService, AXPMultiSourceSelectorWidget, AXPMultiSourceSelectorWidgetColumnComponent, AXPMultiSourceSelectorWidgetEditComponent, AXPMultiSourceSelectorWidgetViewComponent, AXPMultiSourceType, AXPOpenEntityDetailsCommand, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPRelatedColumnEnrichmentService, AXPRelatedColumnMetadataResolver, AXPSelectorStructureWidget, AXPSelectorStructureWidgetColumnComponent, AXPSelectorStructureWidgetEditComponent, AXPSelectorStructureWidgetViewComponent, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXPTruncatedBreadcrumbComponent, AXPUpdateEntityCommand, AXPViewEntityDetailsCommand, AXP_CATEGORY_TREE_ROOT_TITLE_I18N_KEY, 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, AXP_MULTI_SOURCE_DEFINITION_PROVIDER, AXP_RECORD_WORKFLOW_INFO_CORRELATION_ID_FIELD, AXP_RECORD_WORKFLOW_INFO_DEFINITION_ID_FIELD, AXP_RECORD_WORKFLOW_INFO_INSTANCE_ID_FIELD, DEFAULT_COLUMN_ORDER, DEFAULT_PAIR_SPAN_RULES, DEFAULT_PROPERTY_ORDER, DEFAULT_SECTION_ORDER, ENTITY_LIST_ROUTE_CONTEXT_SESSION_KEY, EntityBuilder, EntityDataAccessor, actionExists, applyDataSourcePagingWithoutLoad, attachmentFieldCount, attachmentsPlugin, attachmentsSemanticallyEqual, axpCreateEntityAiToolInputDefaults, axpCreateEntityCommandDefinition, buildAXPRecordWorkflowInfo, canPersistEntityListState, cloneLayoutArrays, collectEntityQuickSearchFieldPaths, collectNestedFieldPathsFromEntityColumns, collectQuickSearchPathsFromSingleEntityDefinition, columnOrderingMiddleware, columnOrderingMiddlewareProvider, columnWidthMiddleware, columnWidthMiddlewareProvider, commandMessageTextForError, committedAttachments, computeEntityAggregates, createColumnOrderingMiddlewareProvider, createLayoutOrderingMiddlewareProvider, createModifierContext, defaultCardLayoutMiddleware, defaultCardLayoutMiddlewareProvider, defaultMultiLanguageMiddleware, defaultMultiLanguageMiddlewareProvider, detectEntityChanges, ensureLayoutPropertyView, ensureLayoutSection, ensureListActions, eventDispatchMiddleware, filterSortEntityRows, findEntityListRowDataInTree, fingerprintAttachmentItem, fingerprintAttachments, formatLookupItemDisplay, formatLookupItemDisplayAsync, getDataSourcePageIndex, getEntityListRowId, getMasterInterfacePropertySortKey, getRecordWorkflowCorrelationId, getRecordWorkflowInstanceId, hasFileUploaderTitleOrDescriptionFields, isAXPMiddlewareAbortError, isAttachmentListEntry, isCategoryEntity, isCategoryFilter, isFileListItem, isFileUploaderEditDialogAuto, isLegacyEntityDataSelectorOptions, layoutOrderingMiddlewareFactory, layoutOrderingMiddlewareProvider, mapEntityStorageErrorToCommandResult, mapLegacyEntityDataSelectorOptions, normalizeEntityDataSelectorOptions, normalizeEntityFieldToFileList, normalizeEntityListPersistenceMode, normalizeListPaging, persistedAttachments, provideEntity, resolveEntityPluginDetailPageOrder, resolveFileUploaderEditDialog, resolveFileUploaderEntityScope, resolveLookupDisplayField, resolveLookupDisplayTemplate, restoreEntityListExpandedRows, runEntityQuery, searchResultDescriptionMiddleware, searchResultDescriptionMiddlewareProvider, shouldLoadEntityListStateFromStorage, shouldResetEntityListStateOnRouteEntry };
|
|
25505
25661
|
//# sourceMappingURL=acorex-platform-layout-entity.mjs.map
|