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

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 (81) hide show
  1. package/fesm2022/acorex-platform-auth.mjs +9 -3
  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-DilV4dql.mjs} +16 -3
  4. package/fesm2022/acorex-platform-common-common-settings.provider-DilV4dql.mjs.map +1 -0
  5. package/fesm2022/acorex-platform-common.mjs +3426 -2488
  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 +826 -152
  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 +98 -189
  16. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  17. package/fesm2022/{acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs → acorex-platform-layout-components-binding-expression-editor-popup.component-RttFwaw9.mjs} +17 -4
  18. package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-RttFwaw9.mjs.map +1 -0
  19. package/fesm2022/acorex-platform-layout-components.mjs +181 -46
  20. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  21. package/fesm2022/acorex-platform-layout-designer.mjs +7 -6
  22. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  23. package/fesm2022/acorex-platform-layout-entity-attachments-page.component-CwG6n_Yb.mjs.map +1 -1
  24. package/fesm2022/acorex-platform-layout-entity-contracts.mjs +1208 -0
  25. package/fesm2022/acorex-platform-layout-entity-contracts.mjs.map +1 -0
  26. package/fesm2022/acorex-platform-layout-entity-file-list-popup.component--IeMZLIr.mjs.map +1 -1
  27. package/fesm2022/acorex-platform-layout-entity.mjs +1080 -889
  28. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  29. package/fesm2022/acorex-platform-layout-views.mjs +1150 -247
  30. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  31. package/fesm2022/acorex-platform-layout-widget-core.mjs +388 -207
  32. package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
  33. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs +513 -0
  34. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs.map +1 -0
  35. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-CZc2zFlg.mjs} +4 -4
  36. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-CZc2zFlg.mjs.map +1 -0
  37. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-XWRUVoL4.mjs} +2 -2
  38. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs.map → acorex-platform-layout-widgets-tabular-data-view-popup.component-XWRUVoL4.mjs.map} +1 -1
  39. package/fesm2022/acorex-platform-layout-widgets.mjs +1541 -394
  40. package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
  41. package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
  42. 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
  43. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs.map +1 -0
  44. package/fesm2022/acorex-platform-themes-default.mjs +956 -115
  45. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  46. package/fesm2022/{acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs → acorex-platform-themes-shared-settings.provider-UyKdkeyk.mjs} +50 -3
  47. package/fesm2022/acorex-platform-themes-shared-settings.provider-UyKdkeyk.mjs.map +1 -0
  48. package/fesm2022/acorex-platform-themes-shared.mjs +104 -24
  49. package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
  50. package/fesm2022/acorex-platform-workflow.mjs +6 -8
  51. package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
  52. package/package.json +9 -5
  53. package/types/acorex-platform-auth.d.ts +3 -1
  54. package/types/acorex-platform-common.d.ts +655 -1268
  55. package/types/acorex-platform-contracts.d.ts +1791 -260
  56. package/types/acorex-platform-core.d.ts +2302 -2800
  57. package/types/acorex-platform-domain-contracts.d.ts +416 -0
  58. package/types/acorex-platform-domain.d.ts +4 -415
  59. package/types/acorex-platform-layout-builder.d.ts +11 -20
  60. package/types/acorex-platform-layout-components.d.ts +29 -5
  61. package/types/acorex-platform-layout-designer.d.ts +2 -1
  62. package/types/acorex-platform-layout-entity-contracts.d.ts +889 -0
  63. package/types/acorex-platform-layout-entity.d.ts +143 -275
  64. package/types/acorex-platform-layout-views.d.ts +147 -31
  65. package/types/acorex-platform-layout-widget-core.d.ts +74 -14
  66. package/types/acorex-platform-layout-widgets.d.ts +136 -38
  67. package/types/acorex-platform-runtime.d.ts +1 -1
  68. package/types/acorex-platform-themes-default.d.ts +227 -73
  69. package/types/acorex-platform-themes-shared.d.ts +4 -0
  70. package/types/acorex-platform-workflow.d.ts +5 -18
  71. package/fesm2022/acorex-platform-common-common-settings.provider-Ytey9uhY.mjs.map +0 -1
  72. package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs.map +0 -1
  73. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs +0 -116
  74. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs.map +0 -1
  75. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs.map +0 -1
  76. package/fesm2022/acorex-platform-native.mjs +0 -155
  77. package/fesm2022/acorex-platform-native.mjs.map +0 -1
  78. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs.map +0 -1
  79. package/fesm2022/acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs.map +0 -1
  80. package/native/README.md +0 -4
  81. package/types/acorex-platform-native.d.ts +0 -28
@@ -1,42 +1,47 @@
1
+ import { mergeForeignKeyFieldIntoCreateActions, collectNestedCreateHiddenProperties, normalizeEntityDisplayTemplate, sanitizeResolvedEntityDisplayTitle, isUnresolvedEntityDisplayTemplate, AXPEntityDataSourceKeys, AXPEntityEventsKeys, collectEntityListSortableFields, collectEntityListFilterDefinitions, parseDottedFieldPath, ENTITY_ROW_POPUP_TITLE_OPTION, buildEntitySearchTitleContext } from '@acorex/platform/layout/entity-contracts';
2
+ export * from '@acorex/platform/layout/entity-contracts';
3
+ 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';
1
4
  import { AXToastService } from '@acorex/components/toast';
2
5
  import * as i3$1 from '@acorex/core/translation';
3
- import { AXTranslationService, AXTranslationModule, resolveMultiLanguageString, translateSync } from '@acorex/core/translation';
6
+ import { AXTranslationService, resolveMultiLanguageString, AXTranslationModule, translateSync } from '@acorex/core/translation';
4
7
  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';
8
+ import { AXPNotFoundError, AXPEntityCommandScope, axpNavigateAppPath, AXPSettingsService, AXPCommonSettings, resolveEntityCreateListBehavior, AXPRefreshEvent, resolveEntityModifyPopupTitle, resolveSearchableText, evaluateEntityDisplayTemplate, AXPFilterOperatorMiddlewareService, isCardFieldBadgeDisplay, resolveCardFieldBadgeColor, getEntityInfo, resolveEnabledMasterListLayouts, resolveDefaultMasterListLayout, AXPReloadEvent, axpRedirectToNotFound, AXP_ENTITY_DELETED_WORKFLOW_EVENT_TYPE, 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';
9
+ import * as i1$3 from '@acorex/platform/workflow';
10
+ import { AXPWorkflowEventService, AXPWorkflowService, ofType, createWorkFlowEvent, AXPWorkflowAction, AXPWorkflowModule } from '@acorex/platform/workflow';
6
11
  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';
12
+ 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';
13
+ import { cloneDeep, merge, get, castArray, set, orderBy, isNil, isEmpty, isEqual as isEqual$1, isObjectLike, isArray, has, isString } from 'lodash-es';
8
14
  import { Subject, filter, takeUntil } from 'rxjs';
9
15
  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';
16
+ import { AXPWidgetsCatalog, AXPPlatformScope, AXPDataGenerator, AXPSystemActionType } from '@acorex/platform/contracts';
17
+ import { AXPDeviceService, AXPExpressionEvaluatorService, AXPContextEvalFactory, AXPBroadcastEventService, applyFilterArray, applySortArray, resolveActionLook, AXPDistributedEventListenerService, AXHighlightService, extractValue, setSmart, getChangedPaths, AXPContextStore, isSelectionValueEqual, AXPDebugService, FORM_DIRTY_TRACE_NS, objectKeyValueTransforms, setupPopupFooterKeyboardShortcuts, AXPHookService, AXPComponentSlotModule, AXPColumnWidthService, AXPModuleManifestRegistry, defaultColumnWidthProvider, AXP_COLUMN_WIDTH_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXPModuleManifestsDataSourceDefinition } from '@acorex/platform/core';
14
18
  import { transform, isEqual } from 'lodash';
15
19
  import { AXPSessionService, AXPPermissionDefinitionsDataSourceDefinition } from '@acorex/platform/auth';
16
20
  import { Router, NavigationStart, ActivatedRoute, RouterModule, ROUTES } from '@angular/router';
17
21
  import { defineCommand, AXP_COMMAND_DEFINITION_CATEGORY_ENTITY, AXPCommandService, AXPQueryService, AXPQueryExecutor, AXPCommandExecutor, provideCommandSetups, provideQuerySetups, AXPCommandRegistry, AXPQueryRegistry } from '@acorex/platform/runtime';
22
+ import { AXFormatService } from '@acorex/core/format';
18
23
  import * as i1 from '@acorex/components/button';
19
24
  import { AXButtonModule } from '@acorex/components/button';
20
25
  import * as i3 from '@acorex/components/skeleton';
21
26
  import { AXSkeletonModule } from '@acorex/components/skeleton';
22
- import { AXFormatService } from '@acorex/core/format';
27
+ import * as i2 from '@acorex/platform/layout/widget-core';
28
+ 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
29
  import * as i5 from '@angular/common';
24
30
  import { CommonModule, DOCUMENT, AsyncPipe, NgClass } from '@angular/common';
25
31
  import { AXOverlayService } from '@acorex/cdk/overlay';
26
32
  import { AXLocaleService } from '@acorex/core/locale';
27
33
  import { AXPlatform } from '@acorex/core/platform';
28
34
  import { AXPThemeLayoutBlockComponent, AXPPreloadFiltersComponent, AXP_PAGE_COMPONENT_PROVIDER, AXPStateMessageComponent, AXPColumnItemListComponent, AXPDataSelectorService, AXPPageComponentRegistryService } from '@acorex/platform/layout/components';
29
- import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageComponentRendererDirective, AXPPageComponentInstanceRegistryService, axpDetailsViewCanDeactivateGuard } from '@acorex/platform/layout/views';
35
+ import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageComponentRendererDirective, AXPPageComponentInstanceRegistryService, AXP_LAYOUT_DETAILS_VIEW_ADAPTER_LOADER, axpDetailsViewCanDeactivateGuard } from '@acorex/platform/layout/views';
30
36
  import { AXDataSource } from '@acorex/cdk/common';
31
37
  import { AXP_ENTITY_CRUD_SETUP } from '@acorex/platform/domain';
32
38
  export { AXP_ENTITY_DEFINITION_CRUD_SERVICE } from '@acorex/platform/domain';
33
- import * as i1$3 from '@acorex/platform/workflow';
34
- import { AXPWorkflowService, ofType, createWorkFlowEvent, AXPWorkflowAction, AXPWorkflowEventService, AXPWorkflowModule } from '@acorex/platform/workflow';
35
39
  import { AXPLayoutThemeService } from '@acorex/platform/themes/shared';
36
40
  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) {
@@ -2532,6 +2302,7 @@ class AXPCreateEntityCommand {
2532
2302
  this.translationService = inject(AXTranslationService);
2533
2303
  this.settingsService = inject(AXPSettingsService);
2534
2304
  this.openEntityDetailsCommand = inject(AXPOpenEntityDetailsCommand);
2305
+ this.workflowEventService = inject(AXPWorkflowEventService);
2535
2306
  this.context = {};
2536
2307
  }
2537
2308
  async execute(input) {
@@ -2588,8 +2359,7 @@ class AXPCreateEntityCommand {
2588
2359
  }
2589
2360
  const createFn = entityRef.commands?.create?.execute;
2590
2361
  const updateFn = entityRef.commands?.update?.execute;
2591
- const context = dialogRef.context();
2592
- console.log('context', context);
2362
+ const context = merge({}, data, dialogRef.context());
2593
2363
  const hasPersistedId = hasPersistedRootId(context);
2594
2364
  const persistFn = hasPersistedId ? updateFn : createFn;
2595
2365
  const missingPersistHandlerMsg = hasPersistedId
@@ -2647,13 +2417,24 @@ class AXPCreateEntityCommand {
2647
2417
  .show();
2648
2418
  const commandResult = result;
2649
2419
  const redirectOption = options?.process?.redirect;
2650
- const shouldRedirect = redirectOption !== undefined
2651
- ? redirectOption
2652
- : await this.settingsService.get(AXPCommonSettings.RedirectToDetailsAfterCreate);
2653
- if (commandResult.success && shouldRedirect && commandResult.data) {
2420
+ const { shouldRedirect, shouldHighlight } = await resolveEntityCreateListBehavior(this.settingsService, {
2421
+ redirect: redirectOption,
2422
+ });
2423
+ if (commandResult.success && commandResult.data) {
2654
2424
  const createdItem = commandResult.data?.item ?? commandResult.data;
2655
- const createdId = createdItem?.id;
2656
- if (createdId != null) {
2425
+ const createdId = createdItem?.id ?? createdItem?._id;
2426
+ const refreshMeta = { resetPagination: true };
2427
+ if (createdId != null && shouldHighlight) {
2428
+ refreshMeta['highlightRowId'] = createdId;
2429
+ }
2430
+ if (entityRef.parentKey && createdItem?.[entityRef.parentKey]) {
2431
+ refreshMeta['refreshTargetId'] = createdItem[entityRef.parentKey];
2432
+ }
2433
+ this.workflowEventService.dispatch(AXPRefreshEvent({
2434
+ entity: `${moduleName}.${entityName}`,
2435
+ meta: refreshMeta,
2436
+ }));
2437
+ if (shouldRedirect && createdId != null) {
2657
2438
  await this.openEntityDetailsCommand.execute({
2658
2439
  entity: `${moduleName}.${entityName}`,
2659
2440
  data: { id: String(createdId) },
@@ -2744,6 +2525,9 @@ class AXPUpdateEntityCommand {
2744
2525
  this.entityService = inject(AXPEntityDefinitionRegistryService);
2745
2526
  this.toastService = inject(AXToastService);
2746
2527
  this.translationService = inject(AXTranslationService);
2528
+ this.formatService = inject(AXFormatService);
2529
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
2530
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
2747
2531
  this.eventService = inject(AXPBroadcastEventService);
2748
2532
  }
2749
2533
  //#endregion
@@ -2751,7 +2535,7 @@ class AXPUpdateEntityCommand {
2751
2535
  async execute(input) {
2752
2536
  const enableOperationToasts = await this.settingsService.get(AXPCommonSettings.EnableOperationToasts);
2753
2537
  const dialogSize = input['dialogSize'];
2754
- const { entity, entityInfo, data, options } = input.__context__;
2538
+ const { entity, data, options } = input.__context__;
2755
2539
  const excludeProperties = options?.excludeProperties;
2756
2540
  const includeProperties = options?.includeProperties;
2757
2541
  const decoration = options?.['decoration'];
@@ -2790,10 +2574,17 @@ class AXPUpdateEntityCommand {
2790
2574
  if (headerTitle) {
2791
2575
  chain = chain.title(headerTitle);
2792
2576
  }
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}`);
2577
+ else {
2578
+ let recordData = {};
2579
+ const recordId = typeof data === 'string' ? data : (data?.id ?? data?._id);
2580
+ if (recordId) {
2581
+ recordData = await this.entityForm.getRecordById(`${moduleName}.${entityName}`, String(recordId));
2582
+ }
2583
+ else if (typeof data === 'object' && data != null) {
2584
+ recordData = data;
2585
+ }
2586
+ const title = await resolveEntityModifyPopupTitle(entityRef, recordData, this.translationService, this.formatService, this.expressionEvaluator, this.contextEvalFactory, '@general:actions.edit.title');
2587
+ chain = chain.title(title);
2797
2588
  }
2798
2589
  const finalSize = layoutSize || dialogSize;
2799
2590
  if (finalSize) {
@@ -2887,15 +2678,19 @@ var updateEntity_command = /*#__PURE__*/Object.freeze({
2887
2678
 
2888
2679
  class AXPViewEntityDetailsCommand {
2889
2680
  constructor() {
2890
- //#region ---- Services & Dependencies ----
2681
+ //#region ---- Services & Dependencies ----
2891
2682
  this.entityForm = inject(AXPEntityFormBuilderService);
2892
2683
  this.entityService = inject(AXPEntityDefinitionRegistryService);
2893
2684
  this.translationService = inject(AXTranslationService);
2685
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
2686
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
2894
2687
  }
2895
2688
  //#endregion
2896
- //#region ---- Command Execution ----
2689
+ //#region ---- Command Execution ----
2897
2690
  async execute(input) {
2898
- const excludeProperties = input['excludeProperties'];
2691
+ const excludeProperties = input['excludeProperties'] ??
2692
+ input?.options?.excludeProperties ??
2693
+ input?.__context__?.options?.excludeProperties;
2899
2694
  const { entity, entityInfo, data } = input.__context__;
2900
2695
  const [moduleName, entityName] = (entity || '').split('.');
2901
2696
  if (!moduleName || !entityName) {
@@ -2906,10 +2701,9 @@ class AXPViewEntityDetailsCommand {
2906
2701
  },
2907
2702
  };
2908
2703
  }
2909
- await this.entityService.resolve(moduleName, entityName);
2704
+ const entityDef = await this.entityService.resolve(moduleName, entityName);
2910
2705
  let dialogRef;
2911
2706
  try {
2912
- // Validate data type
2913
2707
  if (!data || (typeof data !== 'string' && typeof data !== 'object')) {
2914
2708
  return {
2915
2709
  success: false,
@@ -2918,22 +2712,18 @@ class AXPViewEntityDetailsCommand {
2918
2712
  },
2919
2713
  };
2920
2714
  }
2921
- // Pass data directly to single() - it handles string | object internally
2922
2715
  let chain = this.entityForm.entity(`${moduleName}.${entityName}`).single(data);
2923
2716
  if (excludeProperties && excludeProperties.length > 0) {
2924
2717
  chain = chain.exclude(...excludeProperties);
2925
2718
  }
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}`);
2719
+ const dialogTitle = await this.resolveDialogTitle(entityDef, data);
2720
+ if (dialogTitle) {
2721
+ chain = chain.title(dialogTitle);
2930
2722
  }
2931
2723
  chain = chain.actions((actions) => {
2932
2724
  actions.submit('@general:actions.ok.title');
2933
2725
  });
2934
2726
  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
2727
  dialogRef.close();
2938
2728
  return {
2939
2729
  success: true,
@@ -2953,11 +2743,62 @@ class AXPViewEntityDetailsCommand {
2953
2743
  };
2954
2744
  }
2955
2745
  finally {
2956
- if (dialogRef) {
2746
+ if (dialogRef && typeof dialogRef === 'object' && dialogRef !== null && 'setLoading' in dialogRef) {
2957
2747
  dialogRef.setLoading(false);
2958
2748
  }
2959
2749
  }
2960
2750
  }
2751
+ //#endregion
2752
+ //#region ---- Title resolution ----
2753
+ async resolveDialogTitle(entityDef, data) {
2754
+ const titleTemplate = entityDef.interfaces?.master?.single?.title ??
2755
+ entityDef.formats?.searchResult?.title ??
2756
+ entityDef.formats?.individual;
2757
+ if (!titleTemplate || typeof titleTemplate !== 'string') {
2758
+ return this.translationService.translateAsync('@general:actions.detail.title');
2759
+ }
2760
+ if (!titleTemplate.includes('{{')) {
2761
+ const translated = await this.translationService.translateAsync(titleTemplate);
2762
+ return resolveMultiLanguageString(translated, this.translationService.getActiveLang()).trim() || translated;
2763
+ }
2764
+ const recordContext = await this.loadRecordContext(`${entityDef.module}.${entityDef.name}`, data);
2765
+ const scope = {
2766
+ context: this.contextEvalFactory.createScope(recordContext),
2767
+ };
2768
+ const evaluated = await this.expressionEvaluator.evaluate(titleTemplate, scope);
2769
+ const locale = this.translationService.getActiveLang();
2770
+ const text = resolveMultiLanguageString(evaluated, locale).trim() || String(evaluated ?? '').trim();
2771
+ if (text) {
2772
+ return text;
2773
+ }
2774
+ return this.translationService.translateAsync('@general:actions.detail.title');
2775
+ }
2776
+ async loadRecordContext(entityFullName, data) {
2777
+ if (typeof data === 'object' && data !== null && !Array.isArray(data)) {
2778
+ const hasNestedFields = get(data, 'subject.title') != null ||
2779
+ get(data, 'recordType.title') != null ||
2780
+ get(data, 'occurredDate') != null;
2781
+ if (hasNestedFields) {
2782
+ return data;
2783
+ }
2784
+ }
2785
+ const recordId = typeof data === 'string' ? data : String(get(data, 'id') ?? '');
2786
+ if (!recordId) {
2787
+ return typeof data === 'object' && data !== null ? data : {};
2788
+ }
2789
+ try {
2790
+ const [moduleName, entityName] = entityFullName.split('.');
2791
+ const entity = await this.entityService.resolve(moduleName, entityName);
2792
+ const byKeyFn = entity?.queries?.byKey?.execute;
2793
+ if (typeof byKeyFn === 'function') {
2794
+ return (await byKeyFn(recordId)) ?? {};
2795
+ }
2796
+ }
2797
+ catch {
2798
+ // Fall back to list row payload below.
2799
+ }
2800
+ return typeof data === 'object' && data !== null ? data : {};
2801
+ }
2961
2802
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPViewEntityDetailsCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2962
2803
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPViewEntityDetailsCommand, providedIn: 'root' }); }
2963
2804
  }
@@ -2973,55 +2814,39 @@ var viewEntityDetails_command = /*#__PURE__*/Object.freeze({
2973
2814
  AXPViewEntityDetailsCommand: AXPViewEntityDetailsCommand
2974
2815
  });
2975
2816
 
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;
2817
+ /** Common keys on denormalized expose stubs (e.g. `{ id, displayName }` from lookup expose). */
2818
+ const LOOKUP_EXPOSE_STUB_DISPLAY_FIELDS = ['displayName', 'title', 'name', 'fullName', 'code'];
2819
+ function resolveLookupItemFieldValue(item, field) {
2820
+ const direct = get(item, field);
2821
+ if (direct != null && direct !== '') {
2822
+ return direct;
2823
+ }
2824
+ if (!field.includes('.')) {
2825
+ return direct;
2826
+ }
2827
+ for (const fallback of LOOKUP_EXPOSE_STUB_DISPLAY_FIELDS) {
2828
+ const candidate = get(item, fallback);
2829
+ if (candidate != null && candidate !== '') {
2830
+ return candidate;
2831
+ }
2832
+ }
2833
+ return direct;
3005
2834
  }
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 {};
2835
+ function formatLookupFieldValue(raw, locale, translationService, resolveMultiLanguage) {
2836
+ if (raw == null || raw === '') {
2837
+ return '';
3011
2838
  }
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
- };
2839
+ if (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') {
2840
+ return String(raw);
2841
+ }
2842
+ if (typeof raw === 'object' && !Array.isArray(raw)) {
2843
+ if (resolveMultiLanguage) {
2844
+ return resolveMultiLanguage(raw);
2845
+ }
2846
+ return resolveSearchableText(raw, locale, translationService);
2847
+ }
2848
+ return String(raw);
3020
2849
  }
3021
-
3022
- //#region ---- Contracts barrel ----
3023
- //#endregion
3024
-
3025
2850
  //#region ---- Template resolution ----
3026
2851
  /**
3027
2852
  * Resolves the display template for a lookup item.
@@ -3063,9 +2888,9 @@ function resolveLookupDisplayField(entity, options) {
3063
2888
  return found ?? 'title';
3064
2889
  }
3065
2890
  /**
3066
- * Formats a lookup row for display using template and/or field resolution.
2891
+ * Formats a lookup row for display using template and/or field resolution (display tier).
3067
2892
  */
3068
- function formatLookupItemDisplay(item, entity, options, formatService, resolveMultiLanguage) {
2893
+ async function formatLookupItemDisplayAsync(item, entity, options, formatService, displayDeps, resolveMultiLanguage) {
3069
2894
  if (item == null) {
3070
2895
  return '';
3071
2896
  }
@@ -3080,6 +2905,45 @@ function formatLookupItemDisplay(item, entity, options, formatService, resolveMu
3080
2905
  }
3081
2906
  const template = resolveLookupDisplayTemplate(entity, options);
3082
2907
  if (template) {
2908
+ if (template.includes('{{') || template.includes('context.eval')) {
2909
+ const evaluated = await evaluateEntityDisplayTemplate(template, item, displayDeps.expressionEvaluator, displayDeps.locale, displayDeps.translationService, displayDeps.contextEvalFactory);
2910
+ const text = sanitizeResolvedEntityDisplayTitle(resolveSearchableText(evaluated, displayDeps.locale, displayDeps.translationService));
2911
+ if (text && !isUnresolvedEntityDisplayTemplate(text)) {
2912
+ return text;
2913
+ }
2914
+ }
2915
+ else {
2916
+ const formatted = formatService.format(template, 'string', item);
2917
+ if (formatted) {
2918
+ const text = String(formatted);
2919
+ if (!isUnresolvedEntityDisplayTemplate(text)) {
2920
+ return text;
2921
+ }
2922
+ }
2923
+ }
2924
+ }
2925
+ const field = resolveLookupDisplayField(entity, options);
2926
+ const raw = typeof item === 'object' && item != null ? resolveLookupItemFieldValue(item, field) : undefined;
2927
+ return formatLookupFieldValue(raw, displayDeps.locale, displayDeps.translationService, resolveMultiLanguage);
2928
+ }
2929
+ /**
2930
+ * @deprecated Prefer {@link formatLookupItemDisplayAsync} for expression templates with `context.eval`.
2931
+ */
2932
+ function formatLookupItemDisplay(item, entity, options, formatService, resolveMultiLanguage) {
2933
+ if (item == null) {
2934
+ return '';
2935
+ }
2936
+ if (typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean') {
2937
+ return String(item);
2938
+ }
2939
+ if (typeof item !== 'object') {
2940
+ return '';
2941
+ }
2942
+ if (options.isMultiLanguage?.(item) && resolveMultiLanguage) {
2943
+ return resolveMultiLanguage(item);
2944
+ }
2945
+ const template = resolveLookupDisplayTemplate(entity, options);
2946
+ if (template && !template.includes('context.eval') && !template.includes('{{')) {
3083
2947
  const formatted = formatService.format(template, 'string', item);
3084
2948
  if (formatted) {
3085
2949
  const text = String(formatted);
@@ -3089,8 +2953,8 @@ function formatLookupItemDisplay(item, entity, options, formatService, resolveMu
3089
2953
  }
3090
2954
  }
3091
2955
  const field = resolveLookupDisplayField(entity, options);
3092
- const raw = get(item, field);
3093
- if (raw == null) {
2956
+ const raw = typeof item === 'object' && item != null ? resolveLookupItemFieldValue(item, field) : undefined;
2957
+ if (raw == null || raw === '') {
3094
2958
  return '';
3095
2959
  }
3096
2960
  if (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') {
@@ -3113,6 +2977,8 @@ class AXPEntityDetailPopoverComponent {
3113
2977
  this.queryService = inject(AXPQueryService);
3114
2978
  this.formatService = inject(AXFormatService);
3115
2979
  this.translation = inject(AXTranslationService);
2980
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
2981
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
3116
2982
  this.changeDetectorRef = inject(ChangeDetectorRef);
3117
2983
  //#endregion
3118
2984
  //#region ---- Inputs ----
@@ -3128,31 +2994,10 @@ class AXPEntityDetailPopoverComponent {
3128
2994
  //#region ---- Signals ----
3129
2995
  this.entityDetails = signal(null, ...(ngDevMode ? [{ debugName: "entityDetails" }] : /* istanbul ignore next */ []));
3130
2996
  this.isLoadingDetails = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingDetails" }] : /* istanbul ignore next */ []));
2997
+ this.headerTitleVersion = 0;
3131
2998
  /** Placeholder rows for the loading skeleton (matches typical property count). */
3132
2999
  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 */ []));
3000
+ this.headerTitle = signal('', ...(ngDevMode ? [{ debugName: "headerTitle" }] : /* istanbul ignore next */ []));
3156
3001
  /**
3157
3002
  * Stable list of property widgets for the template. Must be a signal (computed), not a method:
3158
3003
  * calling a method from the template rebuilds nodes every CD cycle and can make the widget renderer loop.
@@ -3165,6 +3010,18 @@ class AXPEntityDetailPopoverComponent {
3165
3010
  return [];
3166
3011
  return this.buildEntityPropertiesWithWidgets(data, entityDefinition, this.textField(), this.valueField());
3167
3012
  }, ...(ngDevMode ? [{ debugName: "entityPropertiesWithWidgets" }] : /* istanbul ignore next */ []));
3013
+ effect(() => {
3014
+ void this.translation.getActiveLang();
3015
+ const details = this.entityDetails();
3016
+ const preset = this.displayTitle();
3017
+ const fallbackItem = this.item();
3018
+ const version = ++this.headerTitleVersion;
3019
+ void this.resolveHeaderTitle(details?.entityDefinition, details?.entityData, preset, fallbackItem).then((title) => {
3020
+ if (version === this.headerTitleVersion) {
3021
+ this.headerTitle.set(title);
3022
+ }
3023
+ });
3024
+ });
3168
3025
  }
3169
3026
  //#endregion
3170
3027
  //#region ---- Public Methods ----
@@ -3201,10 +3058,34 @@ class AXPEntityDetailPopoverComponent {
3201
3058
  }
3202
3059
  //#endregion
3203
3060
  //#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 : '';
3061
+ async resolveHeaderTitle(entityDefinition, data, preset, fallbackItem) {
3062
+ if (data && entityDefinition) {
3063
+ const fromDetails = await this.resolveLookupDisplayLabelAsync(data, entityDefinition);
3064
+ if (fromDetails) {
3065
+ return fromDetails;
3066
+ }
3067
+ }
3068
+ const presetTrimmed = preset?.trim();
3069
+ if (presetTrimmed && !isUnresolvedEntityDisplayTemplate(presetTrimmed)) {
3070
+ return presetTrimmed;
3071
+ }
3072
+ if (fallbackItem) {
3073
+ const fromItem = await this.resolveLookupDisplayLabelAsync(fallbackItem, entityDefinition);
3074
+ if (fromItem) {
3075
+ return fromItem;
3076
+ }
3077
+ }
3078
+ return presetTrimmed ?? '';
3079
+ }
3080
+ async resolveLookupDisplayLabelAsync(item, entityDefinition) {
3081
+ const locale = this.translation.getActiveLang() ?? 'en-US';
3082
+ const label = await formatLookupItemDisplayAsync(item, entityDefinition ?? null, { textField: this.textField() }, this.formatService, {
3083
+ expressionEvaluator: this.expressionEvaluator,
3084
+ contextEvalFactory: this.contextEvalFactory,
3085
+ translationService: this.translation,
3086
+ locale,
3087
+ }, (value) => this.translation.resolve(value));
3088
+ return label && !isUnresolvedEntityDisplayTemplate(label) ? label : '';
3208
3089
  }
3209
3090
  /**
3210
3091
  * Returns true if a value is meaningful for display (non-empty/non-null).
@@ -3369,14 +3250,24 @@ class AXPEntityDetailPopoverComponent {
3369
3250
  resolveDataPath(prop, data) {
3370
3251
  const iface = prop.schema?.interface;
3371
3252
  const expose = iface?.options?.['expose'];
3253
+ const textField = iface?.options?.['textField']?.trim();
3372
3254
  if (expose?.length) {
3373
- // Try expanded path first (e.g. personTitle for personTitle.title)
3374
3255
  const textTarget = expose.find((e) => e.source !== 'id');
3375
3256
  if (textTarget) {
3376
3257
  const expandedPath = textTarget.target.split('.')[0];
3377
3258
  const expandedValue = get(data, expandedPath);
3378
3259
  if (expandedValue != null && typeof expandedValue === 'object') {
3379
- return expandedPath;
3260
+ if (textField) {
3261
+ if (this.hasMeaningfulValue(get(expandedValue, textField))) {
3262
+ return expandedPath;
3263
+ }
3264
+ }
3265
+ else {
3266
+ const leaf = textTarget.target.split('.').pop();
3267
+ if (leaf && this.hasMeaningfulValue(get(expandedValue, leaf))) {
3268
+ return expandedPath;
3269
+ }
3270
+ }
3380
3271
  }
3381
3272
  }
3382
3273
  }
@@ -3388,7 +3279,7 @@ class AXPEntityDetailPopoverComponent {
3388
3279
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailPopoverComponent, decorators: [{
3389
3280
  type: Component,
3390
3281
  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 }] }] } });
3282
+ }], 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
3283
 
3393
3284
  class AXPEntityDetailPopoverService {
3394
3285
  constructor() {
@@ -3402,6 +3293,7 @@ class AXPEntityDetailPopoverService {
3402
3293
  //#region ---- Private Properties ----
3403
3294
  this.overlayRef = null;
3404
3295
  this.componentRef = null;
3296
+ this.anchorElement = null;
3405
3297
  this.outsideClickHandler = null;
3406
3298
  this.keydownHandler = null;
3407
3299
  this.routerSubscription = null;
@@ -3458,6 +3350,7 @@ class AXPEntityDetailPopoverService {
3458
3350
  });
3459
3351
  this.overlayRef = ref;
3460
3352
  this.componentRef = ref.instance;
3353
+ this.anchorElement = anchorElement;
3461
3354
  setTimeout(() => {
3462
3355
  ref.updatePosition();
3463
3356
  this.bindDismissHandlers(ref.overlayElement, anchorElement);
@@ -3559,6 +3452,7 @@ class AXPEntityDetailPopoverService {
3559
3452
  this.removeDismissHandlers();
3560
3453
  this.overlayRef = null;
3561
3454
  this.componentRef = null;
3455
+ this.anchorElement = null;
3562
3456
  }
3563
3457
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailPopoverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3564
3458
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailPopoverService, providedIn: 'root' }); }
@@ -3817,16 +3711,27 @@ function commandMessageTextForError(value) {
3817
3711
  * 2. Falls back to CRUD service if not defined
3818
3712
  */
3819
3713
  class EntityDataAccessor {
3820
- constructor(module, entity, entityRegistry, queryExecutor, commandService) {
3714
+ constructor(module, entity, entityRegistry, queryExecutor, commandService, injector) {
3821
3715
  this.module = module;
3822
3716
  this.entity = entity;
3823
3717
  this.entityRegistry = entityRegistry;
3824
3718
  this.queryExecutor = queryExecutor;
3825
3719
  this.commandService = commandService;
3720
+ this.injector = injector;
3826
3721
  this.crudService = null;
3827
3722
  this.entityDef = null;
3828
3723
  this.entityDefPromise = null;
3829
3724
  }
3725
+ /**
3726
+ * Lazily creates the CRUD fallback inside an injection context so {@link AXMEntityCrudServiceImpl}
3727
+ * can resolve {@link AXPEntityStorageService} via `inject()`.
3728
+ */
3729
+ ensureCrudService() {
3730
+ if (!this.crudService) {
3731
+ this.crudService = runInInjectionContext(this.injector, () => new AXMEntityCrudServiceImpl(`${this.module}.${this.entity}`));
3732
+ }
3733
+ return this.crudService;
3734
+ }
3830
3735
  /**
3831
3736
  * Resolves the entity definition lazily and caches it.
3832
3737
  * @returns The resolved entity definition
@@ -3859,10 +3764,7 @@ class EntityDataAccessor {
3859
3764
  return await this.queryExecutor.fetch(execute, key);
3860
3765
  }
3861
3766
  // Fallback to CRUD service
3862
- if (!this.crudService) {
3863
- this.crudService = new AXMEntityCrudServiceImpl(`${this.module}.${this.entity}`);
3864
- }
3865
- return await this.crudService.getOne(key);
3767
+ return await this.ensureCrudService().getOne(key);
3866
3768
  }
3867
3769
  /**
3868
3770
  * Queries a list of entities.
@@ -3885,20 +3787,14 @@ class EntityDataAccessor {
3885
3787
  return result;
3886
3788
  }
3887
3789
  // Fallback to CRUD service
3888
- if (!this.crudService) {
3889
- this.crudService = new AXMEntityCrudServiceImpl(`${this.module}.${this.entity}`);
3890
- }
3891
- return await this.crudService.query(queryRequest);
3790
+ return await this.ensureCrudService().query(queryRequest);
3892
3791
  }
3893
3792
  /**
3894
3793
  * Queries category entities linked to this entity (`{module}.{entity}Category`).
3895
3794
  * Falls back to CRUD category storage (same as {@link AXMEntityCrudServiceImpl.getCategoriesList}).
3896
3795
  */
3897
3796
  async getCategoriesList(request = { skip: 0, take: 1000 }) {
3898
- if (!this.crudService) {
3899
- this.crudService = new AXMEntityCrudServiceImpl(`${this.module}.${this.entity}`);
3900
- }
3901
- return await this.crudService.getCategoriesList(request);
3797
+ return await this.ensureCrudService().getCategoriesList(request);
3902
3798
  }
3903
3799
  /**
3904
3800
  * Creates a new entity.
@@ -3920,10 +3816,7 @@ class EntityDataAccessor {
3920
3816
  return result.data?.id || result.data;
3921
3817
  }
3922
3818
  // Fallback to CRUD service
3923
- if (!this.crudService) {
3924
- this.crudService = new AXMEntityCrudServiceImpl(`${this.module}.${this.entity}`);
3925
- }
3926
- return await this.crudService.insertOne(data);
3819
+ return await this.ensureCrudService().insertOne(data);
3927
3820
  }
3928
3821
  /**
3929
3822
  * Updates an existing entity.
@@ -3946,10 +3839,7 @@ class EntityDataAccessor {
3946
3839
  return result.data;
3947
3840
  }
3948
3841
  // Fallback to CRUD service
3949
- if (!this.crudService) {
3950
- this.crudService = new AXMEntityCrudServiceImpl(`${this.module}.${this.entity}`);
3951
- }
3952
- return await this.crudService.updateOne(id, data);
3842
+ return await this.ensureCrudService().updateOne(id, data);
3953
3843
  }
3954
3844
  /**
3955
3845
  * Deletes an entity.
@@ -3970,10 +3860,7 @@ class EntityDataAccessor {
3970
3860
  return;
3971
3861
  }
3972
3862
  // Fallback to CRUD service
3973
- if (!this.crudService) {
3974
- this.crudService = new AXMEntityCrudServiceImpl(`${this.module}.${this.entity}`);
3975
- }
3976
- return await this.crudService.deleteOne(id);
3863
+ return await this.ensureCrudService().deleteOne(id);
3977
3864
  }
3978
3865
  }
3979
3866
  //#endregion
@@ -3983,11 +3870,12 @@ class EntityDataAccessor {
3983
3870
  * Provides methods to create paths and access entity data.
3984
3871
  */
3985
3872
  class EntityBuilder {
3986
- constructor(module, entity, sessionService, entityRegistry, queryExecutor, commandService) {
3873
+ constructor(module, entity, sessionService, entityRegistry, queryExecutor, commandService, injector) {
3987
3874
  this.sessionService = sessionService;
3988
3875
  this.entityRegistry = entityRegistry;
3989
3876
  this.queryExecutor = queryExecutor;
3990
3877
  this.commandService = commandService;
3878
+ this.injector = injector;
3991
3879
  this.module = module;
3992
3880
  this.entity = entity;
3993
3881
  }
@@ -4005,7 +3893,7 @@ class EntityBuilder {
4005
3893
  * @returns An EntityDataAccessor instance
4006
3894
  */
4007
3895
  data() {
4008
- return new EntityDataAccessor(this.module, this.entity, this.entityRegistry, this.queryExecutor, this.commandService);
3896
+ return new EntityDataAccessor(this.module, this.entity, this.entityRegistry, this.queryExecutor, this.commandService, this.injector);
4009
3897
  }
4010
3898
  }
4011
3899
  //#endregion
@@ -4015,6 +3903,7 @@ class AXPEntityService {
4015
3903
  this.entityRegistry = inject(AXPEntityDefinitionRegistryService);
4016
3904
  this.queryExecutor = inject(AXPQueryExecutor);
4017
3905
  this.commandService = inject(AXPCommandService);
3906
+ this.injector = inject(Injector);
4018
3907
  }
4019
3908
  /**
4020
3909
  * @deprecated Use `withEntity(module, entity).createPath(path)` instead.
@@ -4040,7 +3929,7 @@ class AXPEntityService {
4040
3929
  module = moduleOrEntityKey.substring(0, dotIndex);
4041
3930
  entityName = moduleOrEntityKey.substring(dotIndex + 1);
4042
3931
  }
4043
- return new EntityBuilder(module, entityName, this.sessionService, this.entityRegistry, this.queryExecutor, this.commandService);
3932
+ return new EntityBuilder(module, entityName, this.sessionService, this.entityRegistry, this.queryExecutor, this.commandService, this.injector);
4044
3933
  }
4045
3934
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4046
3935
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityService, providedIn: 'root' }); }
@@ -4055,7 +3944,6 @@ class AXPEntityPreloadFiltersContainerComponent extends AXPPageLayoutBaseCompone
4055
3944
  super(...arguments);
4056
3945
  //#region ---- Services & Dependencies ----
4057
3946
  this.route = inject(ActivatedRoute);
4058
- this.router = inject(Router);
4059
3947
  this.entityService = inject(AXPEntityService);
4060
3948
  this.filterOperatorMiddleware = inject(AXPFilterOperatorMiddlewareService);
4061
3949
  //#endregion
@@ -4345,7 +4233,8 @@ const PLUGIN_SLOT_INDEX = {
4345
4233
  attachments: 1,
4346
4234
  documents: 2,
4347
4235
  comments: 3,
4348
- history: 4,
4236
+ dashboard: 4,
4237
+ history: 5,
4349
4238
  };
4350
4239
  //#endregion
4351
4240
  //#region ---- Helpers ----
@@ -4474,7 +4363,7 @@ class AXPEntityCommandTriggerViewModel {
4474
4363
  this.priority = action.priority;
4475
4364
  this.title = action.title;
4476
4365
  this.separated = action.separated ?? false;
4477
- this.color = action.color ?? resolvedLook.color;
4366
+ this.color = (action.color ?? resolvedLook.color);
4478
4367
  this.icon = action.icon ?? resolvedLook.icon;
4479
4368
  this.hidden = action.hidden ?? false;
4480
4369
  this.disabled = action.disabled ?? false;
@@ -4566,6 +4455,7 @@ class AXPEntityDetailListViewModel {
4566
4455
  this.settingsService = this.injector.get(AXPSettingsService);
4567
4456
  this.destroyed = new Subject();
4568
4457
  this.showRowIndexColumnEnabled = signal(false, ...(ngDevMode ? [{ debugName: "showRowIndexColumnEnabled" }] : /* istanbul ignore next */ []));
4458
+ this.lastAppliedFilterKey = null;
4569
4459
  /** Whether the row index column is shown (user setting). */
4570
4460
  this.showIndexColumn = computed(() => this.showRowIndexColumnEnabled(), ...(ngDevMode ? [{ debugName: "showIndexColumn" }] : /* istanbul ignore next */ []));
4571
4461
  this.dataSource = new AXDataSource({
@@ -4759,10 +4649,6 @@ class AXPEntityDetailListViewModel {
4759
4649
  this.applyFilterAndSort();
4760
4650
  }
4761
4651
  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
4652
  const parentFilters = (await Promise.all(this.detailEntityConfig.conditions?.map(async (c) => {
4767
4653
  return {
4768
4654
  field: c.name,
@@ -4780,22 +4666,30 @@ class AXPEntityDetailListViewModel {
4780
4666
  //
4781
4667
  const inline = this.inlineFilters.filters?.length ?? 0;
4782
4668
  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({
4669
+ let effectiveFilter;
4670
+ if (inline && parent) {
4671
+ effectiveFilter = this.filterOperatorMiddleware.transformFilter({
4792
4672
  field: null,
4793
4673
  logic: 'and',
4794
4674
  operator: null,
4795
4675
  filters: [this.inlineFilters, parentFilterWrapper],
4796
- }));
4676
+ });
4677
+ }
4678
+ else if (inline) {
4679
+ effectiveFilter = this.filterOperatorMiddleware.transformFilter(this.inlineFilters);
4680
+ }
4681
+ else if (parent) {
4682
+ effectiveFilter = this.filterOperatorMiddleware.transformFilter(parentFilterWrapper);
4683
+ }
4684
+ const filterKey = JSON.stringify(effectiveFilter ?? null);
4685
+ if (filterKey === this.lastAppliedFilterKey) {
4686
+ return;
4687
+ }
4688
+ this.lastAppliedFilterKey = filterKey;
4689
+ this.dataSource.clearFilter();
4690
+ if (effectiveFilter) {
4691
+ this.dataSource.filter(effectiveFilter);
4797
4692
  }
4798
- //
4799
4693
  this.dataSource.refresh();
4800
4694
  }
4801
4695
  //****************** Commands ******************//
@@ -5344,7 +5238,7 @@ class AXPEntityMasterListViewModel {
5344
5238
  }
5345
5239
  }
5346
5240
  //#endregion
5347
- createExpressionScope(data) {
5241
+ createLogicExpressionScope(data) {
5348
5242
  return {
5349
5243
  context: {
5350
5244
  eval: (path) => get(data, path),
@@ -5355,11 +5249,20 @@ class AXPEntityMasterListViewModel {
5355
5249
  },
5356
5250
  };
5357
5251
  }
5252
+ createDisplayExpressionScope(data) {
5253
+ return {
5254
+ context: this.contextEvalFactory.createScope((data ?? {})),
5255
+ list: {
5256
+ view: () => this.view().name,
5257
+ views: () => this.views().map((v) => ({ name: v.name, title: v.title })),
5258
+ },
5259
+ };
5260
+ }
5358
5261
  async resolveCommandNameExpression(commandName, data) {
5359
5262
  if (!commandName || !commandName.includes('{{')) {
5360
5263
  return commandName;
5361
5264
  }
5362
- const scope = this.createExpressionScope(data);
5265
+ const scope = this.createLogicExpressionScope(data);
5363
5266
  const result = await this.expressionEvaluator.evaluate({ value: commandName }, scope);
5364
5267
  const resolved = result?.value;
5365
5268
  return typeof resolved === 'string' && resolved.trim() !== '' ? resolved : commandName;
@@ -5368,7 +5271,7 @@ class AXPEntityMasterListViewModel {
5368
5271
  if (!title || !title.includes('{{')) {
5369
5272
  return title;
5370
5273
  }
5371
- const scope = this.createExpressionScope(data);
5274
+ const scope = this.createDisplayExpressionScope(data);
5372
5275
  const result = await this.expressionEvaluator.evaluate({ value: title }, scope);
5373
5276
  const resolved = result?.value;
5374
5277
  return typeof resolved === 'string' && resolved.trim() !== '' ? resolved : title;
@@ -5383,7 +5286,7 @@ class AXPEntityMasterListViewModel {
5383
5286
  return '';
5384
5287
  }
5385
5288
  if (value.includes('{{')) {
5386
- const scope = this.createExpressionScope(rowData);
5289
+ const scope = this.createDisplayExpressionScope(rowData);
5387
5290
  const result = await this.expressionEvaluator.evaluate(value, scope);
5388
5291
  if (result === false) {
5389
5292
  return '';
@@ -5421,7 +5324,7 @@ class AXPEntityMasterListViewModel {
5421
5324
  if (color == null || color === '') {
5422
5325
  return 'default';
5423
5326
  }
5424
- const scope = this.createExpressionScope(rowData);
5327
+ const scope = this.createLogicExpressionScope(rowData);
5425
5328
  const result = await this.expressionEvaluator.evaluate(color, scope);
5426
5329
  if (result === false || result == null) {
5427
5330
  return 'default';
@@ -5469,6 +5372,7 @@ class AXPEntityMasterListViewModel {
5469
5372
  this.settings = this.injector.get(AXPSettingsService);
5470
5373
  this.widgetResolver = this.injector.get(AXPWidgetRegistryService);
5471
5374
  this.expressionEvaluator = this.injector.get(AXPExpressionEvaluatorService);
5375
+ this.contextEvalFactory = this.injector.get(AXPContextEvalFactory);
5472
5376
  this.translation = this.injector.get(AXTranslationService);
5473
5377
  this.commandService = this.injector.get(AXPCommandService);
5474
5378
  this.eventService = this.injector.get(AXPBroadcastEventService);
@@ -5582,8 +5486,11 @@ class AXPEntityMasterListViewModel {
5582
5486
  return this._viewDef.description ?? null;
5583
5487
  }, ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
5584
5488
  //****************** Inline filter ******************//
5489
+ this.filterDefinitions = signal([], ...(ngDevMode ? [{ debugName: "filterDefinitions" }] : /* istanbul ignore next */ []));
5585
5490
  this.inlineFiltersPlaceholders = computed(() => {
5586
- return this.entityDef.properties.filter((p) => p.options?.filter?.inline?.enabled).map((c) => c.title ?? c.name);
5491
+ return this.filterDefinitions()
5492
+ .filter((f) => f.filterType.inline)
5493
+ .map((c) => c.title ?? c.field);
5587
5494
  }, ...(ngDevMode ? [{ debugName: "inlineFiltersPlaceholders" }] : /* istanbul ignore next */ []));
5588
5495
  this.hasInlineFilters = computed(() => {
5589
5496
  return this.inlineFiltersPlaceholders().length > 0;
@@ -5623,7 +5530,6 @@ class AXPEntityMasterListViewModel {
5623
5530
  this.primaryRowActions = computed(() => this.allActions().filter((a) => a.scope == AXPEntityCommandScope.Individual && a.priority === 'primary'), ...(ngDevMode ? [{ debugName: "primaryRowActions" }] : /* istanbul ignore next */ []));
5624
5531
  //****************** Filter ******************//
5625
5532
  this.filterQueries = signal([], ...(ngDevMode ? [{ debugName: "filterQueries" }] : /* istanbul ignore next */ []));
5626
- //****************** Columns ******************//
5627
5533
  this.allAvailableColumns = () => {
5628
5534
  const { columns = [], properties } = this.entityDef;
5629
5535
  // const visibleProperties = properties.filter(({ schema }) => schema?.visible !== false);
@@ -5631,13 +5537,15 @@ class AXPEntityMasterListViewModel {
5631
5537
  return columns
5632
5538
  .filter(({ name, showAs, options }) => (propNames.has(name) || showAs) && options?.visible !== false)
5633
5539
  .map((column) => {
5540
+ const relatedProperty = this.resolveMergeDetailProperty(column.name);
5634
5541
  if (column.showAs) {
5635
5542
  const widgetConfig = this.widgetResolver.resolve(column.showAs.type);
5636
5543
  const { title: _wcTitle, description: _wcDescription, ...widgetRest } = widgetConfig;
5637
5544
  const property = {
5638
5545
  ...widgetRest,
5639
5546
  name: column.name,
5640
- title: column.title ?? '',
5547
+ title: column.title ?? relatedProperty?.title ?? '',
5548
+ options: relatedProperty?.options,
5641
5549
  schema: {
5642
5550
  dataType: 'string',
5643
5551
  interface: {
@@ -5666,18 +5574,16 @@ class AXPEntityMasterListViewModel {
5666
5574
  };
5667
5575
  this.cardFields = signal([], ...(ngDevMode ? [{ debugName: "cardFields" }] : /* istanbul ignore next */ []));
5668
5576
  //****************** Sort ******************//
5577
+ this.sortableFieldDefinitions = signal([], ...(ngDevMode ? [{ debugName: "sortableFieldDefinitions" }] : /* istanbul ignore next */ []));
5669
5578
  this.sortableFields = () => {
5670
- const props = this.entityDef.properties.filter((c) => c.options?.sort?.enabled);
5671
- return props.map((e) => {
5672
- return {
5673
- name: e.name,
5674
- title: e.title,
5675
- dir: undefined,
5676
- };
5677
- });
5579
+ return this.sortableFieldDefinitions().map((field) => ({
5580
+ name: field.name,
5581
+ title: field.title,
5582
+ dir: undefined,
5583
+ }));
5678
5584
  };
5679
5585
  this.sortableFieldsCount = () => {
5680
- return this.entityDef.properties.filter((c) => c.options?.sort?.enabled).length ?? 0;
5586
+ return this.sortableFieldDefinitions().length;
5681
5587
  };
5682
5588
  this.canSort = () => {
5683
5589
  return this.sortableFieldsCount() > 0;
@@ -5691,7 +5597,7 @@ class AXPEntityMasterListViewModel {
5691
5597
  this.sortedFields = signal([], ...(ngDevMode ? [{ debugName: "sortedFields" }] : /* istanbul ignore next */ []));
5692
5598
  //#endregion
5693
5599
  this.evaluateExpressions = async (options, data) => {
5694
- const scope = this.createExpressionScope(data);
5600
+ const scope = this.createLogicExpressionScope(data);
5695
5601
  return await this.expressionEvaluator.evaluate(options, scope);
5696
5602
  };
5697
5603
  this.workflow.events$
@@ -6081,7 +5987,7 @@ class AXPEntityMasterListViewModel {
6081
5987
  this.selectedCategory.set(category);
6082
5988
  }
6083
5989
  async getPrimaryActions() {
6084
- const scope = this.createExpressionScope(null);
5990
+ const scope = this.createLogicExpressionScope(null);
6085
5991
  const actions = await Promise.all(this.allActions()
6086
5992
  .filter((a) => a.priority == 'primary' &&
6087
5993
  ((a.scope == AXPEntityCommandScope.Selected && this.hasSelectedItems()) ||
@@ -6098,7 +6004,7 @@ class AXPEntityMasterListViewModel {
6098
6004
  return actions.filter(Boolean);
6099
6005
  }
6100
6006
  async getSecondaryActions() {
6101
- const scope = this.createExpressionScope(null);
6007
+ const scope = this.createLogicExpressionScope(null);
6102
6008
  const actions = await Promise.all(this.allActions()
6103
6009
  .filter((a) => a.priority == 'secondary' &&
6104
6010
  ((a.scope == AXPEntityCommandScope.Selected && this.hasSelectedItems()) ||
@@ -6115,7 +6021,7 @@ class AXPEntityMasterListViewModel {
6115
6021
  return actions.filter(Boolean);
6116
6022
  }
6117
6023
  async secondaryRowActions(rowData) {
6118
- const scope = this.createExpressionScope(rowData);
6024
+ const scope = this.createLogicExpressionScope(rowData);
6119
6025
  const actions = await Promise.all(this.allActions()
6120
6026
  .filter((a) => a.scope === AXPEntityCommandScope.Individual && a.priority === 'secondary')
6121
6027
  .map(async (a) => {
@@ -6276,38 +6182,27 @@ class AXPEntityMasterListViewModel {
6276
6182
  }
6277
6183
  return false;
6278
6184
  }
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
- };
6185
+ /**
6186
+ * Loads host and merge-detail related sortable field definitions (async registry resolution).
6187
+ */
6188
+ async loadSortableFields() {
6189
+ const fields = await collectEntityListSortableFields(this.entityDef, (moduleName, entityName) => this.entityDefinitionRegistry.resolve(moduleName, entityName).catch(() => null));
6190
+ this.sortableFieldDefinitions.set(fields);
6191
+ }
6192
+ /**
6193
+ * Loads host and merge-detail related filter definitions (async registry resolution).
6194
+ */
6195
+ async loadFilterDefinitions() {
6196
+ const definitions = await collectEntityListFilterDefinitions(this.entityDef, (moduleName, entityName) => this.entityDefinitionRegistry.resolve(moduleName, entityName).catch(() => null), {
6197
+ resolveWidget: (type) => this.widgetResolver.resolve(type),
6307
6198
  });
6199
+ this.filterDefinitions.set(definitions);
6200
+ }
6201
+ get filtersDef() {
6202
+ return this.filterDefinitions();
6308
6203
  }
6309
6204
  get preloadFiltersDef() {
6310
- return this.filtersDef.filter((f) => f.filterType.preload?.enabled);
6205
+ return this.filterDefinitions().filter((f) => f.filterType.preload?.enabled);
6311
6206
  }
6312
6207
  // const viewFilters = this.view().conditions.map((f) => ({
6313
6208
  // field: f.name,
@@ -6337,7 +6232,13 @@ class AXPEntityMasterListViewModel {
6337
6232
  .map((s) => ({ name: s.name, dir: s.dir }));
6338
6233
  const filters = this.filterQueries();
6339
6234
  const sortKey = JSON.stringify(sorts);
6340
- const filterKey = JSON.stringify(filters);
6235
+ const transformedFilter = this.filterOperatorMiddleware.transformFilter({
6236
+ field: null,
6237
+ logic: 'and',
6238
+ operator: null,
6239
+ filters: filters,
6240
+ });
6241
+ const filterKey = JSON.stringify(transformedFilter);
6341
6242
  if (sortKey === this.lastAppliedSortKey && filterKey === this.lastAppliedFilterKey) {
6342
6243
  return; // No effective change; avoid redundant refresh
6343
6244
  }
@@ -6349,14 +6250,23 @@ class AXPEntityMasterListViewModel {
6349
6250
  }
6350
6251
  this.dataSource.clearFilter();
6351
6252
  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
- }));
6253
+ this.dataSource.filter(transformedFilter);
6358
6254
  this.events$.next({ action: 'refresh', meta: { resetPagination: filtersChanged } });
6359
6255
  }
6256
+ //****************** Columns ******************//
6257
+ resolveMergeDetailProperty(columnName) {
6258
+ const parsed = parseDottedFieldPath(columnName);
6259
+ if (!parsed) {
6260
+ return null;
6261
+ }
6262
+ const { dataPath, propertyName } = parsed;
6263
+ const related = this.entityDef.relatedEntities?.find((entry) => entry.layout?.type === 'merge-detail' && entry.persistence?.dataPath?.trim() === dataPath);
6264
+ if (!related?.entity) {
6265
+ return null;
6266
+ }
6267
+ const relatedDef = this.getRegisteredEntity(related.entity);
6268
+ return relatedDef?.properties?.find((property) => property.name === propertyName) ?? null;
6269
+ }
6360
6270
  resetColumns() {
6361
6271
  this.applyViewColumns();
6362
6272
  }
@@ -6751,6 +6661,8 @@ class AXPEntityListViewModelFactory {
6751
6661
  const config = await this.entityService.resolve(moduleName, entityName);
6752
6662
  this.layout.setNavigationLoading(false);
6753
6663
  const vm = new AXPEntityMasterListViewModel(this.injector, config);
6664
+ await vm.loadFilterDefinitions();
6665
+ await vm.loadSortableFields();
6754
6666
  await vm.initializeListPersistence();
6755
6667
  return vm;
6756
6668
  }
@@ -6785,7 +6697,7 @@ const AXPEntityListViewModelResolver = async (route, state, service = inject(AXP
6785
6697
  }
6786
6698
  };
6787
6699
 
6788
- const AXPEntityDeletedEvent = createWorkFlowEvent('[Entity] Deleted');
6700
+ const AXPEntityDeletedEvent = createWorkFlowEvent(AXP_ENTITY_DELETED_WORKFLOW_EVENT_TYPE);
6789
6701
  class AXPEntityPerformDeleteAction extends AXPWorkflowAction {
6790
6702
  constructor() {
6791
6703
  super(...arguments);
@@ -7138,6 +7050,9 @@ class AXPEntityModifySectionPopupAction extends AXPWorkflowAction {
7138
7050
  this.popupService = inject(AXPopupService);
7139
7051
  this.platform = inject(AXPlatform);
7140
7052
  this.translateService = inject(AXTranslationService);
7053
+ this.formatService = inject(AXFormatService);
7054
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
7055
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
7141
7056
  this.entityRegistery = inject(AXPEntityDefinitionRegistryService);
7142
7057
  this.config = inject(AXP_ENTITY_CONFIG_TOKEN);
7143
7058
  this.factory = inject(AXPEntityMasterUpdateViewModelFactory);
@@ -7155,7 +7070,7 @@ class AXPEntityModifySectionPopupAction extends AXPWorkflowAction {
7155
7070
  title: headerTitle
7156
7071
  ? headerTitle
7157
7072
  : title ??
7158
- `${this.translateService.translateSync('entity.modify')} ${this.translateService.translateSync(entityRef.formats.individual)}`,
7073
+ (await resolveEntityModifyPopupTitle(entityRef, vm.context(), this.translateService, this.formatService, this.expressionEvaluator, this.contextEvalFactory)),
7159
7074
  size: this.platform.is('Mobile') || this.platform.is('SM') ? 'full' : 'md',
7160
7075
  data: {
7161
7076
  vm,
@@ -7516,6 +7431,8 @@ class AXPEntityPreloadFiltersViewModel {
7516
7431
  this.config = config;
7517
7432
  this.entityDef = cloneDeep(this.config);
7518
7433
  this.widgetResolver = this.injector.get(AXPWidgetRegistryService);
7434
+ this.entityRegistry = this.injector.get(AXPEntityDefinitionRegistryService);
7435
+ this.filterDefinitions = signal([], ...(ngDevMode ? [{ debugName: "filterDefinitions" }] : /* istanbul ignore next */ []));
7519
7436
  //#endregion
7520
7437
  //#region ---- Computed Properties ----
7521
7438
  /**
@@ -7534,46 +7451,7 @@ class AXPEntityPreloadFiltersViewModel {
7534
7451
  * All filter definitions for properties with preload enabled
7535
7452
  */
7536
7453
  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
- });
7454
+ return this.filterDefinitions().filter((definition) => definition.filterType.preload?.enabled);
7577
7455
  }, ...(ngDevMode ? [{ debugName: "preloadFiltersDef" }] : /* istanbul ignore next */ []));
7578
7456
  /**
7579
7457
  * Required filter definitions only
@@ -7582,7 +7460,14 @@ class AXPEntityPreloadFiltersViewModel {
7582
7460
  return this.preloadFiltersDef().filter((c) => c.filterType.preload?.required);
7583
7461
  }, ...(ngDevMode ? [{ debugName: "requiredFiltersDef" }] : /* istanbul ignore next */ []));
7584
7462
  }
7463
+ //#endregion
7585
7464
  //#region ---- Methods ----
7465
+ async loadFilterDefinitions() {
7466
+ const definitions = await collectEntityListFilterDefinitions(this.entityDef, (moduleName, entityName) => this.entityRegistry.resolve(moduleName, entityName).catch(() => null), {
7467
+ resolveWidget: (type) => this.widgetResolver.resolve(type),
7468
+ });
7469
+ this.filterDefinitions.set(definitions);
7470
+ }
7586
7471
  /**
7587
7472
  * Serialize filter values to plain objects (remove signals, functions, etc.)
7588
7473
  */
@@ -7599,159 +7484,17 @@ const AXPEntityPreloadFiltersViewModelResolver = async (route, state) => {
7599
7484
  const entityName = route.paramMap.get('entity');
7600
7485
  try {
7601
7486
  const entity = await entityRegistry.resolve(moduleName, entityName);
7602
- return new AXPEntityPreloadFiltersViewModel(injector, entity);
7603
- }
7604
- catch (error) {
7605
- if (error instanceof AXPNotFoundError) {
7606
- return axpRedirectToNotFound(router);
7607
- }
7608
- throw error;
7609
- }
7610
- };
7611
- //#endregion
7612
-
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}`);
7487
+ const vm = new AXPEntityPreloadFiltersViewModel(injector, entity);
7488
+ await vm.loadFilterDefinitions();
7489
+ return vm;
7490
+ }
7491
+ catch (error) {
7492
+ if (error instanceof AXPNotFoundError) {
7493
+ return axpRedirectToNotFound(router);
7751
7494
  }
7495
+ throw error;
7752
7496
  }
7753
- return [...paths];
7754
- }
7497
+ };
7755
7498
  //#endregion
7756
7499
 
7757
7500
  //#region ---- Path / numeric helpers ----
@@ -10149,7 +9892,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
10149
9892
  ></ax-button>
10150
9893
  </ax-suffix>
10151
9894
  </ax-footer>
10152
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$1.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i4.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i3.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "component", type: AXTreeViewComponent, selector: "ax-tree-view", inputs: ["datasource", "selectMode", "selectionBehavior", "dragArea", "dragBehavior", "showIcons", "showChildrenBadge", "expandedIcon", "collapsedIcon", "indentSize", "look", "nodeTemplate", "idField", "titleField", "tooltipField", "iconField", "expandedField", "selectedField", "indeterminateField", "disabledField", "hiddenField", "childrenField", "childrenCountField", "dataField", "inheritDisabled", "expandOnDoubleClick", "doubleClickDuration", "tooltipDelay", "controlledSelection", "selectedIds"], outputs: ["datasourceChange", "selectedIdsChange", "onBeforeDrop", "onNodeToggle", "onNodeSelect", "onNodeDoubleClick", "onNodeClick", "onSelectionChange", "onOrderChange", "onMoveChange", "onItemsChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "look"] }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
9895
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$1.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i4.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i3.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "component", type: AXTreeViewComponent, selector: "ax-tree-view", inputs: ["datasource", "selectMode", "selectionBehavior", "dragArea", "dragBehavior", "showIcons", "showChildrenBadge", "expandedIcon", "collapsedIcon", "indentSize", "look", "nodeTemplate", "idField", "titleField", "tooltipField", "iconField", "expandedField", "selectedField", "indeterminateField", "disabledField", "hiddenField", "childrenField", "childrenCountField", "dataField", "inheritDisabled", "expandOnDoubleClick", "doubleClickDuration", "tooltipDelay", "controlledSelection", "selectedIds"], outputs: ["datasourceChange", "selectedIdsChange", "onBeforeDrop", "onNodeToggle", "onNodeSelect", "onNodeDoubleClick", "onNodeClick", "onSelectionChange", "onOrderChange", "onMoveChange", "onItemsChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "titleParams", "descriptionParams", "look"] }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
10153
9896
  }
10154
9897
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityCategoryTreeSelectorComponent, decorators: [{
10155
9898
  type: Component,
@@ -12392,6 +12135,7 @@ class AXPEntityListTableService {
12392
12135
  const evaluatedOptions = await this.evaluateExpressions(action?.options, data);
12393
12136
  const options = this.mergeRelatedListFormOptions(command, evaluatedOptions, relatedListExcludeProperties);
12394
12137
  if (this.commandService.exists(command)) {
12138
+ const excludeProperties = options['excludeProperties'];
12395
12139
  await this.commandService.execute(command, {
12396
12140
  __context__: {
12397
12141
  entity: getEntityInfo(entity).source,
@@ -12408,6 +12152,7 @@ class AXPEntityListTableService {
12408
12152
  },
12409
12153
  options,
12410
12154
  metadata: action?.metadata,
12155
+ ...(excludeProperties?.length ? { excludeProperties } : {}),
12411
12156
  });
12412
12157
  }
12413
12158
  else {
@@ -12433,7 +12178,7 @@ class AXPEntityListTableService {
12433
12178
  mergeRelatedListFormOptions(command, evaluatedOptions, relatedListExcludeProperties) {
12434
12179
  const exclusions = relatedListExcludeProperties?.filter(Boolean);
12435
12180
  if (!exclusions?.length ||
12436
- (command !== 'Entity:Create' && command !== 'Entity:Update')) {
12181
+ (command !== 'Entity:Create' && command !== 'Entity:Update' && command !== 'Entity:View')) {
12437
12182
  return evaluatedOptions;
12438
12183
  }
12439
12184
  return {
@@ -12484,6 +12229,7 @@ class AXPEntityListToolbarService {
12484
12229
  constructor() {
12485
12230
  //#region ---- Services & Dependencies ----
12486
12231
  this.widgetResolver = inject(AXPWidgetRegistryService);
12232
+ this.entityRegistry = inject(AXPEntityDefinitionRegistryService);
12487
12233
  }
12488
12234
  //#endregion
12489
12235
  //#region ---- Public Methods ----
@@ -12491,11 +12237,11 @@ class AXPEntityListToolbarService {
12491
12237
  * Convert Entity to Toolbar Options
12492
12238
  */
12493
12239
  async convertEntityToolbarOptions(entity, options) {
12494
- const baseFilters = this.createFilterDefinitions(entity);
12240
+ const baseFilters = await this.createFilterDefinitions(entity);
12495
12241
  const toolbarOptions = {
12496
12242
  filterDefinitions: this.mergeFilterDefinitions(baseFilters, options?.customFilterDefinitions),
12497
12243
  columnDefinitions: this.createColumnDefinitions(entity, options),
12498
- sortDefinitions: this.createSortDefinitions(entity),
12244
+ sortDefinitions: await this.createSortDefinitions(entity),
12499
12245
  canFilter: true,
12500
12246
  canColumns: true,
12501
12247
  canSort: true,
@@ -12571,30 +12317,9 @@ class AXPEntityListToolbarService {
12571
12317
  /**
12572
12318
  * Create Filter Definitions for Toolbar
12573
12319
  */
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
- };
12320
+ async createFilterDefinitions(entity) {
12321
+ return collectEntityListFilterDefinitions(entity, (moduleName, entityName) => this.entityRegistry.resolve(moduleName, entityName).catch(() => null), {
12322
+ resolveWidget: (type) => this.widgetResolver.resolve(type),
12598
12323
  });
12599
12324
  }
12600
12325
  /**
@@ -12642,23 +12367,14 @@ class AXPEntityListToolbarService {
12642
12367
  }
12643
12368
  /**
12644
12369
  * Create Sort Definitions for Toolbar.
12645
- * Includes entity.properties with sort enabled, plus enriched columns (dotted paths).
12370
+ * Includes host properties and merge-detail related fields with sort enabled.
12646
12371
  */
12647
- createSortDefinitions(entity) {
12648
- const fromProperties = entity.properties
12649
- .filter((c) => c.options?.sort?.enabled)
12650
- .map((e) => ({ name: e.name, title: e.title }));
12651
- const columns = entity.columns ?? [];
12652
- const fromColumns = columns
12653
- .filter((col) => col.name.includes('.') && col.title)
12654
- .map((col) => ({ name: col.name, title: col.title ?? col.name }));
12655
- const seen = new Set();
12656
- return [...fromProperties, ...fromColumns].filter((s) => {
12657
- if (seen.has(s.name))
12658
- return false;
12659
- seen.add(s.name);
12660
- return true;
12661
- });
12372
+ async createSortDefinitions(entity) {
12373
+ const fields = await collectEntityListSortableFields(entity, (moduleName, entityName) => this.entityRegistry.resolve(moduleName, entityName).catch(() => null));
12374
+ return fields.map((field) => ({
12375
+ name: field.name,
12376
+ title: field.title,
12377
+ }));
12662
12378
  }
12663
12379
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityListToolbarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
12664
12380
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityListToolbarService }); }
@@ -13693,7 +13409,7 @@ class AXPPageComponentWidgetViewComponent extends AXPBaseWidgetComponent {
13693
13409
  return;
13694
13410
  }
13695
13411
  for (const [path, value] of Object.entries(partial)) {
13696
- this.contextService.update(path, value);
13412
+ this.contextService.update(path, value, { origin: 'user' });
13697
13413
  }
13698
13414
  }
13699
13415
  //#endregion
@@ -13977,6 +13693,8 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
13977
13693
  super(...arguments);
13978
13694
  this.formatService = inject(AXFormatService);
13979
13695
  this.translation = inject(AXTranslationService);
13696
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
13697
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
13980
13698
  this.entityResolver = inject(AXPEntityDefinitionRegistryService);
13981
13699
  this.entity = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entity" }] : /* istanbul ignore next */ []));
13982
13700
  this.multiple = computed(() => this.options()['multiple'], ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
@@ -14010,7 +13728,7 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
14010
13728
  if (typeof item == 'object') {
14011
13729
  return {
14012
13730
  id: item[this.valueField()],
14013
- text: this.getDisplayRaw(item),
13731
+ text: await this.getDisplayRaw(item),
14014
13732
  };
14015
13733
  }
14016
13734
  const def = this.entityDef();
@@ -14021,7 +13739,7 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
14021
13739
  this.loading.set(false);
14022
13740
  return {
14023
13741
  id: fetchedItem[this.valueField()],
14024
- text: this.getDisplayRaw(fetchedItem),
13742
+ text: await this.getDisplayRaw(fetchedItem),
14025
13743
  };
14026
13744
  }
14027
13745
  return {
@@ -14029,12 +13747,17 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
14029
13747
  text: item,
14030
13748
  };
14031
13749
  }
14032
- getDisplayRaw(item) {
14033
- const text = formatLookupItemDisplay(item, this.entityDef(), {
13750
+ async getDisplayRaw(item) {
13751
+ const locale = this.translation.getActiveLang() ?? 'en-US';
13752
+ return formatLookupItemDisplayAsync(item, this.entityDef(), {
14034
13753
  displayFormat: this.options()['displayFormat'],
14035
13754
  textField: this.textField(),
14036
- }, this.formatService, (value) => this.translation.resolve(value));
14037
- return text;
13755
+ }, this.formatService, {
13756
+ expressionEvaluator: this.expressionEvaluator,
13757
+ contextEvalFactory: this.contextEvalFactory,
13758
+ translationService: this.translation,
13759
+ locale,
13760
+ }, (value) => this.translation.resolve(value));
14038
13761
  }
14039
13762
  get __class() {
14040
13763
  const cls = {};
@@ -14097,6 +13820,108 @@ var lookupWidgetView_component = /*#__PURE__*/Object.freeze({
14097
13820
  AXPLookupWidgetViewComponent: AXPLookupWidgetViewComponent
14098
13821
  });
14099
13822
 
13823
+ //#region ---- Expression Scope ----
13824
+ /**
13825
+ * Builds the expression scope used to evaluate lookup `create.context` templates.
13826
+ * Matches widget-renderer `context.eval` / `context.set` semantics.
13827
+ */
13828
+ function buildLookupExpressionScope(contextService, parentPath) {
13829
+ return {
13830
+ context: {
13831
+ eval: (path) => {
13832
+ const fullPath = path.startsWith('>') && parentPath ? `${parentPath}.${path.substring(1)}` : path;
13833
+ return contextService.getValue(fullPath);
13834
+ },
13835
+ set: (path, value) => {
13836
+ contextService.update(path, value, { origin: 'user' });
13837
+ },
13838
+ data: () => contextService.data(),
13839
+ isDirty: () => {
13840
+ if (!contextService.isSavedCommitted()) {
13841
+ return false;
13842
+ }
13843
+ return contextService.isDirty();
13844
+ },
13845
+ options: (path) => {
13846
+ if (path == null || path === '') {
13847
+ return contextService.getValue('options');
13848
+ }
13849
+ return contextService.getValue(`options.${path}`);
13850
+ },
13851
+ },
13852
+ events: {},
13853
+ widget: {},
13854
+ methods: {},
13855
+ vars: {},
13856
+ };
13857
+ }
13858
+ //#endregion
13859
+ //#region ---- Create Context Evaluation ----
13860
+ /**
13861
+ * Deep-evaluates expression strings inside lookup `create.context` (e.g. parentId from context).
13862
+ */
13863
+ async function evaluateLookupCreateContext(template, expressionEvaluator, scope) {
13864
+ if (!template || !isObjectLike(template)) {
13865
+ return {};
13866
+ }
13867
+ return (await evaluateLookupCreateContextValue(template, expressionEvaluator, scope));
13868
+ }
13869
+ async function evaluateLookupCreateContextValue(value, expressionEvaluator, scope) {
13870
+ if (typeof value === 'string' && expressionEvaluator.isExpression(value)) {
13871
+ return expressionEvaluator.evaluate(value, scope);
13872
+ }
13873
+ if (isArray(value)) {
13874
+ const results = await Promise.all(value.map((entry) => evaluateLookupCreateContextValue(entry, expressionEvaluator, scope)));
13875
+ return results;
13876
+ }
13877
+ if (isObjectLike(value)) {
13878
+ const result = {};
13879
+ for (const [key, entry] of Object.entries(value)) {
13880
+ result[key] = await evaluateLookupCreateContextValue(entry, expressionEvaluator, scope);
13881
+ }
13882
+ return result;
13883
+ }
13884
+ return value;
13885
+ }
13886
+ /**
13887
+ * Removes null/undefined entries from resolved create context before Entity:Create.
13888
+ */
13889
+ function compactLookupCreateContext(data) {
13890
+ const result = {};
13891
+ for (const [key, value] of Object.entries(cloneDeep(data))) {
13892
+ if (!isNil(value) && value !== '') {
13893
+ result[key] = value;
13894
+ }
13895
+ }
13896
+ return result;
13897
+ }
13898
+ //#endregion
13899
+
13900
+ //#endregion
13901
+ //#region ---- Resolution ----
13902
+ /**
13903
+ * Resolves lookup create options from `create` and legacy `allowCreate` (mode).
13904
+ */
13905
+ function resolveLookupWidgetCreateOptions(options) {
13906
+ const create = options.create;
13907
+ const legacyMode = options.allowCreate;
13908
+ const context = create?.context;
13909
+ if (create?.enable !== undefined) {
13910
+ if (!create.enable) {
13911
+ return { enabled: false, mode: 'none', context };
13912
+ }
13913
+ const mode = legacyMode && legacyMode !== 'none' ? legacyMode : 'quick';
13914
+ return { enabled: true, mode, context };
13915
+ }
13916
+ const mode = legacyMode ?? 'none';
13917
+ return {
13918
+ enabled: mode !== 'none',
13919
+ mode,
13920
+ context,
13921
+ };
13922
+ }
13923
+ //#endregion
13924
+
14100
13925
  //#endregion
14101
13926
  class AXPEntityDataSelectorRowActionsService {
14102
13927
  constructor() {
@@ -14373,11 +14198,20 @@ function mapLegacyEntityDataSelectorOptions(legacy) {
14373
14198
  normalized.category = { enabled: legacy.showCategoryFilter };
14374
14199
  }
14375
14200
  if (legacy.allowCreate !== undefined) {
14376
- normalized.create = { mode: legacy.allowCreate };
14201
+ normalized.create = {
14202
+ ...(legacy.allowCreate !== undefined && {
14203
+ enable: legacy.allowCreate !== 'none',
14204
+ mode: legacy.allowCreate,
14205
+ }),
14206
+ ...normalized.create,
14207
+ };
14377
14208
  }
14378
14209
  if (legacy.rowActions !== undefined) {
14379
14210
  normalized.rowActions = legacy.rowActions;
14380
14211
  }
14212
+ if (legacy.contextStore !== undefined) {
14213
+ normalized.contextStore = legacy.contextStore;
14214
+ }
14381
14215
  return normalized;
14382
14216
  }
14383
14217
  /**
@@ -14413,6 +14247,9 @@ function normalizeEntityDataSelectorOptions(options) {
14413
14247
  if (nested.create) {
14414
14248
  normalized.create = { ...normalized.create, ...nested.create };
14415
14249
  }
14250
+ if (nested.contextStore !== undefined) {
14251
+ normalized.contextStore = nested.contextStore;
14252
+ }
14416
14253
  if (nested.rowActions !== undefined) {
14417
14254
  normalized.rowActions = nested.rowActions;
14418
14255
  }
@@ -14430,9 +14267,21 @@ class AXPEntityDataSelectorService {
14430
14267
  this.categoryTreeService = inject(AXPCategoryTreeService);
14431
14268
  this.translationService = inject(AXTranslationService);
14432
14269
  this.rowActionsService = inject(AXPEntityDataSelectorRowActionsService);
14270
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
14433
14271
  }
14434
14272
  //#endregion
14435
14273
  //#region ---- Public Methods ----
14274
+ /**
14275
+ * Resolves lookup `create.context` templates using the provided form context store.
14276
+ */
14277
+ async resolveCreateContext(template, contextStore) {
14278
+ if (!template || !contextStore) {
14279
+ return {};
14280
+ }
14281
+ const scope = buildLookupExpressionScope(contextStore);
14282
+ const resolved = await evaluateLookupCreateContext(template, this.expressionEvaluator, scope);
14283
+ return compactLookupCreateContext(resolved);
14284
+ }
14436
14285
  /**
14437
14286
  * Open entity data selector popup.
14438
14287
  * Accepts nested {@link AXPEntityDataSelectorOpenOptions} or deprecated flat {@link AXPEntityDataSelectorOptions}.
@@ -14448,8 +14297,8 @@ class AXPEntityDataSelectorService {
14448
14297
  * Execute Entity:Create and return created item.
14449
14298
  * Used by lookup widget and data selector for inline create.
14450
14299
  */
14451
- async executeEntityCreate(entity, mode) {
14452
- return this.executeCreate(entity, mode);
14300
+ async executeEntityCreate(entity, mode, initialData = {}) {
14301
+ return this.executeCreate(entity, mode, initialData);
14453
14302
  }
14454
14303
  /**
14455
14304
  * Normalize item's phones/emails for expose/display.
@@ -14512,7 +14361,16 @@ class AXPEntityDataSelectorService {
14512
14361
  const dataSource = this.createDataSource(options);
14513
14362
  const columns = this.createColumns(options);
14514
14363
  const searchFields = this.getSearchFields(options);
14515
- const allowCreate = options.create?.mode ?? this.getAllowCreate(options.entity);
14364
+ const hasCreateConfig = options.create !== undefined;
14365
+ const resolvedCreate = resolveLookupWidgetCreateOptions({
14366
+ create: options.create,
14367
+ allowCreate: options.create?.mode,
14368
+ });
14369
+ const allowCreate = hasCreateConfig
14370
+ ? resolvedCreate.enabled
14371
+ ? resolvedCreate.mode
14372
+ : 'none'
14373
+ : this.getAllowCreate(options.entity);
14516
14374
  const rowActions = options.rowActions
14517
14375
  ? this.rowActionsService.createHandler(options.entity, options.rowActions)
14518
14376
  : undefined;
@@ -14537,7 +14395,12 @@ class AXPEntityDataSelectorService {
14537
14395
  filter: options.filter?.value ? { value: options.filter.value } : undefined,
14538
14396
  create: {
14539
14397
  mode: allowCreate,
14540
- onCreate: allowCreate !== 'none' ? (mode) => this.executeCreate(options.entity, mode) : undefined,
14398
+ onCreate: allowCreate !== 'none'
14399
+ ? async (mode) => {
14400
+ const data = await this.resolveCreateContext(resolvedCreate.context, options.contextStore);
14401
+ return this.executeCreate(options.entity, mode, data);
14402
+ }
14403
+ : undefined,
14541
14404
  },
14542
14405
  rowActions,
14543
14406
  };
@@ -14685,7 +14548,7 @@ class AXPEntityDataSelectorService {
14685
14548
  /**
14686
14549
  * Execute Entity:Create and return created item
14687
14550
  */
14688
- async executeCreate(entity, mode) {
14551
+ async executeCreate(entity, mode, initialData = {}) {
14689
14552
  const quickCreate = entity.interfaces?.master?.create?.quickCreate;
14690
14553
  const options = {};
14691
14554
  if (mode === 'quick' && quickCreate) {
@@ -14709,7 +14572,7 @@ class AXPEntityDataSelectorService {
14709
14572
  title: entity.title,
14710
14573
  parentKey: entity.parentKey,
14711
14574
  },
14712
- data: {},
14575
+ data: initialData,
14713
14576
  options,
14714
14577
  },
14715
14578
  });
@@ -15184,6 +15047,9 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15184
15047
  this.formatService = inject(AXFormatService);
15185
15048
  this.translateService = inject(AXTranslationService);
15186
15049
  this.entityDataSelectorService = inject(AXPEntityDataSelectorService);
15050
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
15051
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
15052
+ this.contextStore = inject(AXPContextStore, { optional: true });
15187
15053
  //#endregion
15188
15054
  //#region ---- Inputs ----
15189
15055
  this.selectedItems = input.required(...(ngDevMode ? [{ debugName: "selectedItems" }] : /* istanbul ignore next */ []));
@@ -15196,7 +15062,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15196
15062
  this.validationRules = input.required(...(ngDevMode ? [{ debugName: "validationRules" }] : /* istanbul ignore next */ []));
15197
15063
  this.placeholder = input(...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ []));
15198
15064
  this.hasClearButton = input(false, ...(ngDevMode ? [{ debugName: "hasClearButton" }] : /* istanbul ignore next */ []));
15199
- this.allowCreate = input('none', ...(ngDevMode ? [{ debugName: "allowCreate" }] : /* istanbul ignore next */ []));
15065
+ this.resolvedCreate = input({ enabled: false, mode: 'none' }, ...(ngDevMode ? [{ debugName: "resolvedCreate" }] : /* istanbul ignore next */ []));
15200
15066
  this.allowUnselect = input(true, ...(ngDevMode ? [{ debugName: "allowUnselect" }] : /* istanbul ignore next */ []));
15201
15067
  // Entity and configuration data (for showSelector and searchByValue)
15202
15068
  this.entityDef = input.required(...(ngDevMode ? [{ debugName: "entityDef" }] : /* istanbul ignore next */ []));
@@ -15213,6 +15079,8 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15213
15079
  //#region ---- Internal State ----
15214
15080
  this.searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : /* istanbul ignore next */ []));
15215
15081
  this.isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
15082
+ this.itemLabels = signal({}, ...(ngDevMode ? [{ debugName: "itemLabels" }] : /* istanbul ignore next */ []));
15083
+ this.itemLabelsVersion = 0;
15216
15084
  //#endregion
15217
15085
  //#region ---- View Children ----
15218
15086
  this.tagBox = viewChild('tagBoxComponent', ...(ngDevMode ? [{ debugName: "tagBox" }] : /* istanbul ignore next */ []));
@@ -15235,6 +15103,31 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15235
15103
  }
15236
15104
  }
15237
15105
  }, ...(ngDevMode ? [{ debugName: "#focusEffect" }] : /* istanbul ignore next */ []));
15106
+ this.#itemLabelsEffect = effect(() => {
15107
+ void this.translateService.getActiveLang();
15108
+ const items = this.selectedItemsValue();
15109
+ const entityDef = this.entityDef()();
15110
+ const valueField = this.valueFieldValue();
15111
+ const version = ++this.itemLabelsVersion;
15112
+ void Promise.all(items.map(async (item) => {
15113
+ const id = String(get(item, valueField) ?? '');
15114
+ const label = await formatLookupItemDisplayAsync(item, entityDef, {
15115
+ displayFormat: this.displayFormatValue(),
15116
+ textField: this.displayFieldValue(),
15117
+ }, this.formatService, {
15118
+ expressionEvaluator: this.expressionEvaluator,
15119
+ contextEvalFactory: this.contextEvalFactory,
15120
+ translationService: this.translateService,
15121
+ locale: this.translateService.getActiveLang() ?? 'en-US',
15122
+ }, (value) => this.translateService.resolve(value));
15123
+ return [id, label];
15124
+ })).then((entries) => {
15125
+ if (version !== this.itemLabelsVersion) {
15126
+ return;
15127
+ }
15128
+ this.itemLabels.set(Object.fromEntries(entries));
15129
+ });
15130
+ }, ...(ngDevMode ? [{ debugName: "#itemLabelsEffect" }] : /* istanbul ignore next */ []));
15238
15131
  //#endregion
15239
15132
  //#region ---- Computed Properties ----
15240
15133
  this.tagBoxComponent = computed(() => this.tagBox(), ...(ngDevMode ? [{ debugName: "tagBoxComponent" }] : /* istanbul ignore next */ []));
@@ -15250,6 +15143,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15250
15143
  this.placeholderValue = computed(() => this.placeholder()?.() ?? '', ...(ngDevMode ? [{ debugName: "placeholderValue" }] : /* istanbul ignore next */ []));
15251
15144
  }
15252
15145
  #focusEffect;
15146
+ #itemLabelsEffect;
15253
15147
  focus() {
15254
15148
  this.shouldFocus.set(true);
15255
15149
  }
@@ -15315,11 +15209,9 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15315
15209
  }
15316
15210
  //#endregion
15317
15211
  //#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));
15212
+ getItemLabel(item) {
15213
+ const id = String(get(item, this.valueFieldValue()) ?? '');
15214
+ return this.itemLabels()[id] ?? '';
15323
15215
  }
15324
15216
  /**
15325
15217
  * Get current input value from tag box
@@ -15379,6 +15271,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15379
15271
  .map((item) => get(item, this.valueField()()))
15380
15272
  .filter((id) => id != null);
15381
15273
  try {
15274
+ const createOptions = this.resolvedCreate();
15382
15275
  const result = await this.entityDataSelectorService.open({
15383
15276
  entity,
15384
15277
  title: `${this.translateService.translateSync(entity.formats.plural ?? '')}`,
@@ -15387,7 +15280,12 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15387
15280
  filters: this.customFilter()(),
15388
15281
  parentFilters: this.parentFilters(),
15389
15282
  columns: this.columns()(),
15390
- allowCreate: this.allowCreate(),
15283
+ create: {
15284
+ enable: createOptions.enabled,
15285
+ mode: createOptions.mode,
15286
+ context: createOptions.context,
15287
+ },
15288
+ contextStore: this.contextStore ?? undefined,
15391
15289
  initialSearchTerm: searchTerm,
15392
15290
  selectedItemIds: selectedItemIds.length > 0 ? selectedItemIds : undefined,
15393
15291
  rowActions: this.rowActions(),
@@ -15413,7 +15311,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15413
15311
  this.clear();
15414
15312
  }
15415
15313
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetTagboxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
15416
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLookupWidgetTagboxComponent, isStandalone: true, selector: "axp-lookup-widget-tagbox", inputs: { selectedItems: { classPropertyName: "selectedItems", publicName: "selectedItems", isSignal: true, isRequired: true, transformFunction: null }, displayField: { classPropertyName: "displayField", publicName: "displayField", isSignal: true, isRequired: true, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: true, isRequired: true, transformFunction: null }, displayFormat: { classPropertyName: "displayFormat", publicName: "displayFormat", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: true, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: true, transformFunction: null }, validationRules: { classPropertyName: "validationRules", publicName: "validationRules", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hasClearButton: { classPropertyName: "hasClearButton", publicName: "hasClearButton", isSignal: true, isRequired: false, transformFunction: null }, allowCreate: { classPropertyName: "allowCreate", publicName: "allowCreate", isSignal: true, isRequired: false, transformFunction: null }, allowUnselect: { classPropertyName: "allowUnselect", publicName: "allowUnselect", isSignal: true, isRequired: false, transformFunction: null }, entityDef: { classPropertyName: "entityDef", publicName: "entityDef", isSignal: true, isRequired: true, transformFunction: null }, customFilter: { classPropertyName: "customFilter", publicName: "customFilter", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, parentFilters: { classPropertyName: "parentFilters", publicName: "parentFilters", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, onSetLoading: { classPropertyName: "onSetLoading", publicName: "onSetLoading", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { valueChanged: "valueChanged" }, providers: [
15314
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLookupWidgetTagboxComponent, isStandalone: true, selector: "axp-lookup-widget-tagbox", inputs: { selectedItems: { classPropertyName: "selectedItems", publicName: "selectedItems", isSignal: true, isRequired: true, transformFunction: null }, displayField: { classPropertyName: "displayField", publicName: "displayField", isSignal: true, isRequired: true, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: true, isRequired: true, transformFunction: null }, displayFormat: { classPropertyName: "displayFormat", publicName: "displayFormat", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: true, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: true, transformFunction: null }, validationRules: { classPropertyName: "validationRules", publicName: "validationRules", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hasClearButton: { classPropertyName: "hasClearButton", publicName: "hasClearButton", isSignal: true, isRequired: false, transformFunction: null }, resolvedCreate: { classPropertyName: "resolvedCreate", publicName: "resolvedCreate", isSignal: true, isRequired: false, transformFunction: null }, allowUnselect: { classPropertyName: "allowUnselect", publicName: "allowUnselect", isSignal: true, isRequired: false, transformFunction: null }, entityDef: { classPropertyName: "entityDef", publicName: "entityDef", isSignal: true, isRequired: true, transformFunction: null }, customFilter: { classPropertyName: "customFilter", publicName: "customFilter", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, parentFilters: { classPropertyName: "parentFilters", publicName: "parentFilters", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, onSetLoading: { classPropertyName: "onSetLoading", publicName: "onSetLoading", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { valueChanged: "valueChanged" }, providers: [
15417
15315
  {
15418
15316
  provide: LookupWidgetLookBase,
15419
15317
  useExisting: AXPLookupWidgetTagboxComponent,
@@ -15466,7 +15364,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
15466
15364
  </ax-tag-box>
15467
15365
  <ng-template #tagTemplate let-item let-index="index">
15468
15366
  <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>
15367
+ <span>{{ getItemLabel(item) }}</span>
15470
15368
  <button type="button" (click)="tagBoxComponent.removeItem(index)">
15471
15369
  <ax-icon class="ax-icon ax-icon-close"></ax-icon>
15472
15370
  </button>
@@ -15526,7 +15424,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
15526
15424
  </ax-tag-box>
15527
15425
  <ng-template #tagTemplate let-item let-index="index">
15528
15426
  <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>
15427
+ <span>{{ getItemLabel(item) }}</span>
15530
15428
  <button type="button" (click)="tagBoxComponent.removeItem(index)">
15531
15429
  <ax-icon class="ax-icon ax-icon-close"></ax-icon>
15532
15430
  </button>
@@ -15552,7 +15450,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
15552
15450
  },
15553
15451
  ],
15554
15452
  }]
15555
- }], propDecorators: { selectedItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedItems", required: true }] }], displayField: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayField", required: true }] }], valueField: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueField", required: true }] }], displayFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayFormat", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: true }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: true }] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: true }] }], validationRules: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationRules", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hasClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasClearButton", required: false }] }], allowCreate: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowCreate", required: false }] }], allowUnselect: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowUnselect", required: false }] }], entityDef: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityDef", required: true }] }], customFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "customFilter", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], parentFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentFilters", required: false }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], onSetLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "onSetLoading", required: true }] }], valueChanged: [{ type: i0.Output, args: ["valueChanged"] }], tagBox: [{ type: i0.ViewChild, args: ['tagBoxComponent', { isSignal: true }] }] } });
15453
+ }], propDecorators: { selectedItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedItems", required: true }] }], displayField: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayField", required: true }] }], valueField: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueField", required: true }] }], displayFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayFormat", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: true }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: true }] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: true }] }], validationRules: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationRules", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hasClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasClearButton", required: false }] }], resolvedCreate: [{ type: i0.Input, args: [{ isSignal: true, alias: "resolvedCreate", required: false }] }], allowUnselect: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowUnselect", required: false }] }], entityDef: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityDef", required: true }] }], customFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "customFilter", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], parentFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentFilters", required: false }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], onSetLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "onSetLoading", required: true }] }], valueChanged: [{ type: i0.Output, args: ["valueChanged"] }], tagBox: [{ type: i0.ViewChild, args: ['tagBoxComponent', { isSignal: true }] }] } });
15556
15454
 
15557
15455
  class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15558
15456
  constructor() {
@@ -15595,7 +15493,10 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15595
15493
  this.allowUnselect = computed(() => this.options()['allowUnselect'] ?? true, ...(ngDevMode ? [{ debugName: "allowUnselect" }] : /* istanbul ignore next */ []));
15596
15494
  this.look = computed(() => this.options()['look'] ?? 'lookup', ...(ngDevMode ? [{ debugName: "look" }] : /* istanbul ignore next */ []));
15597
15495
  this.displayField = computed(() => resolveLookupDisplayField(this.entityDef(), { textField: this.textField() }), ...(ngDevMode ? [{ debugName: "displayField" }] : /* istanbul ignore next */ []));
15598
- this.allowCreate = computed(() => this.options()['allowCreate'] ?? 'none', ...(ngDevMode ? [{ debugName: "allowCreate" }] : /* istanbul ignore next */ []));
15496
+ this.resolvedCreate = computed(() => resolveLookupWidgetCreateOptions({
15497
+ create: this.options()['create'],
15498
+ allowCreate: this.options()['allowCreate'],
15499
+ }), ...(ngDevMode ? [{ debugName: "resolvedCreate" }] : /* istanbul ignore next */ []));
15599
15500
  this.selectorRowActions = computed(() => this.options()['selectorRowActions'], ...(ngDevMode ? [{ debugName: "selectorRowActions" }] : /* istanbul ignore next */ []));
15600
15501
  this.valueField = computed(() => this.entityDef()?.properties.find((c) => c.name == 'id')?.name ?? 'id', ...(ngDevMode ? [{ debugName: "valueField" }] : /* istanbul ignore next */ []));
15601
15502
  this.displayFormat = computed(() => resolveLookupDisplayTemplate(this.entityDef(), {
@@ -15641,6 +15542,12 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15641
15542
  //#region ---- Business Logic Methods (Passed to Dumb Components) ----
15642
15543
  this.setLoading = (loading) => {
15643
15544
  this.isLoading.set(loading);
15545
+ if (loading) {
15546
+ this.beginHydration();
15547
+ }
15548
+ else {
15549
+ this.endHydration();
15550
+ }
15644
15551
  };
15645
15552
  /** @param syncContext When false, only updates UI (hydration/revert); skips context writes. */
15646
15553
  this.setItems = (items, syncContext = true) => {
@@ -15650,6 +15557,8 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15650
15557
  items = items.filter((item) => item != null);
15651
15558
  // Normalize phones/emails from repeater nested structure to { value: string }
15652
15559
  items = items.map((item) => this.entityDataSelectorService.normalizeItemContactArrays(item));
15560
+ /** Preserve raw entity fields (e.g. MLS maps) before display-field resolution for expose writes. */
15561
+ const itemsForExpose = cloneDeep(items);
15653
15562
  const displayField = this.displayField();
15654
15563
  items = items.map((item) => {
15655
15564
  const raw = get(item, displayField);
@@ -15664,10 +15573,32 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15664
15573
  }
15665
15574
  const keys = items.map((item) => get(item, this.valueField()));
15666
15575
  const text = items.map((item) => this.mlsResolver.resolve(get(item, displayField)));
15576
+ const newValue = this.singleOrMultiple(keys);
15577
+ const widgetPath = this.fullPath();
15578
+ const savedWidgetValue = widgetPath ? this.contextService.getSavedValue(widgetPath) : undefined;
15579
+ const selectionMatchesSaved = this.contextService.isSavedCommitted() &&
15580
+ widgetPath != null &&
15581
+ isSelectionValueEqual(newValue, savedWidgetValue);
15667
15582
  if (this.expose()) {
15668
- this.expoesItems();
15583
+ AXPDebugService.instance?.trace(FORM_DIRTY_TRACE_NS, 'lookup-widget', 'setItems expose', () => ({
15584
+ path: this.fullPath(),
15585
+ items: items.map((item) => get(item, this.valueField())),
15586
+ expose: this.expose(),
15587
+ selectionMatchesSaved,
15588
+ }));
15589
+ if (selectionMatchesSaved) {
15590
+ this.syncExposePathsToSavedBaseline();
15591
+ }
15592
+ else {
15593
+ this.expoesItems(itemsForExpose);
15594
+ }
15669
15595
  }
15670
- const newValue = this.singleOrMultiple(keys);
15596
+ AXPDebugService.instance?.trace(FORM_DIRTY_TRACE_NS, 'lookup-widget', 'setItems setValue', () => ({
15597
+ path: this.fullPath(),
15598
+ newValue,
15599
+ keys,
15600
+ syncContext,
15601
+ }));
15671
15602
  if (this.filterMode()) {
15672
15603
  this.setValue({
15673
15604
  value: newValue,
@@ -15680,12 +15611,16 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15680
15611
  else {
15681
15612
  this.setValue(newValue);
15682
15613
  }
15614
+ if (this.expose() && selectionMatchesSaved) {
15615
+ this.syncExposePathsToSavedBaseline();
15616
+ }
15683
15617
  };
15684
15618
  }
15685
15619
  #efEntity;
15686
15620
  #efValue;
15687
15621
  async findByValue() {
15688
15622
  this.isLoading.set(true);
15623
+ this.beginHydration();
15689
15624
  const rawValue = this.getValue();
15690
15625
  // When multiple is true, ensure we always work with arrays
15691
15626
  const values = this.multiple()
@@ -15694,6 +15629,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15694
15629
  if (!values.length) {
15695
15630
  this.setItems([], false);
15696
15631
  this.isLoading.set(false);
15632
+ this.endHydration();
15697
15633
  return;
15698
15634
  }
15699
15635
  try {
@@ -15726,6 +15662,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15726
15662
  }
15727
15663
  finally {
15728
15664
  this.isLoading.set(false);
15665
+ this.endHydration();
15729
15666
  }
15730
15667
  }
15731
15668
  //#region ---- Event Handlers from Dumb Components ----
@@ -15736,7 +15673,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15736
15673
  const entity = this.entityDef();
15737
15674
  if (!entity || !entity.commands?.create?.execute)
15738
15675
  return;
15739
- const mode = this.allowCreate();
15676
+ const { mode } = this.resolvedCreate();
15740
15677
  if (mode !== 'full' && mode !== 'quick')
15741
15678
  return;
15742
15679
  await this.executeCreate(mode);
@@ -15746,8 +15683,11 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15746
15683
  if (!entity || !entity.commands?.create?.execute)
15747
15684
  return;
15748
15685
  this.isLoading.set(true);
15686
+ this.beginHydration();
15749
15687
  try {
15750
- const createdItem = await this.entityDataSelectorService.executeEntityCreate(entity, mode);
15688
+ const { context } = this.resolvedCreate();
15689
+ const createData = await this.entityDataSelectorService.resolveCreateContext(context, this.contextService);
15690
+ const createdItem = await this.entityDataSelectorService.executeEntityCreate(entity, mode, createData);
15751
15691
  if (createdItem) {
15752
15692
  const currentItems = this.selectedItems();
15753
15693
  const valueField = this.valueField();
@@ -15767,6 +15707,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15767
15707
  }
15768
15708
  finally {
15769
15709
  this.isLoading.set(false);
15710
+ this.endHydration();
15770
15711
  }
15771
15712
  }
15772
15713
  /**
@@ -15775,9 +15716,31 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15775
15716
  * so e.g. `{ person: { educationLevel: { id, title } } }` would replace the entire `person`
15776
15717
  * object and drop sibling fields like `person.educationLevelId`, causing a value/effect loop.
15777
15718
  */
15778
- expoesItems() {
15719
+ syncExposePathsToSavedBaseline() {
15779
15720
  const exposeValue = castArray(this.expose());
15780
- const items = this.selectedItems();
15721
+ const parentPaths = new Set();
15722
+ exposeValue.forEach((item) => {
15723
+ const target = typeof item === 'string' ? item : item.target;
15724
+ if (target.includes('.')) {
15725
+ parentPaths.add(target.split('.').slice(0, -1).join('.'));
15726
+ }
15727
+ this.contextService.syncPathToSavedBaseline(target, { origin: 'system' });
15728
+ });
15729
+ const saved = this.contextService.saved();
15730
+ parentPaths.forEach((parentPath) => {
15731
+ if (!has(saved, parentPath)) {
15732
+ this.contextService.syncPathToSavedBaseline(parentPath, { origin: 'system' });
15733
+ }
15734
+ });
15735
+ AXPDebugService.instance?.trace(FORM_DIRTY_TRACE_NS, 'lookup-widget', 'syncExposePathsToSavedBaseline', () => ({
15736
+ path: this.fullPath(),
15737
+ expose: this.expose(),
15738
+ parentPaths: [...parentPaths],
15739
+ }));
15740
+ }
15741
+ expoesItems(sourceItems) {
15742
+ const exposeValue = castArray(this.expose());
15743
+ const items = sourceItems ?? this.selectedItems();
15781
15744
  const isEmpty = !items || items.length === 0;
15782
15745
  if (isEmpty) {
15783
15746
  const parentPaths = new Set();
@@ -15788,7 +15751,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15788
15751
  parentPaths.add(pathParts.slice(0, -1).join('.'));
15789
15752
  }
15790
15753
  else {
15791
- this.contextService.update(i, null);
15754
+ this.contextService.update(i, null, { origin: 'user' });
15792
15755
  }
15793
15756
  }
15794
15757
  else {
@@ -15797,25 +15760,25 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15797
15760
  parentPaths.add(pathParts.slice(0, -1).join('.'));
15798
15761
  }
15799
15762
  else {
15800
- this.contextService.update(i.target, null);
15763
+ this.contextService.update(i.target, null, { origin: 'user' });
15801
15764
  }
15802
15765
  }
15803
15766
  });
15804
15767
  parentPaths.forEach((parentPath) => {
15805
- this.contextService.update(parentPath, null);
15768
+ this.contextService.update(parentPath, null, { origin: 'user' });
15806
15769
  });
15807
15770
  return;
15808
15771
  }
15809
15772
  exposeValue.forEach((i) => {
15810
15773
  if (typeof i === 'string') {
15811
15774
  const values = items.map((item) => set({}, i, get(item, i)));
15812
- this.contextService.update(i, this.singleOrMultiple(values));
15775
+ this.contextService.update(i, this.singleOrMultiple(values), { origin: 'user' });
15813
15776
  }
15814
15777
  else {
15815
15778
  const values = this.multiple()
15816
15779
  ? items.map((item) => set({}, i.source, get(item, i.source)))
15817
15780
  : items.map((item) => get(item, i.source));
15818
- this.contextService.update(i.target, this.singleOrMultiple(values));
15781
+ this.contextService.update(i.target, this.singleOrMultiple(values), { origin: 'user' });
15819
15782
  }
15820
15783
  });
15821
15784
  }
@@ -15858,7 +15821,6 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15858
15821
  [placeholder]="placeholder"
15859
15822
  [validationRules]="validationRules"
15860
15823
  [hasClearButton]="hasClearButton()"
15861
- [allowCreate]="allowCreate()"
15862
15824
  [showItemTooltip]="showItemTooltip()"
15863
15825
  [isItemTruncated]="isItemTruncated()"
15864
15826
  (valueChanged)="handleComponentValueChanged($event)"
@@ -15877,7 +15839,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15877
15839
  [isLoading]="isLoading"
15878
15840
  [validationRules]="validationRules"
15879
15841
  [hasClearButton]="hasClearButton()"
15880
- [allowCreate]="allowCreate()"
15842
+ [resolvedCreate]="resolvedCreate()"
15881
15843
  [allowUnselect]="allowUnselect()"
15882
15844
  [entityDef]="entityDef"
15883
15845
  [customFilter]="customFilter"
@@ -15889,7 +15851,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15889
15851
  />
15890
15852
  }
15891
15853
  }
15892
- @if (allowCreate() === 'quick' || allowCreate() === 'full') {
15854
+ @if (resolvedCreate().enabled) {
15893
15855
  <div class="ax-sm">
15894
15856
  <ax-button
15895
15857
  color="primary"
@@ -15904,7 +15866,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
15904
15866
  }
15905
15867
  </div>
15906
15868
  }
15907
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPLookupWidgetSelectComponent, selector: "axp-lookup-widget-select", inputs: ["entityDef", "customFilter", "selectedItems", "displayField", "valueField", "disabled", "multiple", "validationRules", "placeholder", "hasClearButton", "allowCreate", "showItemTooltip", "isItemTruncated"], outputs: ["valueChanged"] }, { kind: "component", type: AXPLookupWidgetTagboxComponent, selector: "axp-lookup-widget-tagbox", inputs: ["selectedItems", "displayField", "valueField", "displayFormat", "disabled", "multiple", "isLoading", "validationRules", "placeholder", "hasClearButton", "allowCreate", "allowUnselect", "entityDef", "customFilter", "columns", "parentFilters", "rowActions", "onSetLoading"], outputs: ["valueChanged"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
15869
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPLookupWidgetSelectComponent, selector: "axp-lookup-widget-select", inputs: ["entityDef", "customFilter", "selectedItems", "displayField", "valueField", "disabled", "multiple", "validationRules", "placeholder", "hasClearButton", "allowCreate", "showItemTooltip", "isItemTruncated"], outputs: ["valueChanged"] }, { kind: "component", type: AXPLookupWidgetTagboxComponent, selector: "axp-lookup-widget-tagbox", inputs: ["selectedItems", "displayField", "valueField", "displayFormat", "disabled", "multiple", "isLoading", "validationRules", "placeholder", "hasClearButton", "resolvedCreate", "allowUnselect", "entityDef", "customFilter", "columns", "parentFilters", "rowActions", "onSetLoading"], outputs: ["valueChanged"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
15908
15870
  }
15909
15871
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetEditComponent, decorators: [{
15910
15872
  type: Component,
@@ -15927,7 +15889,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
15927
15889
  [placeholder]="placeholder"
15928
15890
  [validationRules]="validationRules"
15929
15891
  [hasClearButton]="hasClearButton()"
15930
- [allowCreate]="allowCreate()"
15931
15892
  [showItemTooltip]="showItemTooltip()"
15932
15893
  [isItemTruncated]="isItemTruncated()"
15933
15894
  (valueChanged)="handleComponentValueChanged($event)"
@@ -15946,7 +15907,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
15946
15907
  [isLoading]="isLoading"
15947
15908
  [validationRules]="validationRules"
15948
15909
  [hasClearButton]="hasClearButton()"
15949
- [allowCreate]="allowCreate()"
15910
+ [resolvedCreate]="resolvedCreate()"
15950
15911
  [allowUnselect]="allowUnselect()"
15951
15912
  [entityDef]="entityDef"
15952
15913
  [customFilter]="customFilter"
@@ -15958,7 +15919,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
15958
15919
  />
15959
15920
  }
15960
15921
  }
15961
- @if (allowCreate() === 'quick' || allowCreate() === 'full') {
15922
+ @if (resolvedCreate().enabled) {
15962
15923
  <div class="ax-sm">
15963
15924
  <ax-button
15964
15925
  color="primary"
@@ -16004,6 +15965,8 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16004
15965
  this.entityService = inject(AXPEntityService);
16005
15966
  this.entityResolver = inject(AXPEntityDefinitionRegistryService);
16006
15967
  this.queryExecutor = inject(AXPQueryExecutor);
15968
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
15969
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
16007
15970
  //#endregion
16008
15971
  //#region ---- View Children ----
16009
15972
  this.moreButton = viewChild('moreButton', ...(ngDevMode ? [{ debugName: "moreButton" }] : /* istanbul ignore next */ []));
@@ -16041,11 +16004,16 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16041
16004
  this.resolveError = signal(null, ...(ngDevMode ? [{ debugName: "resolveError" }] : /* istanbul ignore next */ []));
16042
16005
  this.summaryLabel = signal('', ...(ngDevMode ? [{ debugName: "summaryLabel" }] : /* istanbul ignore next */ []));
16043
16006
  this.popoverHeader = signal('', ...(ngDevMode ? [{ debugName: "popoverHeader" }] : /* istanbul ignore next */ []));
16007
+ this.mainItemLabels = signal([], ...(ngDevMode ? [{ debugName: "mainItemLabels" }] : /* istanbul ignore next */ []));
16008
+ this.lazyPopoverItemLabels = signal([], ...(ngDevMode ? [{ debugName: "lazyPopoverItemLabels" }] : /* istanbul ignore next */ []));
16044
16009
  this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : /* istanbul ignore next */ []));
16045
16010
  this.hydratedDisplayItems = signal(null, ...(ngDevMode ? [{ debugName: "hydratedDisplayItems" }] : /* istanbul ignore next */ []));
16046
16011
  this.hydrateRequestId = 0;
16012
+ this.mainLabelsVersion = 0;
16013
+ this.lazyPopoverLabelsVersion = 0;
16047
16014
  //#endregion
16048
16015
  //#region ---- Computed ----
16016
+ this.popoverItemLabels = computed(() => this.isHydratedStrategy() ? this.mainItemLabels() : this.lazyPopoverItemLabels(), ...(ngDevMode ? [{ debugName: "popoverItemLabels" }] : /* istanbul ignore next */ []));
16049
16017
  this.displayItems = computed(() => isNil(this.rawValue)
16050
16018
  ? []
16051
16019
  : castArray(this.rawValue)
@@ -16165,6 +16133,36 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16165
16133
  }
16166
16134
  void this.hydrateScalarIds(entityKey, values);
16167
16135
  });
16136
+ effect(() => {
16137
+ void this.translation.getActiveLang();
16138
+ this.entityDef();
16139
+ const items = this.allItems();
16140
+ const version = ++this.mainLabelsVersion;
16141
+ void this.resolveLabelsForItems(items).then((labels) => {
16142
+ if (version === this.mainLabelsVersion) {
16143
+ this.mainItemLabels.set(labels);
16144
+ }
16145
+ });
16146
+ });
16147
+ effect(() => {
16148
+ if (this.isHydratedStrategy()) {
16149
+ return;
16150
+ }
16151
+ void this.translation.getActiveLang();
16152
+ this.entityDef();
16153
+ const status = this.resolveStatus();
16154
+ const items = this.resolvedPopoverItems();
16155
+ if (status !== 'ready') {
16156
+ this.lazyPopoverItemLabels.set([]);
16157
+ return;
16158
+ }
16159
+ const version = ++this.lazyPopoverLabelsVersion;
16160
+ void this.resolveLabelsForItems(items).then((labels) => {
16161
+ if (version === this.lazyPopoverLabelsVersion) {
16162
+ this.lazyPopoverItemLabels.set(labels);
16163
+ }
16164
+ });
16165
+ });
16168
16166
  }
16169
16167
  //#endregion
16170
16168
  //#region ---- Public methods ----
@@ -16220,7 +16218,9 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16220
16218
  let resolvedTitle = '';
16221
16219
  if (headerItem != null && this.hasDisplayTextOnLookupValue(headerItem)) {
16222
16220
  resolvedTitle =
16223
- typeof headerItem === 'object' ? this.renderLookupLabel(headerItem) : this.formatDisplayValue(headerItem);
16221
+ typeof headerItem === 'object'
16222
+ ? await this.resolveItemLabel(headerItem)
16223
+ : this.formatDisplayValue(headerItem);
16224
16224
  }
16225
16225
  else if (!this.isMultiValueLookup()) {
16226
16226
  const rowText = this.getRowDisplayTextFromTextField();
@@ -16229,8 +16229,7 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16229
16229
  }
16230
16230
  }
16231
16231
  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);
16232
+ resolvedTitle = await this.resolveItemLabel(headerItem);
16234
16233
  if (isUnresolvedEntityDisplayTemplate(resolvedTitle)) {
16235
16234
  resolvedTitle = '';
16236
16235
  }
@@ -16296,8 +16295,22 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16296
16295
  const values = castArray(raw).filter((value) => value != null && value !== '');
16297
16296
  return values.length > 0 && values.every((value) => this.hasDisplayTextOnLookupValue(value));
16298
16297
  }
16299
- getDisplayRaw(item) {
16300
- if (item != null && typeof item === 'object' && this.translation.isValidMultiLanguageObject(item)) {
16298
+ getItemLabel(index) {
16299
+ return this.mainItemLabels()[index] ?? '';
16300
+ }
16301
+ getPopoverItemLabel(index) {
16302
+ return this.popoverItemLabels()[index] ?? '';
16303
+ }
16304
+ //#endregion
16305
+ //#region ---- Private methods ----
16306
+ async resolveLabelsForItems(items) {
16307
+ return Promise.all(items.map((item) => this.resolveItemLabel(item)));
16308
+ }
16309
+ async resolveItemLabel(item) {
16310
+ if (item == null) {
16311
+ return '';
16312
+ }
16313
+ if (typeof item === 'object' && this.translation.isValidMultiLanguageObject(item)) {
16301
16314
  return this.translation.resolve(item);
16302
16315
  }
16303
16316
  if (!this.isMultiValueLookup()) {
@@ -16306,16 +16319,19 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16306
16319
  return this.formatDisplayValue(rowText);
16307
16320
  }
16308
16321
  }
16309
- if (item != null && this.hasDisplayTextOnLookupValue(item)) {
16310
- if (typeof item === 'object') {
16311
- return this.renderLookupLabel(item);
16322
+ if (this.hasDisplayTextOnLookupValue(item)) {
16323
+ if (typeof item !== 'object') {
16324
+ return this.formatDisplayValue(item);
16312
16325
  }
16313
- return this.formatDisplayValue(item);
16314
16326
  }
16315
- return this.renderLookupLabel(item);
16327
+ const locale = this.translation.getActiveLang() ?? 'en-US';
16328
+ return formatLookupItemDisplayAsync(item, this.entityDef(), this.lookupDisplayOptions(), this.formatService, {
16329
+ expressionEvaluator: this.expressionEvaluator,
16330
+ contextEvalFactory: this.contextEvalFactory,
16331
+ translationService: this.translation,
16332
+ locale,
16333
+ }, (value) => this.translation.resolve(value));
16316
16334
  }
16317
- //#endregion
16318
- //#region ---- Private methods ----
16319
16335
  async refreshSummaryLabel(count) {
16320
16336
  const text = await this.translation.translateAsync('@general:widgets.lookup.column.items-count', {
16321
16337
  params: { count: String(count) },
@@ -16639,10 +16655,6 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16639
16655
  return !isNil(candidate) && candidate !== '' && !this.isLikelyEntityId(candidate);
16640
16656
  });
16641
16657
  }
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
16658
  formatDisplayValue(value) {
16647
16659
  if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
16648
16660
  return String(value);
@@ -16663,11 +16675,11 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
16663
16675
  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
16676
  }
16665
16677
  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 }); }
16678
+ 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
16679
  }
16668
16680
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetColumnComponent, decorators: [{
16669
16681
  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>" }]
16682
+ 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
16683
  }], 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
16684
 
16673
16685
  var lookupWidgetColumn_component = /*#__PURE__*/Object.freeze({
@@ -17220,8 +17232,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
17220
17232
  * Multi-source selector popup component
17221
17233
  */
17222
17234
  class AXPMultiSourceSelectorComponent extends AXBasePageComponent {
17235
+ //#endregion
17223
17236
  constructor() {
17224
- super(...arguments);
17237
+ super();
17225
17238
  //#region ---- Services & Dependencies ----
17226
17239
  this.entityDataSelectorService = inject(AXPEntityDataSelectorService);
17227
17240
  this.entityResolver = inject(AXPEntityDefinitionRegistryService);
@@ -17244,8 +17257,20 @@ class AXPMultiSourceSelectorComponent extends AXBasePageComponent {
17244
17257
  }, ...(ngDevMode ? [{ debugName: "activeSource" }] : /* istanbul ignore next */ []));
17245
17258
  this.selectedItems = signal([], ...(ngDevMode ? [{ debugName: "selectedItems" }] : /* istanbul ignore next */ []));
17246
17259
  this.AXPMultiSourceType = AXPMultiSourceType;
17260
+ setupPopupFooterKeyboardShortcuts(() => [
17261
+ {
17262
+ title: '@general:actions.cancel.title',
17263
+ command: 'cancel',
17264
+ handler: () => this.handleCancel(),
17265
+ },
17266
+ {
17267
+ title: '@general:actions.select.title',
17268
+ command: 'select',
17269
+ disabled: () => this.selectedItems().length === 0,
17270
+ handler: () => this.handleConfirm(),
17271
+ },
17272
+ ], { id: 'multi-source-selector-popup' });
17247
17273
  }
17248
- //#endregion
17249
17274
  //#region ---- Lifecycle ----
17250
17275
  ngOnInit() {
17251
17276
  super.ngOnInit();
@@ -17322,7 +17347,7 @@ class AXPMultiSourceSelectorComponent extends AXBasePageComponent {
17322
17347
  items: this.selectedItems(),
17323
17348
  });
17324
17349
  }
17325
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPMultiSourceSelectorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
17350
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPMultiSourceSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
17326
17351
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPMultiSourceSelectorComponent, isStandalone: true, selector: "axp-multi-source-selector", usesInheritance: true, ngImport: i0, template: `
17327
17352
  <div class="ax-flex ax-flex-col ax-h-full ax-overflow-hidden">
17328
17353
  @if (definition().searchStrategy === 'tabs') {
@@ -17471,7 +17496,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
17471
17496
  changeDetection: ChangeDetectionStrategy.OnPush,
17472
17497
  imports: [CommonModule, AXButtonModule, AXTabsModule, AXDecoratorModule, AXTranslationModule],
17473
17498
  }]
17474
- }] });
17499
+ }], ctorParameters: () => [] });
17475
17500
 
17476
17501
  var multiSourceSelector_component = /*#__PURE__*/Object.freeze({
17477
17502
  __proto__: null,
@@ -18906,7 +18931,7 @@ class AXPFileListComponent {
18906
18931
  // ACoreX
18907
18932
  AXFormModule }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXLabelModule }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type:
18908
18933
  // Platform
18909
- AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "look"] }, { kind: "pipe", type:
18934
+ AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "titleParams", "descriptionParams", "look"] }, { kind: "pipe", type:
18910
18935
  // Angular
18911
18936
  AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }] }); }
18912
18937
  }
@@ -21930,13 +21955,20 @@ class AXPPageDetailsConverter extends AXPBaseRelatedEntityConverter {
21930
21955
  const p = relatedEntity?.persistence || {};
21931
21956
  const strategy = p.strategy || 'embedded';
21932
21957
  const mappedTargets = Object.keys(p.map || {}).map((k) => (k || '').split('.')[0]);
21958
+ const excludeProperties = relatedEntity.excludeProperties && relatedEntity.excludeProperties.length > 0
21959
+ ? new Set(relatedEntity.excludeProperties)
21960
+ : undefined;
21933
21961
  const helpers = {
21934
21962
  ...baseHelpers,
21935
21963
  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));
21964
+ let props = baseHelpers.getPropertyByGroupId(groupId) ?? [];
21965
+ if (strategy === 'referenced' && mappedTargets.length > 0) {
21966
+ props = props.filter((prop) => !mappedTargets.includes(prop?.name ?? ''));
21967
+ }
21968
+ if (excludeProperties) {
21969
+ props = props.filter((prop) => !excludeProperties.has(prop.name ?? ''));
21970
+ }
21971
+ return props;
21940
21972
  },
21941
21973
  };
21942
21974
  const evaluateExpressions = async (actionData) => {
@@ -22054,18 +22086,70 @@ class AXPPageDetailsConverter extends AXPBaseRelatedEntityConverter {
22054
22086
  }
22055
22087
  createLoadFunction(entityDef, relatedEntity, evaluateExpressions) {
22056
22088
  return async (context) => {
22057
- const fn = entityDef?.queries.byKey?.execute;
22089
+ const conditions = relatedEntity.conditions ?? [];
22090
+ if (conditions.length > 0) {
22091
+ const evaluatedFilters = await Promise.all(conditions.map(async (c) => ({
22092
+ field: c.name,
22093
+ operator: c.operator,
22094
+ value: await evaluateExpressions(c.value),
22095
+ })));
22096
+ if (conditions.length === 1 && conditions[0].name === 'id') {
22097
+ const byKeyFn = entityDef?.queries?.byKey?.execute;
22098
+ const id = evaluatedFilters[0]?.value;
22099
+ const result = id ? await byKeyFn(id) : null;
22100
+ return { success: true, data: result ?? {} };
22101
+ }
22102
+ const listFn = entityDef?.queries?.list?.execute;
22103
+ const filter = evaluatedFilters.length === 1
22104
+ ? evaluatedFilters[0]
22105
+ : { logic: 'and', filters: evaluatedFilters };
22106
+ const page = await listFn({ skip: 0, take: 1, filter });
22107
+ const item = page?.items?.[0];
22108
+ const data = item ? { ...item } : {};
22109
+ if (!item) {
22110
+ for (const evaluated of evaluatedFilters) {
22111
+ if (evaluated.field) {
22112
+ set(data, evaluated.field, evaluated.value);
22113
+ }
22114
+ }
22115
+ }
22116
+ return { success: true, data };
22117
+ }
22118
+ const fn = entityDef?.queries?.byKey?.execute;
22058
22119
  const conditionValues = relatedEntity.conditions?.map((c) => c.value) ?? [];
22059
22120
  const evaluatedConditionValues = await Promise.all(conditionValues.map((c) => evaluateExpressions(c)));
22060
22121
  const id = evaluatedConditionValues[0];
22061
- const result = await fn(id);
22062
- return { success: true, data: result };
22122
+ const result = id ? await fn(id) : null;
22123
+ return { success: true, data: result ?? {} };
22063
22124
  };
22064
22125
  }
22065
22126
  createExecuteFunction(entityDef, actions, evaluateExpressions, converterContext) {
22066
22127
  return async (e, context) => {
22067
22128
  try {
22068
22129
  if (e.name === 'update-entity') {
22130
+ const recordId = context?.['id'];
22131
+ if (!recordId) {
22132
+ const createFn = entityDef?.commands?.create?.execute;
22133
+ const created = await createFn(context);
22134
+ if (created && typeof created === 'object' && 'success' in created) {
22135
+ const cmd = created;
22136
+ if (!cmd.success) {
22137
+ const errorText = commandMessageTextForError(cmd.message?.text) || 'Failed to create entity';
22138
+ return {
22139
+ success: false,
22140
+ message: cmd.message ?? { text: errorText },
22141
+ };
22142
+ }
22143
+ return {
22144
+ success: true,
22145
+ data: cmd.data ?? created,
22146
+ };
22147
+ }
22148
+ return {
22149
+ success: true,
22150
+ data: created,
22151
+ };
22152
+ }
22069
22153
  const fn = entityDef?.commands?.update?.execute;
22070
22154
  const result = await fn(context);
22071
22155
  if (result && typeof result === 'object' && 'success' in result) {
@@ -22327,11 +22411,16 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
22327
22411
  const excludeForUpdate = commandName === 'Entity:Update' &&
22328
22412
  relatedEntity.excludeProperties &&
22329
22413
  relatedEntity.excludeProperties.length > 0;
22414
+ const excludeForView = commandName === 'Entity:View' &&
22415
+ relatedEntity.excludeProperties &&
22416
+ relatedEntity.excludeProperties.length > 0;
22330
22417
  const mergedOptions = excludeForCreate
22331
22418
  ? { ...evaluatedOptions, excludeProperties: createExcludes }
22332
22419
  : excludeForUpdate
22333
22420
  ? { ...evaluatedOptions, excludeProperties: relatedEntity.excludeProperties }
22334
- : evaluatedOptions;
22421
+ : excludeForView
22422
+ ? { ...evaluatedOptions, excludeProperties: relatedEntity.excludeProperties }
22423
+ : evaluatedOptions;
22335
22424
  if (context.commandService.exists(commandName)) {
22336
22425
  // check options for evaluation
22337
22426
  await context.commandService.execute(commandName, {
@@ -22350,6 +22439,7 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
22350
22439
  },
22351
22440
  options: mergedOptions,
22352
22441
  metadata: action.metadata,
22442
+ ...(excludeForView ? { excludeProperties: relatedEntity.excludeProperties } : {}),
22353
22443
  });
22354
22444
  }
22355
22445
  else {
@@ -22880,6 +22970,7 @@ class AXPMainEntityContentBuilder {
22880
22970
  const tabListTabs = await this.buildTabLists(tabListEntities ?? [], rootContext, dependencies);
22881
22971
  // Build actions from single interface
22882
22972
  const actions = this.buildActions(entity, singleInterface);
22973
+ let cachedRootContext = rootContext;
22883
22974
  //console.log({ rootContext, dependencies });
22884
22975
  return {
22885
22976
  id: entity?.name ?? '',
@@ -22916,14 +23007,15 @@ class AXPMainEntityContentBuilder {
22916
23007
  },
22917
23008
  load: async (params) => {
22918
23009
  if (params?.forceRefresh) {
23010
+ cachedRootContext = await dependencies.reloadRootContext();
22919
23011
  return {
22920
23012
  success: true,
22921
- data: await dependencies.reloadRootContext(),
23013
+ data: cachedRootContext,
22922
23014
  };
22923
23015
  }
22924
23016
  return {
22925
23017
  success: true,
22926
- data: rootContext,
23018
+ data: cachedRootContext,
22927
23019
  };
22928
23020
  },
22929
23021
  execute: async (e, context) => {
@@ -23260,6 +23352,7 @@ class AXPLayoutAdapterFactory {
23260
23352
  this.layoutAdapterBuilder = layoutAdapterBuilder;
23261
23353
  this.filterOperatorMiddleware = filterOperatorMiddleware;
23262
23354
  this.pageComponentConverter = inject(AXPPageComponentConverter);
23355
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
23263
23356
  }
23264
23357
  async createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies) {
23265
23358
  const entity = await entityResolver.resolve(moduleName, entityName);
@@ -23313,9 +23406,7 @@ class AXPLayoutAdapterFactory {
23313
23406
  if (hidden && typeof hidden === 'string') {
23314
23407
  try {
23315
23408
  const scope = {
23316
- context: {
23317
- eval: (path) => get(rootContext, path),
23318
- },
23409
+ context: this.contextEvalFactory.createScope(rootContext),
23319
23410
  };
23320
23411
  const result = await dependencies.expressionEvaluator.evaluate({ hidden }, scope);
23321
23412
  hidden = result.hidden;
@@ -23477,9 +23568,7 @@ class AXPLayoutAdapterFactory {
23477
23568
  }
23478
23569
  const scope = {
23479
23570
  ...rootContext,
23480
- context: {
23481
- eval: (path) => get(rootContext, path),
23482
- },
23571
+ context: this.contextEvalFactory.createScope(rootContext),
23483
23572
  };
23484
23573
  const title = await dependencies.expressionEvaluator.evaluate(titleTemplate, scope);
23485
23574
  return title;
@@ -23494,27 +23583,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
23494
23583
  }]
23495
23584
  }], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }, { type: AXPMainEntityContentBuilder }, { type: AXPLayoutAdapterBuilder }, { type: i4$2.AXPFilterOperatorMiddlewareService }] });
23496
23585
 
23497
- const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver = inject(AXPEntityDefinitionRegistryService), expressionEvaluator = inject(AXPExpressionEvaluatorService), session = inject(AXPSessionService), formatService = inject(AXFormatService), workflowService = inject(AXPWorkflowService), commandService = inject(AXPCommandService), layoutAdapterFactory = inject(AXPLayoutAdapterFactory), router = inject(Router)) => {
23498
- const moduleName = route.parent?.paramMap.get('module');
23499
- const entityName = route.paramMap.get('entity');
23500
- const id = route.paramMap.get('id');
23501
- const dependencies = {
23502
- entityResolver,
23503
- expressionEvaluator,
23504
- session,
23505
- formatService,
23506
- workflowService,
23507
- commandService,
23508
- };
23509
- try {
23510
- return await layoutAdapterFactory.createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies);
23586
+ //#region ---- Entity Details View Adapter Loader ----
23587
+ class AXPEntityDetailsViewAdapterLoader {
23588
+ constructor() {
23589
+ //#region ---- Services & Dependencies ----
23590
+ this.entityResolver = inject(AXPEntityDefinitionRegistryService);
23591
+ this.layoutAdapterFactory = inject(AXPLayoutAdapterFactory);
23592
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
23593
+ this.session = inject(AXPSessionService);
23594
+ this.formatService = inject(AXFormatService);
23595
+ this.workflowService = inject(AXPWorkflowService);
23596
+ this.commandService = inject(AXPCommandService);
23511
23597
  }
23512
- catch (error) {
23513
- if (error instanceof AXPNotFoundError) {
23514
- return axpRedirectToNotFound(router);
23515
- }
23516
- throw error;
23598
+ //#endregion
23599
+ /**
23600
+ * Builds the details-view adapter for an entity record (definition, layout pages, root context).
23601
+ */
23602
+ async load(params) {
23603
+ const { moduleName, entityName, id } = params;
23604
+ const dependencies = {
23605
+ entityResolver: this.entityResolver,
23606
+ expressionEvaluator: this.expressionEvaluator,
23607
+ session: this.session,
23608
+ formatService: this.formatService,
23609
+ workflowService: this.workflowService,
23610
+ commandService: this.commandService,
23611
+ };
23612
+ return this.layoutAdapterFactory.createDetailsViewAdapter(this.entityResolver, moduleName, entityName, id, dependencies);
23517
23613
  }
23614
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailsViewAdapterLoader, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
23615
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailsViewAdapterLoader, providedIn: 'root' }); }
23616
+ }
23617
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailsViewAdapterLoader, decorators: [{
23618
+ type: Injectable,
23619
+ args: [{ providedIn: 'root' }]
23620
+ }] });
23621
+ const AXP_ENTITY_DETAILS_VIEW_ADAPTER_LOADER_PROVIDER = {
23622
+ provide: AXP_LAYOUT_DETAILS_VIEW_ADAPTER_LOADER,
23623
+ useExisting: AXPEntityDetailsViewAdapterLoader,
23518
23624
  };
23519
23625
 
23520
23626
  class AXPEntityPreloadFilterGuard {
@@ -23577,9 +23683,7 @@ const eventDispatchMiddleware = {
23577
23683
  if (ctx.op === 'create') {
23578
23684
  const createdData = ctx.result ? { ...ctx.data, id: ctx.result } : ctx.data;
23579
23685
  await dispatcher.dispatchInserted(ctx.entityName, { refType: ctx.entityName, data: createdData });
23580
- workflowEventService.dispatch(AXPRefreshEvent({
23581
- entity: ctx.entityName,
23582
- }));
23686
+ // List refresh is dispatched after create UI closes (Entity:Create command / create-entity workflow).
23583
23687
  }
23584
23688
  else if (ctx.op === 'update') {
23585
23689
  await dispatcher.dispatchUpdated(ctx.entityName, {
@@ -24244,8 +24348,8 @@ const AXPCrudModifier = {
24244
24348
  if (!command?.create) {
24245
24349
  command.create = {
24246
24350
  execute: async (data) => {
24247
- console.log('create', ctx.module.get() + '.' + ctx.name.get(), data);
24248
24351
  const res = await dataService.insertOne(data);
24352
+ //await delay(2000);
24249
24353
  return { id: res };
24250
24354
  },
24251
24355
  };
@@ -24265,7 +24369,9 @@ const AXPCrudModifier = {
24265
24369
  if (id == null || id === '') {
24266
24370
  throw new Error(`Update requires entity id (${entityKey})`);
24267
24371
  }
24268
- return await dataService.updateOne(id, patch);
24372
+ const updated = await dataService.updateOne(id, patch);
24373
+ //await delay(2000);
24374
+ return updated;
24269
24375
  },
24270
24376
  };
24271
24377
  }
@@ -24279,6 +24385,7 @@ const AXPCrudModifier = {
24279
24385
  queries.byKey = {
24280
24386
  execute: async (id) => {
24281
24387
  const data = await dataService.getOne(id);
24388
+ //await delay(1000);
24282
24389
  return data;
24283
24390
  },
24284
24391
  type: AXPEntityQueryType.Single,
@@ -24288,7 +24395,7 @@ const AXPCrudModifier = {
24288
24395
  queries.list = {
24289
24396
  execute: async (e) => {
24290
24397
  const res = await dataService.query(e);
24291
- // console.log('query', res, ctx.module.get() + '.' + ctx.name.get(), e);
24398
+ //console.log('query', res, ctx.module.get() + '.' + ctx.name.get(), e);
24292
24399
  return res;
24293
24400
  },
24294
24401
  type: AXPEntityQueryType.List,
@@ -24321,6 +24428,68 @@ class AXPEntityCommandSearchDefinitionProvider {
24321
24428
  function moduleNameToI18nScope(moduleName) {
24322
24429
  return moduleName.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');
24323
24430
  }
24431
+ //#region ---- Entity search definition builder ----
24432
+ function buildEntitySearchDefinition(entity, manifestRegistry) {
24433
+ const manifest = manifestRegistry.get(entity.module);
24434
+ const i18nScope = manifest?.i18n ?? moduleNameToI18nScope(entity.module);
24435
+ const searchTitleTemplate = entity.formats.searchResult?.title;
24436
+ const titleContext = buildEntitySearchTitleContext(entity, searchTitleTemplate);
24437
+ return {
24438
+ name: `Module.${entity.module}.${entity.name}`,
24439
+ title: `@${i18nScope}:module.title`,
24440
+ group: `Module.${entity.module}`,
24441
+ icon: entity.icon ?? 'fa-solid fa-objects-column',
24442
+ order: 4,
24443
+ format: {
24444
+ title: searchTitleTemplate,
24445
+ description: entity.formats.searchResult?.description ?? `${entity.module} / ${entity.title}`,
24446
+ id: '{{data.id}}',
24447
+ titleFallbackTemplates: titleContext.fallbackTemplates,
24448
+ titleFallbackFields: titleContext.fallbackFields,
24449
+ },
24450
+ actions: [
24451
+ {
24452
+ name: 'open-entity',
24453
+ type: AXPSystemActionType.View,
24454
+ priority: 'primary',
24455
+ },
24456
+ ],
24457
+ };
24458
+ }
24459
+ //#endregion
24460
+ //#region ---- Lazy resolver ----
24461
+ class AXPEntitySearchDefinitionLazyResolver {
24462
+ constructor() {
24463
+ this.entityResolver = inject(AXPEntityResolver);
24464
+ this.manifestRegistry = inject(AXPModuleManifestRegistry);
24465
+ this.resolved = new Map();
24466
+ }
24467
+ async resolve(definitionName) {
24468
+ const cached = this.resolved.get(definitionName);
24469
+ if (cached) {
24470
+ return cached;
24471
+ }
24472
+ const match = definitionName.match(/^Module\.([^.]+)\.(.+)$/);
24473
+ if (!match) {
24474
+ return null;
24475
+ }
24476
+ const [, moduleName, entityName] = match;
24477
+ await this.manifestRegistry.initialize();
24478
+ const entity = await this.entityResolver.get(moduleName, entityName);
24479
+ if (!entity) {
24480
+ return null;
24481
+ }
24482
+ const definition = buildEntitySearchDefinition(entity, this.manifestRegistry);
24483
+ this.resolved.set(definitionName, definition);
24484
+ return definition;
24485
+ }
24486
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntitySearchDefinitionLazyResolver, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
24487
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntitySearchDefinitionLazyResolver }); }
24488
+ }
24489
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntitySearchDefinitionLazyResolver, decorators: [{
24490
+ type: Injectable
24491
+ }] });
24492
+
24324
24493
  class AXPEntitySearchDefinitionProvider {
24325
24494
  constructor() {
24326
24495
  this.entityRegister = inject(AXPEntityDefinitionRegistryService);
@@ -24328,28 +24497,13 @@ class AXPEntitySearchDefinitionProvider {
24328
24497
  }
24329
24498
  async provide(context) {
24330
24499
  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
- },
24500
+ for (const entity of this.entityRegister.getAll()) {
24501
+ const definition = buildEntitySearchDefinition(entity, this.manifestRegistry);
24502
+ context.addDefinition(definition.name, definition.title, definition.group, definition.icon, definition.order, {
24503
+ actions: definition.actions,
24504
+ format: definition.format,
24351
24505
  });
24352
- });
24506
+ }
24353
24507
  }
24354
24508
  }
24355
24509
 
@@ -24455,9 +24609,9 @@ class AXPMiddlewareEntityStorageService extends AXPEntityStorageService {
24455
24609
  ...init,
24456
24610
  };
24457
24611
  }
24458
- async initial(entityName, collection, options) {
24612
+ async initial(entityName, collection) {
24459
24613
  const ctx = this.createCtx('initial', entityName, { data: collection });
24460
- return this.run(ctx, () => this.backend.initial(ctx.entityName, ctx.data, options));
24614
+ return this.run(ctx, () => this.backend.initial(ctx.entityName, ctx.data));
24461
24615
  }
24462
24616
  async getOne(entityName, id) {
24463
24617
  const key = getDedupKey('getOne', entityName, { id });
@@ -24641,6 +24795,7 @@ class AXPEntityCreatePopupAction extends AXPWorkflowAction {
24641
24795
  this.factory = inject(AXPEntityCreateViewModelFactory);
24642
24796
  this.config = inject(AXP_ENTITY_CONFIG_TOKEN);
24643
24797
  this.translateService = inject(AXTranslationService);
24798
+ this.settingsService = inject(AXPSettingsService);
24644
24799
  }
24645
24800
  async execute(context) {
24646
24801
  const [module, entity] = context.getVariable('entity').split('.');
@@ -24672,8 +24827,22 @@ class AXPEntityCreatePopupAction extends AXPWorkflowAction {
24672
24827
  const prevData = context.getVariable('data');
24673
24828
  const prevMeta = context.getVariable('meta');
24674
24829
  context.setVariable('data', { ...prevData, ...result.data.item });
24675
- if (entityRef.parentKey && result.data.item[entityRef.parentKey]) {
24676
- context.setVariable('meta', { ...prevMeta, refreshTargetId: result.data.item[entityRef.parentKey] });
24830
+ const createdItem = result.data.item;
24831
+ const highlightRowId = createdItem?.id ?? createdItem?._id;
24832
+ const { shouldRedirect, shouldHighlight } = await resolveEntityCreateListBehavior(this.settingsService, {
24833
+ redirect: process?.redirect,
24834
+ });
24835
+ context.setVariable('shouldRedirect', shouldRedirect);
24836
+ const meta = {
24837
+ ...prevMeta,
24838
+ resetPagination: true,
24839
+ ...(shouldHighlight && highlightRowId != null ? { highlightRowId } : {}),
24840
+ ...(entityRef.parentKey && createdItem[entityRef.parentKey]
24841
+ ? { refreshTargetId: createdItem[entityRef.parentKey] }
24842
+ : {}),
24843
+ };
24844
+ if (Object.keys(meta).length > 0) {
24845
+ context.setVariable('meta', meta);
24677
24846
  }
24678
24847
  }
24679
24848
  }
@@ -24724,7 +24893,7 @@ const AXPCreateEntityWorkflow = {
24724
24893
  action: 'AXPEntityCreateSubmittedAction',
24725
24894
  nextSteps: [
24726
24895
  {
24727
- conditions: [{ type: 'SINGLE', expression: 'context.getVariable("options")?.process?.redirect != false' }],
24896
+ conditions: [{ type: 'SINGLE', expression: 'context.getVariable("shouldRedirect") == true' }],
24728
24897
  nextStepId: 'show-entity',
24729
24898
  },
24730
24899
  ],
@@ -24741,6 +24910,9 @@ class AXPQuickEntityModifyPopupAction extends AXPWorkflowAction {
24741
24910
  this.popupService = inject(AXPopupService);
24742
24911
  this.platform = inject(AXPlatform);
24743
24912
  this.translateService = inject(AXTranslationService);
24913
+ this.formatService = inject(AXFormatService);
24914
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
24915
+ this.contextEvalFactory = inject(AXPContextEvalFactory);
24744
24916
  this.entityRegistery = inject(AXPEntityDefinitionRegistryService);
24745
24917
  this.config = inject(AXP_ENTITY_CONFIG_TOKEN);
24746
24918
  this.factory = inject(AXPEntityMasterUpdateViewModelFactory);
@@ -24750,10 +24922,8 @@ class AXPQuickEntityModifyPopupAction extends AXPWorkflowAction {
24750
24922
  const data = context.getVariable('data');
24751
24923
  const entityRef = await this.entityRegistery.resolve(moduleName, entityName);
24752
24924
  const { parentKey } = entityRef;
24753
- console.log(data);
24754
24925
  const { id } = data;
24755
- const { interfaces, title } = entityRef;
24756
- const properties = interfaces?.master?.update?.properties?.map((p) => p.name) || [];
24926
+ const properties = entityRef.interfaces?.master?.update?.properties?.map((p) => p.name) || [];
24757
24927
  const vm = await this.factory.create(moduleName, entityName, id, properties);
24758
24928
  const options = context.getVariable('options');
24759
24929
  const decoration = options?.['decoration'];
@@ -24763,12 +24933,11 @@ class AXPQuickEntityModifyPopupAction extends AXPWorkflowAction {
24763
24933
  if (parentKey) {
24764
24934
  context.setVariable('parentKey', parentKey);
24765
24935
  }
24766
- console.log(`${this.translateService.translateSync('entity.modify')}`);
24767
24936
  const com = await this.config.viewers.master.modify();
24768
24937
  const popup = await this.popupService.open(com, {
24769
24938
  title: headerTitle
24770
24939
  ? headerTitle
24771
- : `${this.translateService.translateSync('@general:actions.modify.title')} ${this.translateService.translateSync(entityRef.formats.individual)}`,
24940
+ : await resolveEntityModifyPopupTitle(entityRef, vm.context(), this.translateService, this.formatService, this.expressionEvaluator, this.contextEvalFactory),
24772
24941
  size: this.platform.is('Mobile') || this.platform.is('SM') ? 'full' : size ? size : 'md',
24773
24942
  data: {
24774
24943
  vm,
@@ -25031,6 +25200,7 @@ function routesFacory() {
25031
25200
  return config.viewers.root();
25032
25201
  },
25033
25202
  canActivate: [...AXP_PROTECTED_ROUTE_GUARDS],
25203
+ data: { rootLayout: true },
25034
25204
  children: [
25035
25205
  {
25036
25206
  path: ':module',
@@ -25064,18 +25234,11 @@ function routesFacory() {
25064
25234
  // },
25065
25235
  {
25066
25236
  path: 'e/:entity/:id/view',
25067
- resolve: { adapter: AXPLayoutDetailsViewRouteResolver },
25068
25237
  loadComponent: () => {
25069
25238
  return config.viewers.master.details();
25070
25239
  },
25071
25240
  canDeactivate: [axpDetailsViewCanDeactivateGuard],
25072
- runGuardsAndResolvers: (from, to) => {
25073
- const entityChanged = from.params['module'] !== to.params['module'] || from.params['entity'] !== to.params['entity'];
25074
- const idChanged = from.params['id'] !== to.params['id'];
25075
- const refreshChanged = from.queryParams['_ts'] !== to.queryParams['_ts'];
25076
- return entityChanged || idChanged || refreshChanged;
25077
- },
25078
- data: { reuse: false },
25241
+ data: { reuse: 'queryParamsChange' },
25079
25242
  },
25080
25243
  {
25081
25244
  path: 'e/:entity/:id',
@@ -25108,6 +25271,16 @@ class AXPEntityModule {
25108
25271
  AXPAttachmentsPluginModule, i1$3.AXPWorkflowModule, AXPWidgetCoreModule,
25109
25272
  LayoutBuilderModule] }); }
25110
25273
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityModule, providers: [
25274
+ AXP_ENTITY_DETAILS_VIEW_ADAPTER_LOADER_PROVIDER,
25275
+ {
25276
+ provide: AXP_REPEATER_ENTITY_BY_KEY_LOOKUP,
25277
+ useFactory: () => {
25278
+ const entityService = inject(AXPEntityService);
25279
+ return {
25280
+ byKey: (entityKey, id) => entityService.withEntity(entityKey).data().byKey(id),
25281
+ };
25282
+ },
25283
+ },
25111
25284
  { provide: AXP_WIDGET_DEFINITION_PROVIDER, useClass: AXPEntityWidgetsProvider, multi: true },
25112
25285
  {
25113
25286
  provide: ROUTES,
@@ -25124,6 +25297,10 @@ class AXPEntityModule {
25124
25297
  useClass: AXPEntityCommandSearchDefinitionProvider,
25125
25298
  multi: true,
25126
25299
  },
25300
+ {
25301
+ provide: AXP_SEARCH_DEFINITION_LAZY_RESOLVER,
25302
+ useClass: AXPEntitySearchDefinitionLazyResolver,
25303
+ },
25127
25304
  // Bind the middleware wrapper as the public storage service
25128
25305
  { provide: AXPEntityStorageService, useClass: AXPMiddlewareEntityStorageService },
25129
25306
  {
@@ -25295,6 +25472,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
25295
25472
  exports: [],
25296
25473
  declarations: [],
25297
25474
  providers: [
25475
+ AXP_ENTITY_DETAILS_VIEW_ADAPTER_LOADER_PROVIDER,
25476
+ {
25477
+ provide: AXP_REPEATER_ENTITY_BY_KEY_LOOKUP,
25478
+ useFactory: () => {
25479
+ const entityService = inject(AXPEntityService);
25480
+ return {
25481
+ byKey: (entityKey, id) => entityService.withEntity(entityKey).data().byKey(id),
25482
+ };
25483
+ },
25484
+ },
25298
25485
  { provide: AXP_WIDGET_DEFINITION_PROVIDER, useClass: AXPEntityWidgetsProvider, multi: true },
25299
25486
  {
25300
25487
  provide: ROUTES,
@@ -25311,6 +25498,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
25311
25498
  useClass: AXPEntityCommandSearchDefinitionProvider,
25312
25499
  multi: true,
25313
25500
  },
25501
+ {
25502
+ provide: AXP_SEARCH_DEFINITION_LAZY_RESOLVER,
25503
+ useClass: AXPEntitySearchDefinitionLazyResolver,
25504
+ },
25314
25505
  // Bind the middleware wrapper as the public storage service
25315
25506
  { provide: AXPEntityStorageService, useClass: AXPMiddlewareEntityStorageService },
25316
25507
  {
@@ -25618,5 +25809,5 @@ var getEntityDetails_query = /*#__PURE__*/Object.freeze({
25618
25809
  * Generated bundle index. Do not edit.
25619
25810
  */
25620
25811
 
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 };
25812
+ 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
25813
  //# sourceMappingURL=acorex-platform-layout-entity.mjs.map