@acorex/platform 21.0.0-next.85 → 21.0.0-next.88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/fesm2022/acorex-platform-auth.mjs +1 -1
  2. package/fesm2022/acorex-platform-auth.mjs.map +1 -1
  3. package/fesm2022/{acorex-platform-common-common-settings.provider-Ytey9uhY.mjs → acorex-platform-common-common-settings.provider-VfmZct9H.mjs} +43 -3
  4. package/fesm2022/acorex-platform-common-common-settings.provider-VfmZct9H.mjs.map +1 -0
  5. package/fesm2022/acorex-platform-common.mjs +1709 -870
  6. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-contracts.mjs +1160 -9
  8. package/fesm2022/acorex-platform-contracts.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-core.mjs +210 -131
  10. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-domain-contracts.mjs +58 -0
  12. package/fesm2022/acorex-platform-domain-contracts.mjs.map +1 -0
  13. package/fesm2022/acorex-platform-domain.mjs +2 -50
  14. package/fesm2022/acorex-platform-domain.mjs.map +1 -1
  15. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  16. package/fesm2022/acorex-platform-layout-components.mjs +59 -23
  17. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  18. package/fesm2022/acorex-platform-layout-designer.mjs +3 -2
  19. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  20. package/fesm2022/acorex-platform-layout-entity-attachments-page.component-CwG6n_Yb.mjs.map +1 -1
  21. package/fesm2022/acorex-platform-layout-entity-contracts.mjs +1114 -0
  22. package/fesm2022/acorex-platform-layout-entity-contracts.mjs.map +1 -0
  23. package/fesm2022/acorex-platform-layout-entity-file-list-popup.component--IeMZLIr.mjs.map +1 -1
  24. package/fesm2022/acorex-platform-layout-entity.mjs +661 -742
  25. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  26. package/fesm2022/acorex-platform-layout-views.mjs +333 -119
  27. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  28. package/fesm2022/acorex-platform-layout-widget-core.mjs +11 -105
  29. package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
  30. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs +513 -0
  31. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs.map +1 -0
  32. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-D4MOHEpI.mjs} +4 -4
  33. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-D4MOHEpI.mjs.map +1 -0
  34. package/fesm2022/acorex-platform-layout-widgets.mjs +868 -57
  35. package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
  36. package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
  37. 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
  38. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs.map +1 -0
  39. package/fesm2022/acorex-platform-themes-default.mjs +740 -96
  40. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  41. package/fesm2022/{acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs → acorex-platform-themes-shared-settings.provider-BUwPqwUS.mjs} +3 -3
  42. package/fesm2022/acorex-platform-themes-shared-settings.provider-BUwPqwUS.mjs.map +1 -0
  43. package/fesm2022/acorex-platform-themes-shared.mjs +4 -3
  44. package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
  45. package/fesm2022/acorex-platform-workflow.mjs +6 -8
  46. package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
  47. package/package.json +9 -5
  48. package/types/acorex-platform-auth.d.ts +2 -1
  49. package/types/acorex-platform-common.d.ts +419 -1083
  50. package/types/acorex-platform-contracts.d.ts +1791 -260
  51. package/types/acorex-platform-core.d.ts +2153 -2806
  52. package/types/acorex-platform-domain-contracts.d.ts +416 -0
  53. package/types/acorex-platform-domain.d.ts +4 -415
  54. package/types/acorex-platform-layout-builder.d.ts +2 -1
  55. package/types/acorex-platform-layout-components.d.ts +15 -4
  56. package/types/acorex-platform-layout-designer.d.ts +2 -1
  57. package/types/acorex-platform-layout-entity-contracts.d.ts +864 -0
  58. package/types/acorex-platform-layout-entity.d.ts +88 -269
  59. package/types/acorex-platform-layout-views.d.ts +48 -14
  60. package/types/acorex-platform-layout-widget-core.d.ts +9 -5
  61. package/types/acorex-platform-layout-widgets.d.ts +89 -13
  62. package/types/acorex-platform-runtime.d.ts +1 -1
  63. package/types/acorex-platform-themes-default.d.ts +173 -70
  64. package/types/acorex-platform-workflow.d.ts +5 -18
  65. package/fesm2022/acorex-platform-common-common-settings.provider-Ytey9uhY.mjs.map +0 -1
  66. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs +0 -116
  67. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs.map +0 -1
  68. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs.map +0 -1
  69. package/fesm2022/acorex-platform-native.mjs +0 -155
  70. package/fesm2022/acorex-platform-native.mjs.map +0 -1
  71. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs.map +0 -1
  72. package/fesm2022/acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs.map +0 -1
  73. package/native/README.md +0 -4
  74. package/types/acorex-platform-native.d.ts +0 -28
@@ -1,25 +1,29 @@
1
1
  import { AXToastService } from '@acorex/components/toast';
2
2
  import * as i3$1 from '@acorex/core/translation';
3
- import { AXTranslationService, AXTranslationModule, resolveMultiLanguageString, translateSync } from '@acorex/core/translation';
3
+ import { AXTranslationService, resolveMultiLanguageString, AXTranslationModule, translateSync } from '@acorex/core/translation';
4
4
  import * as i4$2 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, evaluateEntityDisplayTemplate, AXPFilterOperatorMiddlewareService, isCardFieldBadgeDisplay, resolveCardFieldBadgeColor, getEntityInfo, resolveEnabledMasterListLayouts, resolveDefaultMasterListLayout, AXPRefreshEvent, AXPReloadEvent, axpRedirectToNotFound, AXPCleanNestedFilters, AXPFileTypeProviderService, AXPFileStorageService, resolveEntityRowDisplayTitle, AXPFileActionsService, axpIsEntityRecordNotFound, AXPDefaultMultiLanguageConfigService, withDefaultMultiLanguageOnWidgetNodeTree, AXPEntityQueryType, 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, ChangeDetectorRef, input, signal, computed, ChangeDetectionStrategy, Component, ElementRef, NgModule, viewChild, effect, Input, afterNextRender, untracked, ViewEncapsulation, viewChildren, linkedSignal, HostBinding, output, EnvironmentInjector, makeEnvironmentProviders } from '@angular/core';
7
+ import { InjectionToken, inject, Injector, runInInjectionContext, Injectable, ChangeDetectorRef, input, signal, computed, effect, ChangeDetectionStrategy, Component, ElementRef, NgModule, viewChild, Input, afterNextRender, untracked, ViewEncapsulation, viewChildren, linkedSignal, HostBinding, output, EnvironmentInjector, makeEnvironmentProviders } from '@angular/core';
8
+ import { cloneDeep, merge, get, castArray, set, orderBy, isNil, isEmpty, isEqual as isEqual$1, isArray, isString } from 'lodash-es';
8
9
  import { Subject, filter, takeUntil } from 'rxjs';
9
10
  import { AXPLayoutBuilderService, LayoutBuilderModule } from '@acorex/platform/layout/builder';
10
- import * as i2 from '@acorex/platform/layout/widget-core';
11
- 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 { AXPSystemActionType, AXPDeviceService, AXPExpressionEvaluatorService, AXPBroadcastEventService, applyFilterArray, applySortArray, resolveActionLook, AXPDistributedEventListenerService, AXPPlatformScope, AXHighlightService, extractValue, setSmart, getChangedPaths, objectKeyValueTransforms, AXPHookService, AXPDataGenerator, AXPComponentSlotModule, AXPContextStore, AXPColumnWidthService, AXPModuleManifestRegistry, defaultColumnWidthProvider, AXP_COLUMN_WIDTH_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXPModuleManifestsDataSourceDefinition } from '@acorex/platform/core';
13
- import { cloneDeep, merge, get, castArray, set, orderBy, omit, isNil, isEmpty, isEqual as isEqual$1, isArray, isString } from 'lodash-es';
11
+ import { AXPWidgetsCatalog, AXPPlatformScope, AXPDataGenerator, AXPSystemActionType } from '@acorex/platform/contracts';
12
+ import { AXPDeviceService, AXPExpressionEvaluatorService, AXPContextEvalFactory, AXPBroadcastEventService, applyFilterArray, applySortArray, resolveActionLook, AXPDistributedEventListenerService, AXHighlightService, extractValue, setSmart, getChangedPaths, objectKeyValueTransforms, AXPHookService, AXPComponentSlotModule, AXPContextStore, AXPColumnWidthService, AXPModuleManifestRegistry, defaultColumnWidthProvider, AXP_COLUMN_WIDTH_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXPModuleManifestsDataSourceDefinition } from '@acorex/platform/core';
13
+ import { mergeForeignKeyFieldIntoCreateActions, collectNestedCreateHiddenProperties, normalizeEntityDisplayTemplate, sanitizeResolvedEntityDisplayTitle, isUnresolvedEntityDisplayTemplate, AXPEntityDataSourceKeys, AXPEntityEventsKeys, collectEntityListFilterDefinitions, ENTITY_ROW_POPUP_TITLE_OPTION, buildEntitySearchTitleContext } from '@acorex/platform/layout/entity-contracts';
14
+ export * from '@acorex/platform/layout/entity-contracts';
15
+ export { collectNestedCreateHiddenProperties, entityDetailsCreateActions, entityDetailsCreateActionsDeferredParent, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsNewEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterEditAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, mergeForeignKeyFieldIntoCreateActions } from '@acorex/platform/layout/entity-contracts';
14
16
  import { transform, isEqual } from 'lodash';
15
17
  import { AXPSessionService, AXPPermissionDefinitionsDataSourceDefinition } from '@acorex/platform/auth';
16
18
  import { Router, NavigationStart, 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 i3 from '@acorex/components/skeleton';
21
24
  import { AXSkeletonModule } from '@acorex/components/skeleton';
22
- import { AXFormatService } from '@acorex/core/format';
25
+ import * as i2 from '@acorex/platform/layout/widget-core';
26
+ import { 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';
23
27
  import * as i5 from '@angular/common';
24
28
  import { CommonModule, DOCUMENT, AsyncPipe, NgClass } from '@angular/common';
25
29
  import { AXOverlayService } from '@acorex/cdk/overlay';
@@ -37,6 +41,7 @@ import { moveItemInArray } from '@angular/cdk/drag-drop';
37
41
  import { AXDialogService } from '@acorex/components/dialog';
38
42
  import { AXLoadingDialogService } from '@acorex/components/loading-dialog';
39
43
  import { AXPopupService } from '@acorex/components/popup';
44
+ 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
45
  import * as i2$1 from '@acorex/components/badge';
41
46
  import { AXBadgeModule } from '@acorex/components/badge';
42
47
  import { AXCheckBoxModule } from '@acorex/components/check-box';
@@ -57,7 +62,6 @@ import { AXLoadingModule } from '@acorex/components/loading';
57
62
  import * as i6 from '@acorex/components/tag-box';
58
63
  import { AXTagBoxModule } from '@acorex/components/tag-box';
59
64
  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
65
  import * as i2$2 from '@acorex/components/select-box';
62
66
  import { AXSelectBoxModule } from '@acorex/components/select-box';
63
67
  import * as i3$4 from '@acorex/components/dropdown';
@@ -854,276 +858,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
854
858
  }]
855
859
  }] });
856
860
 
857
- // #region Master
858
- function entityMasterCreateAction() {
859
- return {
860
- title: '@general:actions.create.title',
861
- command: {
862
- name: 'Entity:Create',
863
- },
864
- priority: 'primary',
865
- type: AXPSystemActionType.Create,
866
- scope: AXPEntityCommandScope.TypeLevel,
867
- };
868
- }
869
- function entityMasterEditAction() {
870
- return {
871
- title: '@general:actions.edit.title',
872
- command: 'Entity:Update',
873
- priority: 'secondary',
874
- type: AXPSystemActionType.Update,
875
- scope: AXPEntityCommandScope.Individual,
876
- default: true,
877
- };
878
- }
879
- function entityMasterBulkDeleteAction() {
880
- return {
881
- title: '@general:actions.delete-items.title',
882
- command: 'delete-entity',
883
- priority: 'primary',
884
- type: AXPSystemActionType.Delete,
885
- scope: AXPEntityCommandScope.Selected,
886
- order: 100,
887
- };
888
- }
889
- function entityMasterViewAction() {
890
- return {
891
- title: '@general:actions.view.title',
892
- command: 'open-entity',
893
- priority: 'secondary',
894
- type: AXPSystemActionType.View,
895
- scope: AXPEntityCommandScope.Individual,
896
- default: true,
897
- };
898
- }
899
- function entityMasterDeleteAction() {
900
- return {
901
- title: '@general:actions.delete.title',
902
- command: 'delete-entity',
903
- priority: 'secondary',
904
- type: AXPSystemActionType.Delete,
905
- scope: AXPEntityCommandScope.Individual,
906
- order: 100,
907
- shortcuts: ['ctrl+shift+delete'],
908
- };
909
- }
910
- function entityMasterCrudActions(options) {
911
- const opts = {
912
- create: true,
913
- delete: true,
914
- view: true,
915
- edit: false,
916
- ...options,
917
- };
918
- const actions = [];
919
- if (opts.create) {
920
- actions.push(entityMasterCreateAction());
921
- }
922
- if (opts.delete) {
923
- actions.push(entityMasterBulkDeleteAction());
924
- actions.push(entityMasterDeleteAction());
925
- }
926
- if (opts.view) {
927
- actions.push(entityMasterViewAction());
928
- }
929
- if (opts.edit) {
930
- actions.push(entityMasterEditAction());
931
- }
932
- return actions;
933
- }
934
- function entityMasterRecordActions() {
935
- return [entityMasterDeleteAction()];
936
- }
937
- // #endregion
938
- // #region Details
939
- function entityDetailsCreateActions(parentId) {
940
- return {
941
- title: '@general:actions.create.title',
942
- command: {
943
- name: 'Entity:Create',
944
- options: {
945
- process: {
946
- redirect: false,
947
- canCreateNewOne: true,
948
- data: {
949
- [parentId]: '{{context.eval("id")}}',
950
- },
951
- },
952
- },
953
- },
954
- priority: 'primary',
955
- type: AXPSystemActionType.Create,
956
- scope: AXPEntityCommandScope.TypeLevel,
957
- };
958
- }
959
- /**
960
- * Type-level Create with empty `process.data`; the FK is supplied from `relatedEntity.persistence.foreignKeyField`
961
- * when the related list is built (see `mergeForeignKeyFieldIntoCreateActions`).
962
- */
963
- function entityDetailsCreateActionsDeferredParent() {
964
- return {
965
- title: '@general:actions.create.title',
966
- command: {
967
- name: 'Entity:Create',
968
- options: {
969
- process: {
970
- redirect: false,
971
- canCreateNewOne: true,
972
- data: {},
973
- },
974
- },
975
- },
976
- priority: 'primary',
977
- type: AXPSystemActionType.Create,
978
- scope: AXPEntityCommandScope.TypeLevel,
979
- };
980
- }
981
- /**
982
- * Ensures each type-level `Entity:Create` action includes `process.data[foreignKeyField]` bound to the parent row id.
983
- */
984
- function mergeForeignKeyFieldIntoCreateActions(foreignKeyField, actions) {
985
- if (!foreignKeyField || !actions?.length) {
986
- return actions ?? [];
987
- }
988
- return actions.map((a) => {
989
- const cmd = a.command;
990
- if (typeof cmd !== 'object' ||
991
- !cmd ||
992
- cmd.name !== 'Entity:Create' ||
993
- a.scope !== AXPEntityCommandScope.TypeLevel) {
994
- return a;
995
- }
996
- const opts = (cmd.options ?? {});
997
- const proc = (opts['process'] ?? {});
998
- const data = { ...(proc['data'] ?? {}) };
999
- if (data[foreignKeyField] === undefined || data[foreignKeyField] === null || data[foreignKeyField] === '') {
1000
- data[foreignKeyField] = '{{ context.eval("id") }}';
1001
- }
1002
- return {
1003
- ...a,
1004
- command: {
1005
- ...cmd,
1006
- options: { ...opts, process: { ...proc, data } },
1007
- },
1008
- };
1009
- });
1010
- }
1011
- /** Property names hidden on nested Create from a related list (`excludeProperties` plus `foreignKeyField` when set). */
1012
- function collectNestedCreateHiddenProperties(relatedEntity) {
1013
- const fk = relatedEntity.persistence?.foreignKeyField;
1014
- const merged = [...(relatedEntity.excludeProperties ?? [])];
1015
- if (fk) {
1016
- merged.push(fk);
1017
- }
1018
- const unique = [...new Set(merged)];
1019
- return unique.length ? unique : undefined;
1020
- }
1021
- function entityDetailsSimpleCondition(fk) {
1022
- return {
1023
- name: fk,
1024
- operator: { type: 'equal' },
1025
- value: '{{context.eval("id")}}',
1026
- };
1027
- }
1028
- function entityDetailsReferenceCondition(type) {
1029
- return [
1030
- {
1031
- name: 'reference.id',
1032
- operator: { type: 'equal' },
1033
- value: '{{context.eval("id")}}',
1034
- },
1035
- {
1036
- name: 'reference.type',
1037
- operator: { type: 'equal' },
1038
- value: type,
1039
- },
1040
- ];
1041
- }
1042
- function entityDetailsEditAction() {
1043
- return {
1044
- title: '@general:actions.edit.title',
1045
- // command: 'quick-modify-entity',
1046
- command: 'Entity:Update',
1047
- priority: 'secondary',
1048
- type: AXPSystemActionType.Update,
1049
- default: true,
1050
- scope: AXPEntityCommandScope.Individual,
1051
- };
1052
- }
1053
- function entityDetailsNewEditAction() {
1054
- return {
1055
- title: 'New Edit',
1056
- command: {
1057
- name: 'Entity:Update',
1058
- },
1059
- priority: 'secondary',
1060
- type: AXPSystemActionType.Update,
1061
- default: true,
1062
- scope: AXPEntityCommandScope.Individual,
1063
- };
1064
- }
1065
- function entityOverrideDetailsViewAction() {
1066
- return {
1067
- title: '@general:actions.view.title',
1068
- command: 'open-entity',
1069
- priority: 'secondary',
1070
- hidden: true,
1071
- type: AXPSystemActionType.View,
1072
- scope: AXPEntityCommandScope.Individual,
1073
- };
1074
- }
1075
- function entityDetailsCrudActions(parentId, options) {
1076
- const opts = {
1077
- create: true,
1078
- delete: true,
1079
- view: true,
1080
- edit: true,
1081
- ...options,
1082
- };
1083
- const actions = [];
1084
- if (opts.create) {
1085
- if (parentId) {
1086
- actions.push(entityDetailsCreateActions(parentId));
1087
- }
1088
- else {
1089
- actions.push(entityDetailsCreateActionsDeferredParent());
1090
- }
1091
- }
1092
- if (opts.edit) {
1093
- actions.push(entityDetailsEditAction());
1094
- }
1095
- if (opts.view) {
1096
- actions.push(entityOverrideDetailsViewAction());
1097
- }
1098
- return actions;
1099
- }
1100
- function entityDetailsReferenceCreateActions(type) {
1101
- return [
1102
- {
1103
- title: '@general:actions.create.title',
1104
- command: {
1105
- name: 'Entity:Create',
1106
- options: {
1107
- process: {
1108
- redirect: false,
1109
- canCreateNewOne: true,
1110
- data: {
1111
- reference: {
1112
- id: '{{context.eval("id")}}',
1113
- type: type,
1114
- },
1115
- },
1116
- },
1117
- },
1118
- },
1119
- priority: 'primary',
1120
- type: AXPSystemActionType.Create,
1121
- scope: AXPEntityCommandScope.TypeLevel,
1122
- },
1123
- entityDetailsEditAction(),
1124
- entityOverrideDetailsViewAction(),
1125
- ];
1126
- }
1127
861
  /**
1128
862
  * Computes a diff between two plain objects with array-aware semantics.
1129
863
  * - For arrays of objects with an id field, computes added/removed by id.
@@ -1481,7 +1215,7 @@ class PropertyFilter {
1481
1215
  const viewLayout = mainViewLayoutMap.get(prop.name);
1482
1216
  const mergedProp = {
1483
1217
  ...prop,
1484
- __layout: viewLayout?.layout,
1218
+ __layout: viewLayout?.layout ? cloneDeep(viewLayout.layout) : undefined,
1485
1219
  __order: viewLayout?.layout?.order,
1486
1220
  };
1487
1221
  if (this.readonlyList?.has(prop.name)) {
@@ -1544,7 +1278,7 @@ class PropertyFilter {
1544
1278
  const mergedProp = {
1545
1279
  ...prop,
1546
1280
  __dataPath: dataPath,
1547
- __layout: viewLayout?.layout,
1281
+ __layout: viewLayout?.layout ? cloneDeep(viewLayout.layout) : undefined,
1548
1282
  __order: viewLayout?.layout?.order,
1549
1283
  };
1550
1284
  // Apply generic propertyOverrides extension (e.g. for identifier defaultValue on nested paths)
@@ -2053,6 +1787,9 @@ const GRID_COLUMNS = 12;
2053
1787
  function getColSpanAt(layout, breakpoint) {
2054
1788
  return layout?.positions?.[breakpoint]?.colSpan ?? GRID_COLUMNS;
2055
1789
  }
1790
+ function getColStartAt(layout, breakpoint) {
1791
+ return layout?.positions?.[breakpoint]?.colStart;
1792
+ }
2056
1793
  function setColSpanAt(layout, breakpoint, colSpan) {
2057
1794
  if (!layout)
2058
1795
  return;
@@ -2077,23 +1814,56 @@ function normalizeLayoutFillRowGaps(items, getLayout, getItemId) {
2077
1814
  if (items.length === 0)
2078
1815
  return scaleFactors;
2079
1816
  for (const breakpoint of LAYOUT_BREAKPOINTS) {
2080
- const colSpans = items.map((item) => getColSpanAt(getLayout(item), breakpoint));
2081
1817
  let i = 0;
2082
- while (i < colSpans.length) {
2083
- let rowSum = 0;
1818
+ while (i < items.length) {
2084
1819
  const rowStart = i;
2085
- while (i < colSpans.length && rowSum + colSpans[i] <= GRID_COLUMNS) {
2086
- rowSum += colSpans[i];
1820
+ let rowHasExplicitColStart = false;
1821
+ let sequentialRowSum = 0;
1822
+ let explicitRowEnd = 0;
1823
+ while (i < items.length) {
1824
+ const layout = getLayout(items[i]);
1825
+ const colStart = getColStartAt(layout, breakpoint);
1826
+ const colSpan = getColSpanAt(layout, breakpoint);
1827
+ // colStart: 1 begins a new row (except for the first item in the current row)
1828
+ if (colStart === 1 && i > rowStart) {
1829
+ break;
1830
+ }
1831
+ if (colStart != null) {
1832
+ rowHasExplicitColStart = true;
1833
+ const end = colStart + colSpan;
1834
+ if (end - 1 > GRID_COLUMNS) {
1835
+ i++;
1836
+ break;
1837
+ }
1838
+ explicitRowEnd = Math.max(explicitRowEnd, end);
1839
+ i++;
1840
+ if (explicitRowEnd >= GRID_COLUMNS) {
1841
+ break;
1842
+ }
1843
+ continue;
1844
+ }
1845
+ if (sequentialRowSum + colSpan > GRID_COLUMNS && i > rowStart) {
1846
+ break;
1847
+ }
1848
+ if (sequentialRowSum + colSpan > GRID_COLUMNS && i === rowStart) {
1849
+ sequentialRowSum = colSpan;
1850
+ i++;
1851
+ break;
1852
+ }
1853
+ sequentialRowSum += colSpan;
2087
1854
  i++;
1855
+ if (sequentialRowSum >= GRID_COLUMNS) {
1856
+ break;
1857
+ }
2088
1858
  }
2089
- if (i === rowStart) {
2090
- rowSum = colSpans[i];
2091
- i++;
1859
+ // Rows with explicit colStart (e.g. 4+4+4 at columns 1/5/9) keep intentional gaps
1860
+ if (rowHasExplicitColStart) {
1861
+ continue;
2092
1862
  }
2093
- if (rowSum < GRID_COLUMNS && rowSum > 0 && i > rowStart) {
1863
+ if (sequentialRowSum < GRID_COLUMNS && sequentialRowSum > 0 && i > rowStart) {
2094
1864
  const lastIdx = i - 1;
2095
- const oldColSpan = colSpans[lastIdx];
2096
- const fill = GRID_COLUMNS - rowSum;
1865
+ const oldColSpan = getColSpanAt(getLayout(items[lastIdx]), breakpoint);
1866
+ const fill = GRID_COLUMNS - sequentialRowSum;
2097
1867
  const newColSpan = Math.min(GRID_COLUMNS, oldColSpan + fill);
2098
1868
  const layout = getLayout(items[lastIdx]);
2099
1869
  if (layout) {
@@ -2588,7 +2358,7 @@ class AXPCreateEntityCommand {
2588
2358
  }
2589
2359
  const createFn = entityRef.commands?.create?.execute;
2590
2360
  const updateFn = entityRef.commands?.update?.execute;
2591
- const context = dialogRef.context();
2361
+ const context = merge({}, data, dialogRef.context());
2592
2362
  console.log('context', context);
2593
2363
  const hasPersistedId = hasPersistedRootId(context);
2594
2364
  const persistFn = hasPersistedId ? updateFn : createFn;
@@ -2744,6 +2514,9 @@ class AXPUpdateEntityCommand {
2744
2514
  this.entityService = inject(AXPEntityDefinitionRegistryService);
2745
2515
  this.toastService = inject(AXToastService);
2746
2516
  this.translationService = inject(AXTranslationService);
2517
+ this.formatService = inject(AXFormatService);
2518
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
2519
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
2747
2520
  this.eventService = inject(AXPBroadcastEventService);
2748
2521
  }
2749
2522
  //#endregion
@@ -2751,7 +2524,7 @@ class AXPUpdateEntityCommand {
2751
2524
  async execute(input) {
2752
2525
  const enableOperationToasts = await this.settingsService.get(AXPCommonSettings.EnableOperationToasts);
2753
2526
  const dialogSize = input['dialogSize'];
2754
- const { entity, entityInfo, data, options } = input.__context__;
2527
+ const { entity, data, options } = input.__context__;
2755
2528
  const excludeProperties = options?.excludeProperties;
2756
2529
  const includeProperties = options?.includeProperties;
2757
2530
  const decoration = options?.['decoration'];
@@ -2790,10 +2563,17 @@ class AXPUpdateEntityCommand {
2790
2563
  if (headerTitle) {
2791
2564
  chain = chain.title(headerTitle);
2792
2565
  }
2793
- else if (entityInfo?.title) {
2794
- const editText = await this.translationService.translateAsync('@general:actions.edit.title');
2795
- const translatedTitle = await this.translationService.translateAsync(entityInfo.title);
2796
- chain = chain.title(`${editText} ${translatedTitle}`);
2566
+ else {
2567
+ let recordData = {};
2568
+ const recordId = typeof data === 'string' ? data : (data?.id ?? data?._id);
2569
+ if (recordId) {
2570
+ recordData = await this.entityForm.getRecordById(`${moduleName}.${entityName}`, String(recordId));
2571
+ }
2572
+ else if (typeof data === 'object' && data != null) {
2573
+ recordData = data;
2574
+ }
2575
+ const title = await resolveEntityModifyPopupTitle(entityRef, recordData, this.translationService, this.formatService, this.expressionEvaluator, this.contextEvalFactory, '@general:actions.edit.title');
2576
+ chain = chain.title(title);
2797
2577
  }
2798
2578
  const finalSize = layoutSize || dialogSize;
2799
2579
  if (finalSize) {
@@ -2887,15 +2667,19 @@ var updateEntity_command = /*#__PURE__*/Object.freeze({
2887
2667
 
2888
2668
  class AXPViewEntityDetailsCommand {
2889
2669
  constructor() {
2890
- //#region ---- Services & Dependencies ----
2670
+ //#region ---- Services & Dependencies ----
2891
2671
  this.entityForm = inject(AXPEntityFormBuilderService);
2892
2672
  this.entityService = inject(AXPEntityDefinitionRegistryService);
2893
2673
  this.translationService = inject(AXTranslationService);
2674
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
2675
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
2894
2676
  }
2895
2677
  //#endregion
2896
- //#region ---- Command Execution ----
2678
+ //#region ---- Command Execution ----
2897
2679
  async execute(input) {
2898
- const excludeProperties = input['excludeProperties'];
2680
+ const excludeProperties = input['excludeProperties'] ??
2681
+ input?.options?.excludeProperties ??
2682
+ input?.__context__?.options?.excludeProperties;
2899
2683
  const { entity, entityInfo, data } = input.__context__;
2900
2684
  const [moduleName, entityName] = (entity || '').split('.');
2901
2685
  if (!moduleName || !entityName) {
@@ -2906,10 +2690,9 @@ class AXPViewEntityDetailsCommand {
2906
2690
  },
2907
2691
  };
2908
2692
  }
2909
- await this.entityService.resolve(moduleName, entityName);
2693
+ const entityDef = await this.entityService.resolve(moduleName, entityName);
2910
2694
  let dialogRef;
2911
2695
  try {
2912
- // Validate data type
2913
2696
  if (!data || (typeof data !== 'string' && typeof data !== 'object')) {
2914
2697
  return {
2915
2698
  success: false,
@@ -2918,22 +2701,18 @@ class AXPViewEntityDetailsCommand {
2918
2701
  },
2919
2702
  };
2920
2703
  }
2921
- // Pass data directly to single() - it handles string | object internally
2922
2704
  let chain = this.entityForm.entity(`${moduleName}.${entityName}`).single(data);
2923
2705
  if (excludeProperties && excludeProperties.length > 0) {
2924
2706
  chain = chain.exclude(...excludeProperties);
2925
2707
  }
2926
- if (entityInfo?.title) {
2927
- const detailText = await this.translationService.translateAsync('@general:actions.detail.title');
2928
- // const translatedTitle = await this.translationService.translateAsync(entityInfo.title);
2929
- chain = chain.title(`${detailText}`);
2708
+ const dialogTitle = await this.resolveDialogTitle(entityDef, data);
2709
+ if (dialogTitle) {
2710
+ chain = chain.title(dialogTitle);
2930
2711
  }
2931
2712
  chain = chain.actions((actions) => {
2932
2713
  actions.submit('@general:actions.ok.title');
2933
2714
  });
2934
2715
  dialogRef = await chain.show();
2935
- // For single/view mode, only close action is available
2936
- // No need to show any message when closing a read-only view
2937
2716
  dialogRef.close();
2938
2717
  return {
2939
2718
  success: true,
@@ -2953,11 +2732,62 @@ class AXPViewEntityDetailsCommand {
2953
2732
  };
2954
2733
  }
2955
2734
  finally {
2956
- if (dialogRef) {
2735
+ if (dialogRef && typeof dialogRef === 'object' && dialogRef !== null && 'setLoading' in dialogRef) {
2957
2736
  dialogRef.setLoading(false);
2958
2737
  }
2959
2738
  }
2960
2739
  }
2740
+ //#endregion
2741
+ //#region ---- Title resolution ----
2742
+ async resolveDialogTitle(entityDef, data) {
2743
+ const titleTemplate = entityDef.interfaces?.master?.single?.title ??
2744
+ entityDef.formats?.searchResult?.title ??
2745
+ entityDef.formats?.individual;
2746
+ if (!titleTemplate || typeof titleTemplate !== 'string') {
2747
+ return this.translationService.translateAsync('@general:actions.detail.title');
2748
+ }
2749
+ if (!titleTemplate.includes('{{')) {
2750
+ const translated = await this.translationService.translateAsync(titleTemplate);
2751
+ return resolveMultiLanguageString(translated, this.translationService.getActiveLang()).trim() || translated;
2752
+ }
2753
+ const recordContext = await this.loadRecordContext(`${entityDef.module}.${entityDef.name}`, data);
2754
+ const scope = {
2755
+ context: this.contextEvalFactory.createScope(recordContext),
2756
+ };
2757
+ const evaluated = await this.expressionEvaluator.evaluate(titleTemplate, scope);
2758
+ const locale = this.translationService.getActiveLang();
2759
+ const text = resolveMultiLanguageString(evaluated, locale).trim() || String(evaluated ?? '').trim();
2760
+ if (text) {
2761
+ return text;
2762
+ }
2763
+ return this.translationService.translateAsync('@general:actions.detail.title');
2764
+ }
2765
+ async loadRecordContext(entityFullName, data) {
2766
+ if (typeof data === 'object' && data !== null && !Array.isArray(data)) {
2767
+ const hasNestedFields = get(data, 'subject.title') != null ||
2768
+ get(data, 'recordType.title') != null ||
2769
+ get(data, 'occurredDate') != null;
2770
+ if (hasNestedFields) {
2771
+ return data;
2772
+ }
2773
+ }
2774
+ const recordId = typeof data === 'string' ? data : String(get(data, 'id') ?? '');
2775
+ if (!recordId) {
2776
+ return typeof data === 'object' && data !== null ? data : {};
2777
+ }
2778
+ try {
2779
+ const [moduleName, entityName] = entityFullName.split('.');
2780
+ const entity = await this.entityService.resolve(moduleName, entityName);
2781
+ const byKeyFn = entity?.queries?.byKey?.execute;
2782
+ if (typeof byKeyFn === 'function') {
2783
+ return (await byKeyFn(recordId)) ?? {};
2784
+ }
2785
+ }
2786
+ catch {
2787
+ // Fall back to list row payload below.
2788
+ }
2789
+ return typeof data === 'object' && data !== null ? data : {};
2790
+ }
2961
2791
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPViewEntityDetailsCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2962
2792
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPViewEntityDetailsCommand, providedIn: 'root' }); }
2963
2793
  }
@@ -2973,55 +2803,39 @@ var viewEntityDetails_command = /*#__PURE__*/Object.freeze({
2973
2803
  AXPViewEntityDetailsCommand: AXPViewEntityDetailsCommand
2974
2804
  });
2975
2805
 
2976
- //#region ---- Datasource keys ----
2977
- /** Platform entity layout datasource registry names. */
2978
- const AXPEntityDataSourceKeys = {
2979
- Entities: 'entities',
2980
- };
2981
- //#endregion
2982
-
2983
- const AXPEntityEventsKeys = {
2984
- REFRESH_LAYOUT: 'entity:refresh-layout',
2985
- REFRESH_DATA: 'entity:refresh-data',
2986
- };
2987
-
2988
- //#endregion
2989
-
2990
- /** Entity query filter field for {@link AXPRecordWorkflowInfo.instanceId}. */
2991
- const AXP_RECORD_WORKFLOW_INFO_INSTANCE_ID_FIELD = 'workflowInfo.instanceId';
2992
- /** Entity query filter field for {@link AXPRecordWorkflowInfo.correlationId}. */
2993
- const AXP_RECORD_WORKFLOW_INFO_CORRELATION_ID_FIELD = 'workflowInfo.correlationId';
2994
- /** Entity query filter field for {@link AXPRecordWorkflowInfo.definitionId}. */
2995
- const AXP_RECORD_WORKFLOW_INFO_DEFINITION_ID_FIELD = 'workflowInfo.definitionId';
2996
- /** Returns a trimmed workflow instance id from a record, if present. */
2997
- function getRecordWorkflowInstanceId(record) {
2998
- const id = record?.workflowInfo?.instanceId?.trim();
2999
- return id && id.length > 0 ? id : null;
3000
- }
3001
- /** Returns a trimmed workflow correlation id from a record, if present. */
3002
- function getRecordWorkflowCorrelationId(record) {
3003
- const id = record?.workflowInfo?.correlationId?.trim();
3004
- return id && id.length > 0 ? id : null;
2806
+ /** Common keys on denormalized expose stubs (e.g. `{ id, displayName }` from lookup expose). */
2807
+ const LOOKUP_EXPOSE_STUB_DISPLAY_FIELDS = ['displayName', 'title', 'name', 'fullName', 'code'];
2808
+ function resolveLookupItemFieldValue(item, field) {
2809
+ const direct = get(item, field);
2810
+ if (direct != null && direct !== '') {
2811
+ return direct;
2812
+ }
2813
+ if (!field.includes('.')) {
2814
+ return direct;
2815
+ }
2816
+ for (const fallback of LOOKUP_EXPOSE_STUB_DISPLAY_FIELDS) {
2817
+ const candidate = get(item, fallback);
2818
+ if (candidate != null && candidate !== '') {
2819
+ return candidate;
2820
+ }
2821
+ }
2822
+ return direct;
3005
2823
  }
3006
- /** Builds canonical workflow metadata for a domain record (engine / middleware). */
3007
- function buildAXPRecordWorkflowInfo(params) {
3008
- const instanceId = params.instanceId?.trim();
3009
- if (!instanceId) {
3010
- return {};
2824
+ function formatLookupFieldValue(raw, locale, translationService, resolveMultiLanguage) {
2825
+ if (raw == null || raw === '') {
2826
+ return '';
3011
2827
  }
3012
- const definitionId = params.definitionId?.trim();
3013
- const correlationId = params.correlationId?.trim();
3014
- return {
3015
- instanceId,
3016
- ...(definitionId ? { definitionId } : { definitionId: null }),
3017
- ...(correlationId ? { correlationId } : { correlationId: null }),
3018
- ...(params.pinnedVersion != null ? { pinnedVersion: params.pinnedVersion } : {}),
3019
- };
2828
+ if (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') {
2829
+ return String(raw);
2830
+ }
2831
+ if (typeof raw === 'object' && !Array.isArray(raw)) {
2832
+ if (resolveMultiLanguage) {
2833
+ return resolveMultiLanguage(raw);
2834
+ }
2835
+ return resolveSearchableText(raw, locale, translationService);
2836
+ }
2837
+ return String(raw);
3020
2838
  }
3021
-
3022
- //#region ---- Contracts barrel ----
3023
- //#endregion
3024
-
3025
2839
  //#region ---- Template resolution ----
3026
2840
  /**
3027
2841
  * Resolves the display template for a lookup item.
@@ -3063,9 +2877,9 @@ function resolveLookupDisplayField(entity, options) {
3063
2877
  return found ?? 'title';
3064
2878
  }
3065
2879
  /**
3066
- * Formats a lookup row for display using template and/or field resolution.
2880
+ * Formats a lookup row for display using template and/or field resolution (display tier).
3067
2881
  */
3068
- function formatLookupItemDisplay(item, entity, options, formatService, resolveMultiLanguage) {
2882
+ async function formatLookupItemDisplayAsync(item, entity, options, formatService, displayDeps, resolveMultiLanguage) {
3069
2883
  if (item == null) {
3070
2884
  return '';
3071
2885
  }
@@ -3080,6 +2894,45 @@ function formatLookupItemDisplay(item, entity, options, formatService, resolveMu
3080
2894
  }
3081
2895
  const template = resolveLookupDisplayTemplate(entity, options);
3082
2896
  if (template) {
2897
+ if (template.includes('{{') || template.includes('context.eval')) {
2898
+ const evaluated = await evaluateEntityDisplayTemplate(template, item, displayDeps.expressionEvaluator, displayDeps.locale, displayDeps.translationService, displayDeps.contextEvalFactory);
2899
+ const text = sanitizeResolvedEntityDisplayTitle(resolveSearchableText(evaluated, displayDeps.locale, displayDeps.translationService));
2900
+ if (text && !isUnresolvedEntityDisplayTemplate(text)) {
2901
+ return text;
2902
+ }
2903
+ }
2904
+ else {
2905
+ const formatted = formatService.format(template, 'string', item);
2906
+ if (formatted) {
2907
+ const text = String(formatted);
2908
+ if (!isUnresolvedEntityDisplayTemplate(text)) {
2909
+ return text;
2910
+ }
2911
+ }
2912
+ }
2913
+ }
2914
+ const field = resolveLookupDisplayField(entity, options);
2915
+ const raw = typeof item === 'object' && item != null ? resolveLookupItemFieldValue(item, field) : undefined;
2916
+ return formatLookupFieldValue(raw, displayDeps.locale, displayDeps.translationService, resolveMultiLanguage);
2917
+ }
2918
+ /**
2919
+ * @deprecated Prefer {@link formatLookupItemDisplayAsync} for expression templates with `context.eval`.
2920
+ */
2921
+ function formatLookupItemDisplay(item, entity, options, formatService, resolveMultiLanguage) {
2922
+ if (item == null) {
2923
+ return '';
2924
+ }
2925
+ if (typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean') {
2926
+ return String(item);
2927
+ }
2928
+ if (typeof item !== 'object') {
2929
+ return '';
2930
+ }
2931
+ if (options.isMultiLanguage?.(item) && resolveMultiLanguage) {
2932
+ return resolveMultiLanguage(item);
2933
+ }
2934
+ const template = resolveLookupDisplayTemplate(entity, options);
2935
+ if (template && !template.includes('context.eval') && !template.includes('{{')) {
3083
2936
  const formatted = formatService.format(template, 'string', item);
3084
2937
  if (formatted) {
3085
2938
  const text = String(formatted);
@@ -3089,8 +2942,8 @@ function formatLookupItemDisplay(item, entity, options, formatService, resolveMu
3089
2942
  }
3090
2943
  }
3091
2944
  const field = resolveLookupDisplayField(entity, options);
3092
- const raw = get(item, field);
3093
- if (raw == null) {
2945
+ const raw = typeof item === 'object' && item != null ? resolveLookupItemFieldValue(item, field) : undefined;
2946
+ if (raw == null || raw === '') {
3094
2947
  return '';
3095
2948
  }
3096
2949
  if (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') {
@@ -3113,6 +2966,8 @@ class AXPEntityDetailPopoverComponent {
3113
2966
  this.queryService = inject(AXPQueryService);
3114
2967
  this.formatService = inject(AXFormatService);
3115
2968
  this.translation = inject(AXTranslationService);
2969
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
2970
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
3116
2971
  this.changeDetectorRef = inject(ChangeDetectorRef);
3117
2972
  //#endregion
3118
2973
  //#region ---- Inputs ----
@@ -3128,31 +2983,10 @@ class AXPEntityDetailPopoverComponent {
3128
2983
  //#region ---- Signals ----
3129
2984
  this.entityDetails = signal(null, ...(ngDevMode ? [{ debugName: "entityDetails" }] : /* istanbul ignore next */ []));
3130
2985
  this.isLoadingDetails = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingDetails" }] : /* istanbul ignore next */ []));
2986
+ this.headerTitleVersion = 0;
3131
2987
  /** Placeholder rows for the loading skeleton (matches typical property count). */
3132
2988
  this.loadingSkeletonRows = [1, 2, 3, 4, 5];
3133
- this.headerTitle = computed(() => {
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 */ []));
2989
+ this.headerTitle = signal('', ...(ngDevMode ? [{ debugName: "headerTitle" }] : /* istanbul ignore next */ []));
3156
2990
  /**
3157
2991
  * Stable list of property widgets for the template. Must be a signal (computed), not a method:
3158
2992
  * calling a method from the template rebuilds nodes every CD cycle and can make the widget renderer loop.
@@ -3165,6 +2999,18 @@ class AXPEntityDetailPopoverComponent {
3165
2999
  return [];
3166
3000
  return this.buildEntityPropertiesWithWidgets(data, entityDefinition, this.textField(), this.valueField());
3167
3001
  }, ...(ngDevMode ? [{ debugName: "entityPropertiesWithWidgets" }] : /* istanbul ignore next */ []));
3002
+ effect(() => {
3003
+ void this.translation.getActiveLang();
3004
+ const details = this.entityDetails();
3005
+ const preset = this.displayTitle();
3006
+ const fallbackItem = this.item();
3007
+ const version = ++this.headerTitleVersion;
3008
+ void this.resolveHeaderTitle(details?.entityDefinition, details?.entityData, preset, fallbackItem).then((title) => {
3009
+ if (version === this.headerTitleVersion) {
3010
+ this.headerTitle.set(title);
3011
+ }
3012
+ });
3013
+ });
3168
3014
  }
3169
3015
  //#endregion
3170
3016
  //#region ---- Public Methods ----
@@ -3201,10 +3047,34 @@ class AXPEntityDetailPopoverComponent {
3201
3047
  }
3202
3048
  //#endregion
3203
3049
  //#region ---- Helper Methods ----
3204
- resolveLookupDisplayLabel(item, entityDefinition) {
3205
- const label = formatLookupItemDisplay(item, entityDefinition, { textField: this.textField() }, this.formatService, (value) => this.translation.resolve(value));
3206
- const resolved = typeof label === 'string' ? label : this.translation.resolve(label);
3207
- return resolved && !isUnresolvedEntityDisplayTemplate(resolved) ? resolved : '';
3050
+ async resolveHeaderTitle(entityDefinition, data, preset, fallbackItem) {
3051
+ if (data && entityDefinition) {
3052
+ const fromDetails = await this.resolveLookupDisplayLabelAsync(data, entityDefinition);
3053
+ if (fromDetails) {
3054
+ return fromDetails;
3055
+ }
3056
+ }
3057
+ const presetTrimmed = preset?.trim();
3058
+ if (presetTrimmed && !isUnresolvedEntityDisplayTemplate(presetTrimmed)) {
3059
+ return presetTrimmed;
3060
+ }
3061
+ if (fallbackItem) {
3062
+ const fromItem = await this.resolveLookupDisplayLabelAsync(fallbackItem, entityDefinition);
3063
+ if (fromItem) {
3064
+ return fromItem;
3065
+ }
3066
+ }
3067
+ return presetTrimmed ?? '';
3068
+ }
3069
+ async resolveLookupDisplayLabelAsync(item, entityDefinition) {
3070
+ const locale = this.translation.getActiveLang() ?? 'en-US';
3071
+ const label = await formatLookupItemDisplayAsync(item, entityDefinition ?? null, { textField: this.textField() }, this.formatService, {
3072
+ expressionEvaluator: this.expressionEvaluator,
3073
+ contextEvalFactory: this.contextEvalFactory,
3074
+ translationService: this.translation,
3075
+ locale,
3076
+ }, (value) => this.translation.resolve(value));
3077
+ return label && !isUnresolvedEntityDisplayTemplate(label) ? label : '';
3208
3078
  }
3209
3079
  /**
3210
3080
  * Returns true if a value is meaningful for display (non-empty/non-null).
@@ -3369,14 +3239,24 @@ class AXPEntityDetailPopoverComponent {
3369
3239
  resolveDataPath(prop, data) {
3370
3240
  const iface = prop.schema?.interface;
3371
3241
  const expose = iface?.options?.['expose'];
3242
+ const textField = iface?.options?.['textField']?.trim();
3372
3243
  if (expose?.length) {
3373
- // Try expanded path first (e.g. personTitle for personTitle.title)
3374
3244
  const textTarget = expose.find((e) => e.source !== 'id');
3375
3245
  if (textTarget) {
3376
3246
  const expandedPath = textTarget.target.split('.')[0];
3377
3247
  const expandedValue = get(data, expandedPath);
3378
3248
  if (expandedValue != null && typeof expandedValue === 'object') {
3379
- return expandedPath;
3249
+ if (textField) {
3250
+ if (this.hasMeaningfulValue(get(expandedValue, textField))) {
3251
+ return expandedPath;
3252
+ }
3253
+ }
3254
+ else {
3255
+ const leaf = textTarget.target.split('.').pop();
3256
+ if (leaf && this.hasMeaningfulValue(get(expandedValue, leaf))) {
3257
+ return expandedPath;
3258
+ }
3259
+ }
3380
3260
  }
3381
3261
  }
3382
3262
  }
@@ -3388,7 +3268,7 @@ class AXPEntityDetailPopoverComponent {
3388
3268
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailPopoverComponent, decorators: [{
3389
3269
  type: Component,
3390
3270
  args: [{ selector: 'axp-entity-detail-popover', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, AXButtonModule, AXPWidgetCoreModule, AXTranslationModule, AXSkeletonModule], template: "<div\n class=\"ax-lightest-surface dark:ax-dark-surface ax-p-4 ax-w-[min(600px,calc(100vw-2rem))] ax-rounded-lg ax-shadow-lg\"\n>\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 @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 }}:</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\n [color]=\"'primary'\"\n [look]=\"'solid'\"\n [text]=\"'@general:actions.open-details.title' | translate | async\"\n (click)=\"navigateToDetails()\"\n >\n </ax-button>\n </div>\n }\n</div>\n" }]
3391
- }], 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 }] }], requestClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "requestClose", required: false }] }] } });
3271
+ }], 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 }] }], requestClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "requestClose", required: false }] }] } });
3392
3272
 
3393
3273
  class AXPEntityDetailPopoverService {
3394
3274
  constructor() {
@@ -3402,6 +3282,7 @@ class AXPEntityDetailPopoverService {
3402
3282
  //#region ---- Private Properties ----
3403
3283
  this.overlayRef = null;
3404
3284
  this.componentRef = null;
3285
+ this.anchorElement = null;
3405
3286
  this.outsideClickHandler = null;
3406
3287
  this.keydownHandler = null;
3407
3288
  this.routerSubscription = null;
@@ -3458,6 +3339,7 @@ class AXPEntityDetailPopoverService {
3458
3339
  });
3459
3340
  this.overlayRef = ref;
3460
3341
  this.componentRef = ref.instance;
3342
+ this.anchorElement = anchorElement;
3461
3343
  setTimeout(() => {
3462
3344
  ref.updatePosition();
3463
3345
  this.bindDismissHandlers(ref.overlayElement, anchorElement);
@@ -3559,6 +3441,7 @@ class AXPEntityDetailPopoverService {
3559
3441
  this.removeDismissHandlers();
3560
3442
  this.overlayRef = null;
3561
3443
  this.componentRef = null;
3444
+ this.anchorElement = null;
3562
3445
  }
3563
3446
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailPopoverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3564
3447
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailPopoverService, providedIn: 'root' }); }
@@ -4055,7 +3938,6 @@ class AXPEntityPreloadFiltersContainerComponent extends AXPPageLayoutBaseCompone
4055
3938
  super(...arguments);
4056
3939
  //#region ---- Services & Dependencies ----
4057
3940
  this.route = inject(ActivatedRoute);
4058
- this.router = inject(Router);
4059
3941
  this.entityService = inject(AXPEntityService);
4060
3942
  this.filterOperatorMiddleware = inject(AXPFilterOperatorMiddlewareService);
4061
3943
  //#endregion
@@ -4474,7 +4356,7 @@ class AXPEntityCommandTriggerViewModel {
4474
4356
  this.priority = action.priority;
4475
4357
  this.title = action.title;
4476
4358
  this.separated = action.separated ?? false;
4477
- this.color = action.color ?? resolvedLook.color;
4359
+ this.color = (action.color ?? resolvedLook.color);
4478
4360
  this.icon = action.icon ?? resolvedLook.icon;
4479
4361
  this.hidden = action.hidden ?? false;
4480
4362
  this.disabled = action.disabled ?? false;
@@ -4566,6 +4448,7 @@ class AXPEntityDetailListViewModel {
4566
4448
  this.settingsService = this.injector.get(AXPSettingsService);
4567
4449
  this.destroyed = new Subject();
4568
4450
  this.showRowIndexColumnEnabled = signal(false, ...(ngDevMode ? [{ debugName: "showRowIndexColumnEnabled" }] : /* istanbul ignore next */ []));
4451
+ this.lastAppliedFilterKey = null;
4569
4452
  /** Whether the row index column is shown (user setting). */
4570
4453
  this.showIndexColumn = computed(() => this.showRowIndexColumnEnabled(), ...(ngDevMode ? [{ debugName: "showIndexColumn" }] : /* istanbul ignore next */ []));
4571
4454
  this.dataSource = new AXDataSource({
@@ -4759,10 +4642,6 @@ class AXPEntityDetailListViewModel {
4759
4642
  this.applyFilterAndSort();
4760
4643
  }
4761
4644
  async applyFilterAndSort() {
4762
- this.dataSource.clearFilter();
4763
- //
4764
- //this.dataSource.sort(...this.detailEntity.().map(s => ({ dir: s.dir, field: s.name } as AXDataSourceSortOption)));
4765
- //
4766
4645
  const parentFilters = (await Promise.all(this.detailEntityConfig.conditions?.map(async (c) => {
4767
4646
  return {
4768
4647
  field: c.name,
@@ -4780,22 +4659,30 @@ class AXPEntityDetailListViewModel {
4780
4659
  //
4781
4660
  const inline = this.inlineFilters.filters?.length ?? 0;
4782
4661
  const parent = parentFilterWrapper.filters?.length ?? 0;
4783
- //
4784
- if (inline) {
4785
- this.dataSource.filter(this.filterOperatorMiddleware.transformFilter(this.inlineFilters));
4786
- }
4787
- else if (!inline && parent) {
4788
- this.dataSource.filter(this.filterOperatorMiddleware.transformFilter(parentFilterWrapper));
4789
- }
4790
- else if (inline && parent) {
4791
- this.dataSource.filter(this.filterOperatorMiddleware.transformFilter({
4662
+ let effectiveFilter;
4663
+ if (inline && parent) {
4664
+ effectiveFilter = this.filterOperatorMiddleware.transformFilter({
4792
4665
  field: null,
4793
4666
  logic: 'and',
4794
4667
  operator: null,
4795
4668
  filters: [this.inlineFilters, parentFilterWrapper],
4796
- }));
4669
+ });
4670
+ }
4671
+ else if (inline) {
4672
+ effectiveFilter = this.filterOperatorMiddleware.transformFilter(this.inlineFilters);
4673
+ }
4674
+ else if (parent) {
4675
+ effectiveFilter = this.filterOperatorMiddleware.transformFilter(parentFilterWrapper);
4676
+ }
4677
+ const filterKey = JSON.stringify(effectiveFilter ?? null);
4678
+ if (filterKey === this.lastAppliedFilterKey) {
4679
+ return;
4680
+ }
4681
+ this.lastAppliedFilterKey = filterKey;
4682
+ this.dataSource.clearFilter();
4683
+ if (effectiveFilter) {
4684
+ this.dataSource.filter(effectiveFilter);
4797
4685
  }
4798
- //
4799
4686
  this.dataSource.refresh();
4800
4687
  }
4801
4688
  //****************** Commands ******************//
@@ -5344,7 +5231,7 @@ class AXPEntityMasterListViewModel {
5344
5231
  }
5345
5232
  }
5346
5233
  //#endregion
5347
- createExpressionScope(data) {
5234
+ createLogicExpressionScope(data) {
5348
5235
  return {
5349
5236
  context: {
5350
5237
  eval: (path) => get(data, path),
@@ -5355,11 +5242,20 @@ class AXPEntityMasterListViewModel {
5355
5242
  },
5356
5243
  };
5357
5244
  }
5245
+ createDisplayExpressionScope(data) {
5246
+ return {
5247
+ context: this.contextEvalFactory.createScope((data ?? {})),
5248
+ list: {
5249
+ view: () => this.view().name,
5250
+ views: () => this.views().map((v) => ({ name: v.name, title: v.title })),
5251
+ },
5252
+ };
5253
+ }
5358
5254
  async resolveCommandNameExpression(commandName, data) {
5359
5255
  if (!commandName || !commandName.includes('{{')) {
5360
5256
  return commandName;
5361
5257
  }
5362
- const scope = this.createExpressionScope(data);
5258
+ const scope = this.createLogicExpressionScope(data);
5363
5259
  const result = await this.expressionEvaluator.evaluate({ value: commandName }, scope);
5364
5260
  const resolved = result?.value;
5365
5261
  return typeof resolved === 'string' && resolved.trim() !== '' ? resolved : commandName;
@@ -5368,7 +5264,7 @@ class AXPEntityMasterListViewModel {
5368
5264
  if (!title || !title.includes('{{')) {
5369
5265
  return title;
5370
5266
  }
5371
- const scope = this.createExpressionScope(data);
5267
+ const scope = this.createDisplayExpressionScope(data);
5372
5268
  const result = await this.expressionEvaluator.evaluate({ value: title }, scope);
5373
5269
  const resolved = result?.value;
5374
5270
  return typeof resolved === 'string' && resolved.trim() !== '' ? resolved : title;
@@ -5383,7 +5279,7 @@ class AXPEntityMasterListViewModel {
5383
5279
  return '';
5384
5280
  }
5385
5281
  if (value.includes('{{')) {
5386
- const scope = this.createExpressionScope(rowData);
5282
+ const scope = this.createDisplayExpressionScope(rowData);
5387
5283
  const result = await this.expressionEvaluator.evaluate(value, scope);
5388
5284
  if (result === false) {
5389
5285
  return '';
@@ -5421,7 +5317,7 @@ class AXPEntityMasterListViewModel {
5421
5317
  if (color == null || color === '') {
5422
5318
  return 'default';
5423
5319
  }
5424
- const scope = this.createExpressionScope(rowData);
5320
+ const scope = this.createLogicExpressionScope(rowData);
5425
5321
  const result = await this.expressionEvaluator.evaluate(color, scope);
5426
5322
  if (result === false || result == null) {
5427
5323
  return 'default';
@@ -5469,6 +5365,7 @@ class AXPEntityMasterListViewModel {
5469
5365
  this.settings = this.injector.get(AXPSettingsService);
5470
5366
  this.widgetResolver = this.injector.get(AXPWidgetRegistryService);
5471
5367
  this.expressionEvaluator = this.injector.get(AXPExpressionEvaluatorService);
5368
+ this.contextEvalFactory = this.injector.get(AXPContextEvalFactory);
5472
5369
  this.translation = this.injector.get(AXTranslationService);
5473
5370
  this.commandService = this.injector.get(AXPCommandService);
5474
5371
  this.eventService = this.injector.get(AXPBroadcastEventService);
@@ -5582,8 +5479,11 @@ class AXPEntityMasterListViewModel {
5582
5479
  return this._viewDef.description ?? null;
5583
5480
  }, ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
5584
5481
  //****************** Inline filter ******************//
5482
+ this.filterDefinitions = signal([], ...(ngDevMode ? [{ debugName: "filterDefinitions" }] : /* istanbul ignore next */ []));
5585
5483
  this.inlineFiltersPlaceholders = computed(() => {
5586
- return this.entityDef.properties.filter((p) => p.options?.filter?.inline?.enabled).map((c) => c.title ?? c.name);
5484
+ return this.filterDefinitions()
5485
+ .filter((f) => f.filterType.inline)
5486
+ .map((c) => c.title ?? c.field);
5587
5487
  }, ...(ngDevMode ? [{ debugName: "inlineFiltersPlaceholders" }] : /* istanbul ignore next */ []));
5588
5488
  this.hasInlineFilters = computed(() => {
5589
5489
  return this.inlineFiltersPlaceholders().length > 0;
@@ -5691,7 +5591,7 @@ class AXPEntityMasterListViewModel {
5691
5591
  this.sortedFields = signal([], ...(ngDevMode ? [{ debugName: "sortedFields" }] : /* istanbul ignore next */ []));
5692
5592
  //#endregion
5693
5593
  this.evaluateExpressions = async (options, data) => {
5694
- const scope = this.createExpressionScope(data);
5594
+ const scope = this.createLogicExpressionScope(data);
5695
5595
  return await this.expressionEvaluator.evaluate(options, scope);
5696
5596
  };
5697
5597
  this.workflow.events$
@@ -6081,7 +5981,7 @@ class AXPEntityMasterListViewModel {
6081
5981
  this.selectedCategory.set(category);
6082
5982
  }
6083
5983
  async getPrimaryActions() {
6084
- const scope = this.createExpressionScope(null);
5984
+ const scope = this.createLogicExpressionScope(null);
6085
5985
  const actions = await Promise.all(this.allActions()
6086
5986
  .filter((a) => a.priority == 'primary' &&
6087
5987
  ((a.scope == AXPEntityCommandScope.Selected && this.hasSelectedItems()) ||
@@ -6098,7 +5998,7 @@ class AXPEntityMasterListViewModel {
6098
5998
  return actions.filter(Boolean);
6099
5999
  }
6100
6000
  async getSecondaryActions() {
6101
- const scope = this.createExpressionScope(null);
6001
+ const scope = this.createLogicExpressionScope(null);
6102
6002
  const actions = await Promise.all(this.allActions()
6103
6003
  .filter((a) => a.priority == 'secondary' &&
6104
6004
  ((a.scope == AXPEntityCommandScope.Selected && this.hasSelectedItems()) ||
@@ -6115,7 +6015,7 @@ class AXPEntityMasterListViewModel {
6115
6015
  return actions.filter(Boolean);
6116
6016
  }
6117
6017
  async secondaryRowActions(rowData) {
6118
- const scope = this.createExpressionScope(rowData);
6018
+ const scope = this.createLogicExpressionScope(rowData);
6119
6019
  const actions = await Promise.all(this.allActions()
6120
6020
  .filter((a) => a.scope === AXPEntityCommandScope.Individual && a.priority === 'secondary')
6121
6021
  .map(async (a) => {
@@ -6276,38 +6176,20 @@ class AXPEntityMasterListViewModel {
6276
6176
  }
6277
6177
  return false;
6278
6178
  }
6279
- get filtersDef() {
6280
- const props = this.entityDef.properties.filter((c) => c.options?.filter?.advance?.enabled ||
6281
- c.options?.filter?.inline?.enabled ||
6282
- c.options?.filter?.preload?.enabled);
6283
- return props.map((e) => {
6284
- const widgetConfig = this.widgetResolver.resolve(e.schema.interface?.type);
6285
- const type = (e.options?.filter?.advance?.widgetType ||
6286
- widgetConfig?.defaultFilterWidgetName ||
6287
- e.schema.interface?.type);
6288
- const iface = e.schema.interface ?? {};
6289
- return {
6290
- title: e.title,
6291
- field: e.name,
6292
- operator: {
6293
- type: 'contains',
6294
- },
6295
- widget: { ...omit(iface, 'triggers'), path: e.name, type },
6296
- filters: [],
6297
- isParametric: false,
6298
- icon: widgetConfig?.icon,
6299
- filterType: {
6300
- advance: e.options?.filter?.advance?.enabled ?? false,
6301
- inline: e.options?.filter?.inline?.enabled ?? false,
6302
- preload: e.options?.filter?.preload,
6303
- },
6304
- // `interface.options.disabled` is for edit forms only; do not gray out advance filters.
6305
- triggers: e.schema.interface?.triggers,
6306
- };
6179
+ /**
6180
+ * Loads host and merge-detail related filter definitions (async registry resolution).
6181
+ */
6182
+ async loadFilterDefinitions() {
6183
+ const definitions = await collectEntityListFilterDefinitions(this.entityDef, (moduleName, entityName) => this.entityDefinitionRegistry.resolve(moduleName, entityName).catch(() => null), {
6184
+ resolveWidget: (type) => this.widgetResolver.resolve(type),
6307
6185
  });
6186
+ this.filterDefinitions.set(definitions);
6187
+ }
6188
+ get filtersDef() {
6189
+ return this.filterDefinitions();
6308
6190
  }
6309
6191
  get preloadFiltersDef() {
6310
- return this.filtersDef.filter((f) => f.filterType.preload?.enabled);
6192
+ return this.filterDefinitions().filter((f) => f.filterType.preload?.enabled);
6311
6193
  }
6312
6194
  // const viewFilters = this.view().conditions.map((f) => ({
6313
6195
  // field: f.name,
@@ -6337,7 +6219,13 @@ class AXPEntityMasterListViewModel {
6337
6219
  .map((s) => ({ name: s.name, dir: s.dir }));
6338
6220
  const filters = this.filterQueries();
6339
6221
  const sortKey = JSON.stringify(sorts);
6340
- const filterKey = JSON.stringify(filters);
6222
+ const transformedFilter = this.filterOperatorMiddleware.transformFilter({
6223
+ field: null,
6224
+ logic: 'and',
6225
+ operator: null,
6226
+ filters: filters,
6227
+ });
6228
+ const filterKey = JSON.stringify(transformedFilter);
6341
6229
  if (sortKey === this.lastAppliedSortKey && filterKey === this.lastAppliedFilterKey) {
6342
6230
  return; // No effective change; avoid redundant refresh
6343
6231
  }
@@ -6349,12 +6237,7 @@ class AXPEntityMasterListViewModel {
6349
6237
  }
6350
6238
  this.dataSource.clearFilter();
6351
6239
  this.dataSource.sort(...sorts.map((s) => ({ dir: s.dir, field: s.name })));
6352
- this.dataSource.filter(this.filterOperatorMiddleware.transformFilter({
6353
- field: null,
6354
- logic: 'and',
6355
- operator: null,
6356
- filters: filters,
6357
- }));
6240
+ this.dataSource.filter(transformedFilter);
6358
6241
  this.events$.next({ action: 'refresh', meta: { resetPagination: filtersChanged } });
6359
6242
  }
6360
6243
  resetColumns() {
@@ -6751,6 +6634,7 @@ class AXPEntityListViewModelFactory {
6751
6634
  const config = await this.entityService.resolve(moduleName, entityName);
6752
6635
  this.layout.setNavigationLoading(false);
6753
6636
  const vm = new AXPEntityMasterListViewModel(this.injector, config);
6637
+ await vm.loadFilterDefinitions();
6754
6638
  await vm.initializeListPersistence();
6755
6639
  return vm;
6756
6640
  }
@@ -7138,6 +7022,9 @@ class AXPEntityModifySectionPopupAction extends AXPWorkflowAction {
7138
7022
  this.popupService = inject(AXPopupService);
7139
7023
  this.platform = inject(AXPlatform);
7140
7024
  this.translateService = inject(AXTranslationService);
7025
+ this.formatService = inject(AXFormatService);
7026
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
7027
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
7141
7028
  this.entityRegistery = inject(AXPEntityDefinitionRegistryService);
7142
7029
  this.config = inject(AXP_ENTITY_CONFIG_TOKEN);
7143
7030
  this.factory = inject(AXPEntityMasterUpdateViewModelFactory);
@@ -7155,7 +7042,7 @@ class AXPEntityModifySectionPopupAction extends AXPWorkflowAction {
7155
7042
  title: headerTitle
7156
7043
  ? headerTitle
7157
7044
  : title ??
7158
- `${this.translateService.translateSync('entity.modify')} ${this.translateService.translateSync(entityRef.formats.individual)}`,
7045
+ (await resolveEntityModifyPopupTitle(entityRef, vm.context(), this.translateService, this.formatService, this.expressionEvaluator, this.contextEvalFactory)),
7159
7046
  size: this.platform.is('Mobile') || this.platform.is('SM') ? 'full' : 'md',
7160
7047
  data: {
7161
7048
  vm,
@@ -7516,6 +7403,8 @@ class AXPEntityPreloadFiltersViewModel {
7516
7403
  this.config = config;
7517
7404
  this.entityDef = cloneDeep(this.config);
7518
7405
  this.widgetResolver = this.injector.get(AXPWidgetRegistryService);
7406
+ this.entityRegistry = this.injector.get(AXPEntityDefinitionRegistryService);
7407
+ this.filterDefinitions = signal([], ...(ngDevMode ? [{ debugName: "filterDefinitions" }] : /* istanbul ignore next */ []));
7519
7408
  //#endregion
7520
7409
  //#region ---- Computed Properties ----
7521
7410
  /**
@@ -7534,46 +7423,7 @@ class AXPEntityPreloadFiltersViewModel {
7534
7423
  * All filter definitions for properties with preload enabled
7535
7424
  */
7536
7425
  this.preloadFiltersDef = computed(() => {
7537
- const props = this.entityDef.properties.filter((c) => c.options?.filter?.preload?.enabled);
7538
- return props.map((e) => {
7539
- const widgetConfig = this.widgetResolver.resolve(e.schema.interface?.type);
7540
- const type = e.schema.interface?.type;
7541
- // Merge validations with existing options
7542
- const validations = e.options?.filter?.preload?.required
7543
- ? [
7544
- {
7545
- rule: 'required',
7546
- message: 'This field is required',
7547
- options: {},
7548
- },
7549
- ]
7550
- : [];
7551
- const mergedOptions = {
7552
- ...e.schema.interface?.options,
7553
- validations,
7554
- };
7555
- return {
7556
- title: e.title,
7557
- field: e.name,
7558
- operator: {
7559
- type: 'contains',
7560
- },
7561
- widget: {
7562
- ...e.schema.interface,
7563
- path: e.name,
7564
- type,
7565
- options: mergedOptions,
7566
- },
7567
- filters: [],
7568
- isParametric: false,
7569
- icon: widgetConfig?.icon,
7570
- filterType: {
7571
- advance: false,
7572
- inline: false,
7573
- preload: e.options?.filter?.preload,
7574
- },
7575
- };
7576
- });
7426
+ return this.filterDefinitions().filter((definition) => definition.filterType.preload?.enabled);
7577
7427
  }, ...(ngDevMode ? [{ debugName: "preloadFiltersDef" }] : /* istanbul ignore next */ []));
7578
7428
  /**
7579
7429
  * Required filter definitions only
@@ -7582,7 +7432,14 @@ class AXPEntityPreloadFiltersViewModel {
7582
7432
  return this.preloadFiltersDef().filter((c) => c.filterType.preload?.required);
7583
7433
  }, ...(ngDevMode ? [{ debugName: "requiredFiltersDef" }] : /* istanbul ignore next */ []));
7584
7434
  }
7435
+ //#endregion
7585
7436
  //#region ---- Methods ----
7437
+ async loadFilterDefinitions() {
7438
+ const definitions = await collectEntityListFilterDefinitions(this.entityDef, (moduleName, entityName) => this.entityRegistry.resolve(moduleName, entityName).catch(() => null), {
7439
+ resolveWidget: (type) => this.widgetResolver.resolve(type),
7440
+ });
7441
+ this.filterDefinitions.set(definitions);
7442
+ }
7586
7443
  /**
7587
7444
  * Serialize filter values to plain objects (remove signals, functions, etc.)
7588
7445
  */
@@ -7599,7 +7456,9 @@ const AXPEntityPreloadFiltersViewModelResolver = async (route, state) => {
7599
7456
  const entityName = route.paramMap.get('entity');
7600
7457
  try {
7601
7458
  const entity = await entityRegistry.resolve(moduleName, entityName);
7602
- return new AXPEntityPreloadFiltersViewModel(injector, entity);
7459
+ const vm = new AXPEntityPreloadFiltersViewModel(injector, entity);
7460
+ await vm.loadFilterDefinitions();
7461
+ return vm;
7603
7462
  }
7604
7463
  catch (error) {
7605
7464
  if (error instanceof AXPNotFoundError) {
@@ -7610,150 +7469,6 @@ const AXPEntityPreloadFiltersViewModelResolver = async (route, state) => {
7610
7469
  };
7611
7470
  //#endregion
7612
7471
 
7613
- //#endregion
7614
- //#region ---- Quick search: schema-driven field paths ----
7615
- const NON_TEXT_DATATYPES = new Set([
7616
- 'number',
7617
- 'integer',
7618
- 'int',
7619
- 'long',
7620
- 'float',
7621
- 'double',
7622
- 'decimal',
7623
- 'money',
7624
- 'currency',
7625
- 'boolean',
7626
- 'bool',
7627
- 'date',
7628
- 'datetime',
7629
- 'time',
7630
- 'object',
7631
- 'array',
7632
- 'json',
7633
- 'image',
7634
- 'file',
7635
- 'binary',
7636
- ]);
7637
- /**
7638
- * Whether an entity property likely stores free text worth a `contains` quick-search clause.
7639
- */
7640
- function isTextLikeDataType(dataType) {
7641
- const dt = (dataType ?? 'string').toLowerCase().trim();
7642
- if (!dt || NON_TEXT_DATATYPES.has(dt)) {
7643
- return false;
7644
- }
7645
- return true;
7646
- }
7647
- /**
7648
- * Lodash-get paths for quick search from a single entity definition: string-like property names
7649
- * plus lookup `expose[].target` paths (e.g. `brand.title`).
7650
- */
7651
- function collectQuickSearchPathsFromSingleEntityDefinition(entity) {
7652
- if (!entity?.properties?.length) {
7653
- return [];
7654
- }
7655
- const paths = new Set();
7656
- for (const p of entity.properties) {
7657
- if (isTextLikeDataType(p.schema?.dataType)) {
7658
- paths.add(p.name);
7659
- }
7660
- const opts = p.schema?.interface?.options;
7661
- const expose = opts?.['expose'];
7662
- if (!Array.isArray(expose)) {
7663
- continue;
7664
- }
7665
- for (const row of expose) {
7666
- if (row && typeof row === 'object' && typeof row.target === 'string') {
7667
- const t = (row.target).trim();
7668
- if (t) {
7669
- paths.add(t);
7670
- }
7671
- }
7672
- }
7673
- }
7674
- return [...paths];
7675
- }
7676
- //#endregion
7677
- //#region ---- Column-derived nested paths ----
7678
- /**
7679
- * Adds dotted paths from master columns (`name` or `options.dataPath`), e.g. `person.fullName`, `jobDefinition.title`.
7680
- */
7681
- function collectNestedFieldPathsFromEntityColumns(entity) {
7682
- if (!entity?.columns?.length) {
7683
- return [];
7684
- }
7685
- const paths = new Set();
7686
- for (const col of entity.columns) {
7687
- const name = col.name.trim();
7688
- if (name.includes('.')) {
7689
- paths.add(name);
7690
- }
7691
- const rawDp = col.options?.['dataPath'];
7692
- if (typeof rawDp === 'string') {
7693
- const dp = rawDp.trim();
7694
- if (dp.includes('.')) {
7695
- paths.add(dp);
7696
- }
7697
- }
7698
- }
7699
- return [...paths];
7700
- }
7701
- //#endregion
7702
- //#region ---- Related merge-detail paths ----
7703
- function parseRelatedEntityFullName(fullName) {
7704
- const t = fullName.trim();
7705
- const idx = t.indexOf('.');
7706
- if (idx <= 0 || idx >= t.length - 1) {
7707
- return null;
7708
- }
7709
- return {
7710
- moduleName: t.slice(0, idx),
7711
- entityName: t.slice(idx + 1),
7712
- };
7713
- }
7714
- //#endregion
7715
- //#region ---- Public API ----
7716
- /**
7717
- * Collects lodash-get field paths used for mock/API quick search (`contains` / OR filters):
7718
- * host properties and lookup expose targets, dotted column paths, and merge-detail related entities
7719
- * prefixed with the related entity merge `persistence.dataPath` (e.g. `person.firstName`).
7720
- */
7721
- async function collectEntityQuickSearchFieldPaths(entity, resolveRelatedDefinition) {
7722
- if (!entity) {
7723
- return [];
7724
- }
7725
- const paths = new Set();
7726
- for (const p of collectQuickSearchPathsFromSingleEntityDefinition(entity)) {
7727
- paths.add(p);
7728
- }
7729
- for (const p of collectNestedFieldPathsFromEntityColumns(entity)) {
7730
- paths.add(p);
7731
- }
7732
- const related = entity.relatedEntities ?? [];
7733
- for (const rel of related) {
7734
- const dataPath = rel.persistence?.dataPath?.trim();
7735
- if (!dataPath || rel.layout?.type !== 'merge-detail') {
7736
- continue;
7737
- }
7738
- const parsed = rel.entity ? parseRelatedEntityFullName(rel.entity) : null;
7739
- if (!parsed) {
7740
- continue;
7741
- }
7742
- const relatedDef = await resolveRelatedDefinition(parsed.moduleName, parsed.entityName);
7743
- if (!relatedDef) {
7744
- continue;
7745
- }
7746
- for (const p of collectQuickSearchPathsFromSingleEntityDefinition(relatedDef)) {
7747
- paths.add(`${dataPath}.${p}`);
7748
- }
7749
- for (const p of collectNestedFieldPathsFromEntityColumns(relatedDef)) {
7750
- paths.add(`${dataPath}.${p}`);
7751
- }
7752
- }
7753
- return [...paths];
7754
- }
7755
- //#endregion
7756
-
7757
7472
  //#region ---- Path / numeric helpers ----
7758
7473
  function getPath(obj, path) {
7759
7474
  if (obj == null || path.length === 0) {
@@ -12392,6 +12107,7 @@ class AXPEntityListTableService {
12392
12107
  const evaluatedOptions = await this.evaluateExpressions(action?.options, data);
12393
12108
  const options = this.mergeRelatedListFormOptions(command, evaluatedOptions, relatedListExcludeProperties);
12394
12109
  if (this.commandService.exists(command)) {
12110
+ const excludeProperties = options['excludeProperties'];
12395
12111
  await this.commandService.execute(command, {
12396
12112
  __context__: {
12397
12113
  entity: getEntityInfo(entity).source,
@@ -12408,6 +12124,7 @@ class AXPEntityListTableService {
12408
12124
  },
12409
12125
  options,
12410
12126
  metadata: action?.metadata,
12127
+ ...(excludeProperties?.length ? { excludeProperties } : {}),
12411
12128
  });
12412
12129
  }
12413
12130
  else {
@@ -12433,7 +12150,7 @@ class AXPEntityListTableService {
12433
12150
  mergeRelatedListFormOptions(command, evaluatedOptions, relatedListExcludeProperties) {
12434
12151
  const exclusions = relatedListExcludeProperties?.filter(Boolean);
12435
12152
  if (!exclusions?.length ||
12436
- (command !== 'Entity:Create' && command !== 'Entity:Update')) {
12153
+ (command !== 'Entity:Create' && command !== 'Entity:Update' && command !== 'Entity:View')) {
12437
12154
  return evaluatedOptions;
12438
12155
  }
12439
12156
  return {
@@ -12484,6 +12201,7 @@ class AXPEntityListToolbarService {
12484
12201
  constructor() {
12485
12202
  //#region ---- Services & Dependencies ----
12486
12203
  this.widgetResolver = inject(AXPWidgetRegistryService);
12204
+ this.entityRegistry = inject(AXPEntityDefinitionRegistryService);
12487
12205
  }
12488
12206
  //#endregion
12489
12207
  //#region ---- Public Methods ----
@@ -12491,7 +12209,7 @@ class AXPEntityListToolbarService {
12491
12209
  * Convert Entity to Toolbar Options
12492
12210
  */
12493
12211
  async convertEntityToolbarOptions(entity, options) {
12494
- const baseFilters = this.createFilterDefinitions(entity);
12212
+ const baseFilters = await this.createFilterDefinitions(entity);
12495
12213
  const toolbarOptions = {
12496
12214
  filterDefinitions: this.mergeFilterDefinitions(baseFilters, options?.customFilterDefinitions),
12497
12215
  columnDefinitions: this.createColumnDefinitions(entity, options),
@@ -12571,30 +12289,9 @@ class AXPEntityListToolbarService {
12571
12289
  /**
12572
12290
  * Create Filter Definitions for Toolbar
12573
12291
  */
12574
- createFilterDefinitions(entity) {
12575
- const props = entity.properties.filter((c) => c.options?.filter?.advance?.enabled || c.options?.filter?.inline?.enabled);
12576
- return props.map((e) => {
12577
- const widgetConfig = this.widgetResolver.resolve(e.schema.interface?.type);
12578
- const type = (e.options?.filter?.advance?.widgetType ||
12579
- widgetConfig?.defaultFilterWidgetName ||
12580
- e.schema.interface?.type);
12581
- const iface = e.schema.interface ?? {};
12582
- return {
12583
- title: e.title,
12584
- field: e.name,
12585
- operator: {
12586
- type: 'contains',
12587
- },
12588
- widget: { ...omit(iface, 'triggers'), path: e.name, type },
12589
- filters: [],
12590
- isParametric: false,
12591
- icon: widgetConfig?.icon,
12592
- filterType: {
12593
- advance: e.options?.filter?.advance?.enabled ?? false,
12594
- inline: e.options?.filter?.inline?.enabled ?? false,
12595
- },
12596
- triggers: e.schema.interface?.triggers,
12597
- };
12292
+ async createFilterDefinitions(entity) {
12293
+ return collectEntityListFilterDefinitions(entity, (moduleName, entityName) => this.entityRegistry.resolve(moduleName, entityName).catch(() => null), {
12294
+ resolveWidget: (type) => this.widgetResolver.resolve(type),
12598
12295
  });
12599
12296
  }
12600
12297
  /**
@@ -13977,6 +13674,8 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
13977
13674
  super(...arguments);
13978
13675
  this.formatService = inject(AXFormatService);
13979
13676
  this.translation = inject(AXTranslationService);
13677
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
13678
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
13980
13679
  this.entityResolver = inject(AXPEntityDefinitionRegistryService);
13981
13680
  this.entity = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entity" }] : /* istanbul ignore next */ []));
13982
13681
  this.multiple = computed(() => this.options()['multiple'], ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
@@ -14010,7 +13709,7 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
14010
13709
  if (typeof item == 'object') {
14011
13710
  return {
14012
13711
  id: item[this.valueField()],
14013
- text: this.getDisplayRaw(item),
13712
+ text: await this.getDisplayRaw(item),
14014
13713
  };
14015
13714
  }
14016
13715
  const def = this.entityDef();
@@ -14021,7 +13720,7 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
14021
13720
  this.loading.set(false);
14022
13721
  return {
14023
13722
  id: fetchedItem[this.valueField()],
14024
- text: this.getDisplayRaw(fetchedItem),
13723
+ text: await this.getDisplayRaw(fetchedItem),
14025
13724
  };
14026
13725
  }
14027
13726
  return {
@@ -14029,12 +13728,17 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
14029
13728
  text: item,
14030
13729
  };
14031
13730
  }
14032
- getDisplayRaw(item) {
14033
- const text = formatLookupItemDisplay(item, this.entityDef(), {
13731
+ async getDisplayRaw(item) {
13732
+ const locale = this.translation.getActiveLang() ?? 'en-US';
13733
+ return formatLookupItemDisplayAsync(item, this.entityDef(), {
14034
13734
  displayFormat: this.options()['displayFormat'],
14035
13735
  textField: this.textField(),
14036
- }, this.formatService, (value) => this.translation.resolve(value));
14037
- return text;
13736
+ }, this.formatService, {
13737
+ expressionEvaluator: this.expressionEvaluator,
13738
+ contextEvalFactory: this.contextEvalFactory,
13739
+ translationService: this.translation,
13740
+ locale,
13741
+ }, (value) => this.translation.resolve(value));
14038
13742
  }
14039
13743
  get __class() {
14040
13744
  const cls = {};
@@ -15184,6 +14888,8 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15184
14888
  this.formatService = inject(AXFormatService);
15185
14889
  this.translateService = inject(AXTranslationService);
15186
14890
  this.entityDataSelectorService = inject(AXPEntityDataSelectorService);
14891
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
14892
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
15187
14893
  //#endregion
15188
14894
  //#region ---- Inputs ----
15189
14895
  this.selectedItems = input.required(...(ngDevMode ? [{ debugName: "selectedItems" }] : /* istanbul ignore next */ []));
@@ -15213,6 +14919,8 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15213
14919
  //#region ---- Internal State ----
15214
14920
  this.searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : /* istanbul ignore next */ []));
15215
14921
  this.isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
14922
+ this.itemLabels = signal({}, ...(ngDevMode ? [{ debugName: "itemLabels" }] : /* istanbul ignore next */ []));
14923
+ this.itemLabelsVersion = 0;
15216
14924
  //#endregion
15217
14925
  //#region ---- View Children ----
15218
14926
  this.tagBox = viewChild('tagBoxComponent', ...(ngDevMode ? [{ debugName: "tagBox" }] : /* istanbul ignore next */ []));
@@ -15235,6 +14943,31 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15235
14943
  }
15236
14944
  }
15237
14945
  }, ...(ngDevMode ? [{ debugName: "#focusEffect" }] : /* istanbul ignore next */ []));
14946
+ this.#itemLabelsEffect = effect(() => {
14947
+ void this.translateService.getActiveLang();
14948
+ const items = this.selectedItemsValue();
14949
+ const entityDef = this.entityDef()();
14950
+ const valueField = this.valueFieldValue();
14951
+ const version = ++this.itemLabelsVersion;
14952
+ void Promise.all(items.map(async (item) => {
14953
+ const id = String(get(item, valueField) ?? '');
14954
+ const label = await formatLookupItemDisplayAsync(item, entityDef, {
14955
+ displayFormat: this.displayFormatValue(),
14956
+ textField: this.displayFieldValue(),
14957
+ }, this.formatService, {
14958
+ expressionEvaluator: this.expressionEvaluator,
14959
+ contextEvalFactory: this.contextEvalFactory,
14960
+ translationService: this.translateService,
14961
+ locale: this.translateService.getActiveLang() ?? 'en-US',
14962
+ }, (value) => this.translateService.resolve(value));
14963
+ return [id, label];
14964
+ })).then((entries) => {
14965
+ if (version !== this.itemLabelsVersion) {
14966
+ return;
14967
+ }
14968
+ this.itemLabels.set(Object.fromEntries(entries));
14969
+ });
14970
+ }, ...(ngDevMode ? [{ debugName: "#itemLabelsEffect" }] : /* istanbul ignore next */ []));
15238
14971
  //#endregion
15239
14972
  //#region ---- Computed Properties ----
15240
14973
  this.tagBoxComponent = computed(() => this.tagBox(), ...(ngDevMode ? [{ debugName: "tagBoxComponent" }] : /* istanbul ignore next */ []));
@@ -15250,6 +14983,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15250
14983
  this.placeholderValue = computed(() => this.placeholder()?.() ?? '', ...(ngDevMode ? [{ debugName: "placeholderValue" }] : /* istanbul ignore next */ []));
15251
14984
  }
15252
14985
  #focusEffect;
14986
+ #itemLabelsEffect;
15253
14987
  focus() {
15254
14988
  this.shouldFocus.set(true);
15255
14989
  }
@@ -15315,11 +15049,9 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15315
15049
  }
15316
15050
  //#endregion
15317
15051
  //#region ---- Utility Methods ----
15318
- getDisplayRaw(item) {
15319
- return formatLookupItemDisplay(item, this.entityDef()(), {
15320
- displayFormat: this.displayFormatValue(),
15321
- textField: this.displayFieldValue(),
15322
- }, this.formatService, (value) => this.translateService.resolve(value));
15052
+ getItemLabel(item) {
15053
+ const id = String(get(item, this.valueFieldValue()) ?? '');
15054
+ return this.itemLabels()[id] ?? '';
15323
15055
  }
15324
15056
  /**
15325
15057
  * Get current input value from tag box
@@ -15466,7 +15198,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15466
15198
  </ax-tag-box>
15467
15199
  <ng-template #tagTemplate let-item let-index="index">
15468
15200
  <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">
15469
- <span>{{ getDisplayRaw(item) | translate | async }}</span>
15201
+ <span>{{ getItemLabel(item) }}</span>
15470
15202
  <button type="button" (click)="tagBoxComponent.removeItem(index)">
15471
15203
  <ax-icon class="ax-icon ax-icon-close"></ax-icon>
15472
15204
  </button>
@@ -15526,7 +15258,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
15526
15258
  </ax-tag-box>
15527
15259
  <ng-template #tagTemplate let-item let-index="index">
15528
15260
  <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">
15529
- <span>{{ getDisplayRaw(item) | translate | async }}</span>
15261
+ <span>{{ getItemLabel(item) }}</span>
15530
15262
  <button type="button" (click)="tagBoxComponent.removeItem(index)">
15531
15263
  <ax-icon class="ax-icon ax-icon-close"></ax-icon>
15532
15264
  </button>
@@ -16004,6 +15736,8 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16004
15736
  this.entityService = inject(AXPEntityService);
16005
15737
  this.entityResolver = inject(AXPEntityDefinitionRegistryService);
16006
15738
  this.queryExecutor = inject(AXPQueryExecutor);
15739
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
15740
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
16007
15741
  //#endregion
16008
15742
  //#region ---- View Children ----
16009
15743
  this.moreButton = viewChild('moreButton', ...(ngDevMode ? [{ debugName: "moreButton" }] : /* istanbul ignore next */ []));
@@ -16041,11 +15775,16 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16041
15775
  this.resolveError = signal(null, ...(ngDevMode ? [{ debugName: "resolveError" }] : /* istanbul ignore next */ []));
16042
15776
  this.summaryLabel = signal('', ...(ngDevMode ? [{ debugName: "summaryLabel" }] : /* istanbul ignore next */ []));
16043
15777
  this.popoverHeader = signal('', ...(ngDevMode ? [{ debugName: "popoverHeader" }] : /* istanbul ignore next */ []));
15778
+ this.mainItemLabels = signal([], ...(ngDevMode ? [{ debugName: "mainItemLabels" }] : /* istanbul ignore next */ []));
15779
+ this.lazyPopoverItemLabels = signal([], ...(ngDevMode ? [{ debugName: "lazyPopoverItemLabels" }] : /* istanbul ignore next */ []));
16044
15780
  this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : /* istanbul ignore next */ []));
16045
15781
  this.hydratedDisplayItems = signal(null, ...(ngDevMode ? [{ debugName: "hydratedDisplayItems" }] : /* istanbul ignore next */ []));
16046
15782
  this.hydrateRequestId = 0;
15783
+ this.mainLabelsVersion = 0;
15784
+ this.lazyPopoverLabelsVersion = 0;
16047
15785
  //#endregion
16048
15786
  //#region ---- Computed ----
15787
+ this.popoverItemLabels = computed(() => this.isHydratedStrategy() ? this.mainItemLabels() : this.lazyPopoverItemLabels(), ...(ngDevMode ? [{ debugName: "popoverItemLabels" }] : /* istanbul ignore next */ []));
16049
15788
  this.displayItems = computed(() => isNil(this.rawValue)
16050
15789
  ? []
16051
15790
  : castArray(this.rawValue)
@@ -16165,6 +15904,36 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16165
15904
  }
16166
15905
  void this.hydrateScalarIds(entityKey, values);
16167
15906
  });
15907
+ effect(() => {
15908
+ void this.translation.getActiveLang();
15909
+ this.entityDef();
15910
+ const items = this.allItems();
15911
+ const version = ++this.mainLabelsVersion;
15912
+ void this.resolveLabelsForItems(items).then((labels) => {
15913
+ if (version === this.mainLabelsVersion) {
15914
+ this.mainItemLabels.set(labels);
15915
+ }
15916
+ });
15917
+ });
15918
+ effect(() => {
15919
+ if (this.isHydratedStrategy()) {
15920
+ return;
15921
+ }
15922
+ void this.translation.getActiveLang();
15923
+ this.entityDef();
15924
+ const status = this.resolveStatus();
15925
+ const items = this.resolvedPopoverItems();
15926
+ if (status !== 'ready') {
15927
+ this.lazyPopoverItemLabels.set([]);
15928
+ return;
15929
+ }
15930
+ const version = ++this.lazyPopoverLabelsVersion;
15931
+ void this.resolveLabelsForItems(items).then((labels) => {
15932
+ if (version === this.lazyPopoverLabelsVersion) {
15933
+ this.lazyPopoverItemLabels.set(labels);
15934
+ }
15935
+ });
15936
+ });
16168
15937
  }
16169
15938
  //#endregion
16170
15939
  //#region ---- Public methods ----
@@ -16220,7 +15989,9 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16220
15989
  let resolvedTitle = '';
16221
15990
  if (headerItem != null && this.hasDisplayTextOnLookupValue(headerItem)) {
16222
15991
  resolvedTitle =
16223
- typeof headerItem === 'object' ? this.renderLookupLabel(headerItem) : this.formatDisplayValue(headerItem);
15992
+ typeof headerItem === 'object'
15993
+ ? await this.resolveItemLabel(headerItem)
15994
+ : this.formatDisplayValue(headerItem);
16224
15995
  }
16225
15996
  else if (!this.isMultiValueLookup()) {
16226
15997
  const rowText = this.getRowDisplayTextFromTextField();
@@ -16229,8 +16000,7 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16229
16000
  }
16230
16001
  }
16231
16002
  if (!resolvedTitle) {
16232
- const displayTitle = formatLookupItemDisplay(headerItem, this.entityDef(), this.lookupDisplayOptions(), this.formatService, (value) => this.translation.resolve(value));
16233
- resolvedTitle = typeof displayTitle === 'string' ? displayTitle : this.translation.resolve(displayTitle);
16003
+ resolvedTitle = await this.resolveItemLabel(headerItem);
16234
16004
  if (isUnresolvedEntityDisplayTemplate(resolvedTitle)) {
16235
16005
  resolvedTitle = '';
16236
16006
  }
@@ -16296,8 +16066,22 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16296
16066
  const values = castArray(raw).filter((value) => value != null && value !== '');
16297
16067
  return values.length > 0 && values.every((value) => this.hasDisplayTextOnLookupValue(value));
16298
16068
  }
16299
- getDisplayRaw(item) {
16300
- if (item != null && typeof item === 'object' && this.translation.isValidMultiLanguageObject(item)) {
16069
+ getItemLabel(index) {
16070
+ return this.mainItemLabels()[index] ?? '';
16071
+ }
16072
+ getPopoverItemLabel(index) {
16073
+ return this.popoverItemLabels()[index] ?? '';
16074
+ }
16075
+ //#endregion
16076
+ //#region ---- Private methods ----
16077
+ async resolveLabelsForItems(items) {
16078
+ return Promise.all(items.map((item) => this.resolveItemLabel(item)));
16079
+ }
16080
+ async resolveItemLabel(item) {
16081
+ if (item == null) {
16082
+ return '';
16083
+ }
16084
+ if (typeof item === 'object' && this.translation.isValidMultiLanguageObject(item)) {
16301
16085
  return this.translation.resolve(item);
16302
16086
  }
16303
16087
  if (!this.isMultiValueLookup()) {
@@ -16306,16 +16090,19 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16306
16090
  return this.formatDisplayValue(rowText);
16307
16091
  }
16308
16092
  }
16309
- if (item != null && this.hasDisplayTextOnLookupValue(item)) {
16310
- if (typeof item === 'object') {
16311
- return this.renderLookupLabel(item);
16093
+ if (this.hasDisplayTextOnLookupValue(item)) {
16094
+ if (typeof item !== 'object') {
16095
+ return this.formatDisplayValue(item);
16312
16096
  }
16313
- return this.formatDisplayValue(item);
16314
16097
  }
16315
- return this.renderLookupLabel(item);
16098
+ const locale = this.translation.getActiveLang() ?? 'en-US';
16099
+ return formatLookupItemDisplayAsync(item, this.entityDef(), this.lookupDisplayOptions(), this.formatService, {
16100
+ expressionEvaluator: this.expressionEvaluator,
16101
+ contextEvalFactory: this.contextEvalFactory,
16102
+ translationService: this.translation,
16103
+ locale,
16104
+ }, (value) => this.translation.resolve(value));
16316
16105
  }
16317
- //#endregion
16318
- //#region ---- Private methods ----
16319
16106
  async refreshSummaryLabel(count) {
16320
16107
  const text = await this.translation.translateAsync('@general:widgets.lookup.column.items-count', {
16321
16108
  params: { count: String(count) },
@@ -16639,10 +16426,6 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16639
16426
  return !isNil(candidate) && candidate !== '' && !this.isLikelyEntityId(candidate);
16640
16427
  });
16641
16428
  }
16642
- renderLookupLabel(value) {
16643
- const label = formatLookupItemDisplay(value, this.entityDef(), this.lookupDisplayOptions(), this.formatService, (item) => this.translation.resolve(item));
16644
- return typeof label === 'string' ? label : this.translation.resolve(label);
16645
- }
16646
16429
  formatDisplayValue(value) {
16647
16430
  if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
16648
16431
  return String(value);
@@ -16663,11 +16446,11 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16663
16446
  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);
16664
16447
  }
16665
16448
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetColumnComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
16666
- 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 @let label = getDisplayRaw(item);\n <span [class.ax-cursor-pointer]=\"detailPopoverEnabled()\" [class.hover:ax-text-primary]=\"detailPopoverEnabled()\"\n [class.hover:ax-underline]=\"detailPopoverEnabled()\" (click)=\"handleItemClick($index, $event)\">\n {{ label }}\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-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 @let label = getDisplayRaw(item);\n <span [class.ax-cursor-pointer]=\"detailPopoverEnabled()\" [class.hover:ax-text-primary]=\"detailPopoverEnabled()\"\n [class.hover:ax-underline]=\"detailPopoverEnabled()\" (click)=\"handlePopoverItemClick($index, $event)\">\n {{ label }}\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$3.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 }); }
16449
+ 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\n [class.ax-cursor-pointer]=\"detailPopoverEnabled()\"\n [class.hover:ax-text-primary]=\"detailPopoverEnabled()\"\n [class.hover:ax-underline]=\"detailPopoverEnabled()\"\n (click)=\"handleItemClick($index, $event)\"\n >\n {{ getItemLabel($index) }}\n </span>\n @if ($index < visibleItems().length - 1) {\n <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()\"\n #moreButton\n >\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\n class=\"ax-cursor-pointer ax-text-primary hover:ax-underline\"\n (click)=\"openLazyPopover(); $event.stopPropagation()\"\n #lazyTrigger\n >\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-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\n [class.ax-cursor-pointer]=\"detailPopoverEnabled()\"\n [class.hover:ax-text-primary]=\"detailPopoverEnabled()\"\n [class.hover:ax-underline]=\"detailPopoverEnabled()\"\n (click)=\"handlePopoverItemClick($index, $event)\"\n >\n {{ getPopoverItemLabel($index) }}\n </span>\n } @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n </div>\n }\n </div>\n</ax-popover>\n", 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$3.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 }); }
16667
16450
  }
16668
16451
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetColumnComponent, decorators: [{
16669
16452
  type: Component,
16670
- 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 @let label = getDisplayRaw(item);\n <span [class.ax-cursor-pointer]=\"detailPopoverEnabled()\" [class.hover:ax-text-primary]=\"detailPopoverEnabled()\"\n [class.hover:ax-underline]=\"detailPopoverEnabled()\" (click)=\"handleItemClick($index, $event)\">\n {{ label }}\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-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 @let label = getDisplayRaw(item);\n <span [class.ax-cursor-pointer]=\"detailPopoverEnabled()\" [class.hover:ax-text-primary]=\"detailPopoverEnabled()\"\n [class.hover:ax-underline]=\"detailPopoverEnabled()\" (click)=\"handlePopoverItemClick($index, $event)\">\n {{ label }}\n </span>\n } @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n </div>\n }\n </div>\n</ax-popover>" }]
16453
+ 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\n [class.ax-cursor-pointer]=\"detailPopoverEnabled()\"\n [class.hover:ax-text-primary]=\"detailPopoverEnabled()\"\n [class.hover:ax-underline]=\"detailPopoverEnabled()\"\n (click)=\"handleItemClick($index, $event)\"\n >\n {{ getItemLabel($index) }}\n </span>\n @if ($index < visibleItems().length - 1) {\n <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()\"\n #moreButton\n >\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\n class=\"ax-cursor-pointer ax-text-primary hover:ax-underline\"\n (click)=\"openLazyPopover(); $event.stopPropagation()\"\n #lazyTrigger\n >\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-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\n [class.ax-cursor-pointer]=\"detailPopoverEnabled()\"\n [class.hover:ax-text-primary]=\"detailPopoverEnabled()\"\n [class.hover:ax-underline]=\"detailPopoverEnabled()\"\n (click)=\"handlePopoverItemClick($index, $event)\"\n >\n {{ getPopoverItemLabel($index) }}\n </span>\n } @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n </div>\n }\n </div>\n</ax-popover>\n" }]
16671
16454
  }], 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 }] }] } });
16672
16455
 
16673
16456
  var lookupWidgetColumn_component = /*#__PURE__*/Object.freeze({
@@ -21930,13 +21713,20 @@ class AXPPageDetailsConverter extends AXPBaseRelatedEntityConverter {
21930
21713
  const p = relatedEntity?.persistence || {};
21931
21714
  const strategy = p.strategy || 'embedded';
21932
21715
  const mappedTargets = Object.keys(p.map || {}).map((k) => (k || '').split('.')[0]);
21716
+ const excludeProperties = relatedEntity.excludeProperties && relatedEntity.excludeProperties.length > 0
21717
+ ? new Set(relatedEntity.excludeProperties)
21718
+ : undefined;
21933
21719
  const helpers = {
21934
21720
  ...baseHelpers,
21935
21721
  getPropertyByGroupId: (groupId) => {
21936
- const props = baseHelpers.getPropertyByGroupId(groupId) ?? [];
21937
- if (strategy !== 'referenced' || mappedTargets.length === 0)
21938
- return props;
21939
- return props.filter((prop) => !mappedTargets.includes(prop?.name));
21722
+ let props = baseHelpers.getPropertyByGroupId(groupId) ?? [];
21723
+ if (strategy === 'referenced' && mappedTargets.length > 0) {
21724
+ props = props.filter((prop) => !mappedTargets.includes(prop?.name ?? ''));
21725
+ }
21726
+ if (excludeProperties) {
21727
+ props = props.filter((prop) => !excludeProperties.has(prop.name ?? ''));
21728
+ }
21729
+ return props;
21940
21730
  },
21941
21731
  };
21942
21732
  const evaluateExpressions = async (actionData) => {
@@ -22054,18 +21844,70 @@ class AXPPageDetailsConverter extends AXPBaseRelatedEntityConverter {
22054
21844
  }
22055
21845
  createLoadFunction(entityDef, relatedEntity, evaluateExpressions) {
22056
21846
  return async (context) => {
22057
- const fn = entityDef?.queries.byKey?.execute;
21847
+ const conditions = relatedEntity.conditions ?? [];
21848
+ if (conditions.length > 0) {
21849
+ const evaluatedFilters = await Promise.all(conditions.map(async (c) => ({
21850
+ field: c.name,
21851
+ operator: c.operator,
21852
+ value: await evaluateExpressions(c.value),
21853
+ })));
21854
+ if (conditions.length === 1 && conditions[0].name === 'id') {
21855
+ const byKeyFn = entityDef?.queries?.byKey?.execute;
21856
+ const id = evaluatedFilters[0]?.value;
21857
+ const result = id ? await byKeyFn(id) : null;
21858
+ return { success: true, data: result ?? {} };
21859
+ }
21860
+ const listFn = entityDef?.queries?.list?.execute;
21861
+ const filter = evaluatedFilters.length === 1
21862
+ ? evaluatedFilters[0]
21863
+ : { logic: 'and', filters: evaluatedFilters };
21864
+ const page = await listFn({ skip: 0, take: 1, filter });
21865
+ const item = page?.items?.[0];
21866
+ const data = item ? { ...item } : {};
21867
+ if (!item) {
21868
+ for (const evaluated of evaluatedFilters) {
21869
+ if (evaluated.field) {
21870
+ set(data, evaluated.field, evaluated.value);
21871
+ }
21872
+ }
21873
+ }
21874
+ return { success: true, data };
21875
+ }
21876
+ const fn = entityDef?.queries?.byKey?.execute;
22058
21877
  const conditionValues = relatedEntity.conditions?.map((c) => c.value) ?? [];
22059
21878
  const evaluatedConditionValues = await Promise.all(conditionValues.map((c) => evaluateExpressions(c)));
22060
21879
  const id = evaluatedConditionValues[0];
22061
- const result = await fn(id);
22062
- return { success: true, data: result };
21880
+ const result = id ? await fn(id) : null;
21881
+ return { success: true, data: result ?? {} };
22063
21882
  };
22064
21883
  }
22065
21884
  createExecuteFunction(entityDef, actions, evaluateExpressions, converterContext) {
22066
21885
  return async (e, context) => {
22067
21886
  try {
22068
21887
  if (e.name === 'update-entity') {
21888
+ const recordId = context?.['id'];
21889
+ if (!recordId) {
21890
+ const createFn = entityDef?.commands?.create?.execute;
21891
+ const created = await createFn(context);
21892
+ if (created && typeof created === 'object' && 'success' in created) {
21893
+ const cmd = created;
21894
+ if (!cmd.success) {
21895
+ const errorText = commandMessageTextForError(cmd.message?.text) || 'Failed to create entity';
21896
+ return {
21897
+ success: false,
21898
+ message: cmd.message ?? { text: errorText },
21899
+ };
21900
+ }
21901
+ return {
21902
+ success: true,
21903
+ data: cmd.data ?? created,
21904
+ };
21905
+ }
21906
+ return {
21907
+ success: true,
21908
+ data: created,
21909
+ };
21910
+ }
22069
21911
  const fn = entityDef?.commands?.update?.execute;
22070
21912
  const result = await fn(context);
22071
21913
  if (result && typeof result === 'object' && 'success' in result) {
@@ -22327,11 +22169,16 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
22327
22169
  const excludeForUpdate = commandName === 'Entity:Update' &&
22328
22170
  relatedEntity.excludeProperties &&
22329
22171
  relatedEntity.excludeProperties.length > 0;
22172
+ const excludeForView = commandName === 'Entity:View' &&
22173
+ relatedEntity.excludeProperties &&
22174
+ relatedEntity.excludeProperties.length > 0;
22330
22175
  const mergedOptions = excludeForCreate
22331
22176
  ? { ...evaluatedOptions, excludeProperties: createExcludes }
22332
22177
  : excludeForUpdate
22333
22178
  ? { ...evaluatedOptions, excludeProperties: relatedEntity.excludeProperties }
22334
- : evaluatedOptions;
22179
+ : excludeForView
22180
+ ? { ...evaluatedOptions, excludeProperties: relatedEntity.excludeProperties }
22181
+ : evaluatedOptions;
22335
22182
  if (context.commandService.exists(commandName)) {
22336
22183
  // check options for evaluation
22337
22184
  await context.commandService.execute(commandName, {
@@ -22350,6 +22197,7 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
22350
22197
  },
22351
22198
  options: mergedOptions,
22352
22199
  metadata: action.metadata,
22200
+ ...(excludeForView ? { excludeProperties: relatedEntity.excludeProperties } : {}),
22353
22201
  });
22354
22202
  }
22355
22203
  else {
@@ -23260,6 +23108,7 @@ class AXPLayoutAdapterFactory {
23260
23108
  this.layoutAdapterBuilder = layoutAdapterBuilder;
23261
23109
  this.filterOperatorMiddleware = filterOperatorMiddleware;
23262
23110
  this.pageComponentConverter = inject(AXPPageComponentConverter);
23111
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
23263
23112
  }
23264
23113
  async createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies) {
23265
23114
  const entity = await entityResolver.resolve(moduleName, entityName);
@@ -23313,9 +23162,7 @@ class AXPLayoutAdapterFactory {
23313
23162
  if (hidden && typeof hidden === 'string') {
23314
23163
  try {
23315
23164
  const scope = {
23316
- context: {
23317
- eval: (path) => get(rootContext, path),
23318
- },
23165
+ context: this.contextEvalFactory.createScope(rootContext),
23319
23166
  };
23320
23167
  const result = await dependencies.expressionEvaluator.evaluate({ hidden }, scope);
23321
23168
  hidden = result.hidden;
@@ -23477,9 +23324,7 @@ class AXPLayoutAdapterFactory {
23477
23324
  }
23478
23325
  const scope = {
23479
23326
  ...rootContext,
23480
- context: {
23481
- eval: (path) => get(rootContext, path),
23482
- },
23327
+ context: this.contextEvalFactory.createScope(rootContext),
23483
23328
  };
23484
23329
  const title = await dependencies.expressionEvaluator.evaluate(titleTemplate, scope);
23485
23330
  return title;
@@ -24288,7 +24133,7 @@ const AXPCrudModifier = {
24288
24133
  queries.list = {
24289
24134
  execute: async (e) => {
24290
24135
  const res = await dataService.query(e);
24291
- // console.log('query', res, ctx.module.get() + '.' + ctx.name.get(), e);
24136
+ //console.log('query', res, ctx.module.get() + '.' + ctx.name.get(), e);
24292
24137
  return res;
24293
24138
  },
24294
24139
  type: AXPEntityQueryType.List,
@@ -24321,6 +24166,68 @@ class AXPEntityCommandSearchDefinitionProvider {
24321
24166
  function moduleNameToI18nScope(moduleName) {
24322
24167
  return moduleName.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');
24323
24168
  }
24169
+ //#region ---- Entity search definition builder ----
24170
+ function buildEntitySearchDefinition(entity, manifestRegistry) {
24171
+ const manifest = manifestRegistry.get(entity.module);
24172
+ const i18nScope = manifest?.i18n ?? moduleNameToI18nScope(entity.module);
24173
+ const searchTitleTemplate = entity.formats.searchResult?.title;
24174
+ const titleContext = buildEntitySearchTitleContext(entity, searchTitleTemplate);
24175
+ return {
24176
+ name: `Module.${entity.module}.${entity.name}`,
24177
+ title: `@${i18nScope}:module.title`,
24178
+ group: `Module.${entity.module}`,
24179
+ icon: entity.icon ?? 'fa-solid fa-objects-column',
24180
+ order: 4,
24181
+ format: {
24182
+ title: searchTitleTemplate,
24183
+ description: entity.formats.searchResult?.description ?? `${entity.module} / ${entity.title}`,
24184
+ id: '{{data.id}}',
24185
+ titleFallbackTemplates: titleContext.fallbackTemplates,
24186
+ titleFallbackFields: titleContext.fallbackFields,
24187
+ },
24188
+ actions: [
24189
+ {
24190
+ name: 'open-entity',
24191
+ type: AXPSystemActionType.View,
24192
+ priority: 'primary',
24193
+ },
24194
+ ],
24195
+ };
24196
+ }
24197
+ //#endregion
24198
+ //#region ---- Lazy resolver ----
24199
+ class AXPEntitySearchDefinitionLazyResolver {
24200
+ constructor() {
24201
+ this.entityResolver = inject(AXPEntityResolver);
24202
+ this.manifestRegistry = inject(AXPModuleManifestRegistry);
24203
+ this.resolved = new Map();
24204
+ }
24205
+ async resolve(definitionName) {
24206
+ const cached = this.resolved.get(definitionName);
24207
+ if (cached) {
24208
+ return cached;
24209
+ }
24210
+ const match = definitionName.match(/^Module\.([^.]+)\.(.+)$/);
24211
+ if (!match) {
24212
+ return null;
24213
+ }
24214
+ const [, moduleName, entityName] = match;
24215
+ await this.manifestRegistry.initialize();
24216
+ const entity = await this.entityResolver.get(moduleName, entityName);
24217
+ if (!entity) {
24218
+ return null;
24219
+ }
24220
+ const definition = buildEntitySearchDefinition(entity, this.manifestRegistry);
24221
+ this.resolved.set(definitionName, definition);
24222
+ return definition;
24223
+ }
24224
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntitySearchDefinitionLazyResolver, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
24225
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntitySearchDefinitionLazyResolver }); }
24226
+ }
24227
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntitySearchDefinitionLazyResolver, decorators: [{
24228
+ type: Injectable
24229
+ }] });
24230
+
24324
24231
  class AXPEntitySearchDefinitionProvider {
24325
24232
  constructor() {
24326
24233
  this.entityRegister = inject(AXPEntityDefinitionRegistryService);
@@ -24328,28 +24235,13 @@ class AXPEntitySearchDefinitionProvider {
24328
24235
  }
24329
24236
  async provide(context) {
24330
24237
  await this.manifestRegistry.initialize();
24331
- this.entityRegister.getAll().forEach((entity) => {
24332
- const manifest = this.manifestRegistry.get(entity.module);
24333
- const i18nScope = manifest?.i18n ?? moduleNameToI18nScope(entity.module);
24334
- const searchTitleTemplate = entity.formats.searchResult?.title;
24335
- const titleContext = buildEntitySearchTitleContext(entity, searchTitleTemplate);
24336
- context.addDefinition(`Module.${entity.module}.${entity.name}`, `@${i18nScope}:module.title`, `Module.${entity.module}`, entity.icon ?? 'fa-solid fa-objects-column', 4, {
24337
- actions: [
24338
- {
24339
- name: 'open-entity',
24340
- type: 'view',
24341
- priority: 'primary',
24342
- },
24343
- ],
24344
- format: {
24345
- title: searchTitleTemplate,
24346
- description: (entity.formats.searchResult?.description) ?? `${entity.module} / ${entity.title}`,
24347
- id: '{{data.id}}',
24348
- titleFallbackTemplates: titleContext.fallbackTemplates,
24349
- titleFallbackFields: titleContext.fallbackFields,
24350
- },
24238
+ for (const entity of this.entityRegister.getAll()) {
24239
+ const definition = buildEntitySearchDefinition(entity, this.manifestRegistry);
24240
+ context.addDefinition(definition.name, definition.title, definition.group, definition.icon, definition.order, {
24241
+ actions: definition.actions,
24242
+ format: definition.format,
24351
24243
  });
24352
- });
24244
+ }
24353
24245
  }
24354
24246
  }
24355
24247
 
@@ -24455,9 +24347,9 @@ class AXPMiddlewareEntityStorageService extends AXPEntityStorageService {
24455
24347
  ...init,
24456
24348
  };
24457
24349
  }
24458
- async initial(entityName, collection, options) {
24350
+ async initial(entityName, collection) {
24459
24351
  const ctx = this.createCtx('initial', entityName, { data: collection });
24460
- return this.run(ctx, () => this.backend.initial(ctx.entityName, ctx.data, options));
24352
+ return this.run(ctx, () => this.backend.initial(ctx.entityName, ctx.data));
24461
24353
  }
24462
24354
  async getOne(entityName, id) {
24463
24355
  const key = getDedupKey('getOne', entityName, { id });
@@ -24741,6 +24633,9 @@ class AXPQuickEntityModifyPopupAction extends AXPWorkflowAction {
24741
24633
  this.popupService = inject(AXPopupService);
24742
24634
  this.platform = inject(AXPlatform);
24743
24635
  this.translateService = inject(AXTranslationService);
24636
+ this.formatService = inject(AXFormatService);
24637
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
24638
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
24744
24639
  this.entityRegistery = inject(AXPEntityDefinitionRegistryService);
24745
24640
  this.config = inject(AXP_ENTITY_CONFIG_TOKEN);
24746
24641
  this.factory = inject(AXPEntityMasterUpdateViewModelFactory);
@@ -24750,10 +24645,8 @@ class AXPQuickEntityModifyPopupAction extends AXPWorkflowAction {
24750
24645
  const data = context.getVariable('data');
24751
24646
  const entityRef = await this.entityRegistery.resolve(moduleName, entityName);
24752
24647
  const { parentKey } = entityRef;
24753
- console.log(data);
24754
24648
  const { id } = data;
24755
- const { interfaces, title } = entityRef;
24756
- const properties = interfaces?.master?.update?.properties?.map((p) => p.name) || [];
24649
+ const properties = entityRef.interfaces?.master?.update?.properties?.map((p) => p.name) || [];
24757
24650
  const vm = await this.factory.create(moduleName, entityName, id, properties);
24758
24651
  const options = context.getVariable('options');
24759
24652
  const decoration = options?.['decoration'];
@@ -24763,12 +24656,11 @@ class AXPQuickEntityModifyPopupAction extends AXPWorkflowAction {
24763
24656
  if (parentKey) {
24764
24657
  context.setVariable('parentKey', parentKey);
24765
24658
  }
24766
- console.log(`${this.translateService.translateSync('entity.modify')}`);
24767
24659
  const com = await this.config.viewers.master.modify();
24768
24660
  const popup = await this.popupService.open(com, {
24769
24661
  title: headerTitle
24770
24662
  ? headerTitle
24771
- : `${this.translateService.translateSync('@general:actions.modify.title')} ${this.translateService.translateSync(entityRef.formats.individual)}`,
24663
+ : await resolveEntityModifyPopupTitle(entityRef, vm.context(), this.translateService, this.formatService, this.expressionEvaluator, this.contextEvalFactory),
24772
24664
  size: this.platform.is('Mobile') || this.platform.is('SM') ? 'full' : size ? size : 'md',
24773
24665
  data: {
24774
24666
  vm,
@@ -25031,6 +24923,7 @@ function routesFacory() {
25031
24923
  return config.viewers.root();
25032
24924
  },
25033
24925
  canActivate: [...AXP_PROTECTED_ROUTE_GUARDS],
24926
+ data: { rootLayout: true },
25034
24927
  children: [
25035
24928
  {
25036
24929
  path: ':module',
@@ -25075,7 +24968,7 @@ function routesFacory() {
25075
24968
  const refreshChanged = from.queryParams['_ts'] !== to.queryParams['_ts'];
25076
24969
  return entityChanged || idChanged || refreshChanged;
25077
24970
  },
25078
- data: { reuse: false },
24971
+ data: { reuse: 'queryParamsChange' },
25079
24972
  },
25080
24973
  {
25081
24974
  path: 'e/:entity/:id',
@@ -25108,6 +25001,15 @@ class AXPEntityModule {
25108
25001
  AXPAttachmentsPluginModule, i1$3.AXPWorkflowModule, AXPWidgetCoreModule,
25109
25002
  LayoutBuilderModule] }); }
25110
25003
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityModule, providers: [
25004
+ {
25005
+ provide: AXP_REPEATER_ENTITY_BY_KEY_LOOKUP,
25006
+ useFactory: () => {
25007
+ const entityService = inject(AXPEntityService);
25008
+ return {
25009
+ byKey: (entityKey, id) => entityService.withEntity(entityKey).data().byKey(id),
25010
+ };
25011
+ },
25012
+ },
25111
25013
  { provide: AXP_WIDGET_DEFINITION_PROVIDER, useClass: AXPEntityWidgetsProvider, multi: true },
25112
25014
  {
25113
25015
  provide: ROUTES,
@@ -25124,6 +25026,10 @@ class AXPEntityModule {
25124
25026
  useClass: AXPEntityCommandSearchDefinitionProvider,
25125
25027
  multi: true,
25126
25028
  },
25029
+ {
25030
+ provide: AXP_SEARCH_DEFINITION_LAZY_RESOLVER,
25031
+ useClass: AXPEntitySearchDefinitionLazyResolver,
25032
+ },
25127
25033
  // Bind the middleware wrapper as the public storage service
25128
25034
  { provide: AXPEntityStorageService, useClass: AXPMiddlewareEntityStorageService },
25129
25035
  {
@@ -25295,6 +25201,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
25295
25201
  exports: [],
25296
25202
  declarations: [],
25297
25203
  providers: [
25204
+ {
25205
+ provide: AXP_REPEATER_ENTITY_BY_KEY_LOOKUP,
25206
+ useFactory: () => {
25207
+ const entityService = inject(AXPEntityService);
25208
+ return {
25209
+ byKey: (entityKey, id) => entityService.withEntity(entityKey).data().byKey(id),
25210
+ };
25211
+ },
25212
+ },
25298
25213
  { provide: AXP_WIDGET_DEFINITION_PROVIDER, useClass: AXPEntityWidgetsProvider, multi: true },
25299
25214
  {
25300
25215
  provide: ROUTES,
@@ -25311,6 +25226,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
25311
25226
  useClass: AXPEntityCommandSearchDefinitionProvider,
25312
25227
  multi: true,
25313
25228
  },
25229
+ {
25230
+ provide: AXP_SEARCH_DEFINITION_LAZY_RESOLVER,
25231
+ useClass: AXPEntitySearchDefinitionLazyResolver,
25232
+ },
25314
25233
  // Bind the middleware wrapper as the public storage service
25315
25234
  { provide: AXPEntityStorageService, useClass: AXPMiddlewareEntityStorageService },
25316
25235
  {
@@ -25618,5 +25537,5 @@ var getEntityDetails_query = /*#__PURE__*/Object.freeze({
25618
25537
  * Generated bundle index. Do not edit.
25619
25538
  */
25620
25539
 
25621
- 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, AXPEntityDataSourceKeys, 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, collectNestedCreateHiddenProperties, collectNestedFieldPathsFromEntityColumns, collectQuickSearchPathsFromSingleEntityDefinition, columnOrderingMiddleware, columnOrderingMiddlewareProvider, columnWidthMiddleware, columnWidthMiddlewareProvider, commandMessageTextForError, committedAttachments, computeEntityAggregates, createColumnOrderingMiddlewareProvider, createLayoutOrderingMiddlewareProvider, createModifierContext, defaultCardLayoutMiddleware, defaultCardLayoutMiddlewareProvider, defaultMultiLanguageMiddleware, defaultMultiLanguageMiddlewareProvider, detectEntityChanges, ensureLayoutPropertyView, ensureLayoutSection, ensureListActions, entityDetailsCreateActions, entityDetailsCreateActionsDeferredParent, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsNewEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterEditAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware, filterSortEntityRows, findEntityListRowDataInTree, fingerprintAttachmentItem, fingerprintAttachments, formatLookupItemDisplay, getDataSourcePageIndex, getEntityListRowId, getMasterInterfacePropertySortKey, getRecordWorkflowCorrelationId, getRecordWorkflowInstanceId, hasFileUploaderTitleOrDescriptionFields, isAXPMiddlewareAbortError, isAttachmentListEntry, isCategoryEntity, isCategoryFilter, isFileListItem, isFileUploaderEditDialogAuto, isLegacyEntityDataSelectorOptions, layoutOrderingMiddlewareFactory, layoutOrderingMiddlewareProvider, mapEntityStorageErrorToCommandResult, mapLegacyEntityDataSelectorOptions, mergeForeignKeyFieldIntoCreateActions, normalizeEntityDataSelectorOptions, normalizeEntityFieldToFileList, normalizeEntityListPersistenceMode, normalizeListPaging, persistedAttachments, provideEntity, resolveEntityPluginDetailPageOrder, resolveFileUploaderEditDialog, resolveFileUploaderEntityScope, resolveLookupDisplayField, resolveLookupDisplayTemplate, restoreEntityListExpandedRows, runEntityQuery, searchResultDescriptionMiddleware, searchResultDescriptionMiddlewareProvider, shouldLoadEntityListStateFromStorage, shouldResetEntityListStateOnRouteEntry };
25540
+ 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, 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, 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, canPersistEntityListState, cloneLayoutArrays, 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, 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 };
25622
25541
  //# sourceMappingURL=acorex-platform-layout-entity.mjs.map