@acorex/platform 21.0.0-next.37 → 21.0.0-next.40

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 (64) hide show
  1. package/fesm2022/acorex-platform-common.mjs +25 -3
  2. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  3. package/fesm2022/acorex-platform-core.mjs +18 -172
  4. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-domain.mjs +3 -0
  6. package/fesm2022/acorex-platform-domain.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-layout-builder.mjs +29 -13
  8. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-layout-components.mjs +62 -40
  10. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-layout-designer.mjs +209 -62
  12. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  13. package/fesm2022/acorex-platform-layout-entity.mjs +1072 -358
  14. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  15. package/fesm2022/acorex-platform-layout-views.mjs +171 -86
  16. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  17. package/fesm2022/acorex-platform-layout-widget-core.mjs +170 -63
  18. package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
  19. package/fesm2022/{acorex-platform-layout-widgets-file-list-popup.component-9uCkMxcc.mjs → acorex-platform-layout-widgets-file-list-popup.component-CDYAGBku.mjs} +5 -60
  20. package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-CDYAGBku.mjs.map +1 -0
  21. package/fesm2022/acorex-platform-layout-widgets.mjs +720 -415
  22. package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
  23. package/fesm2022/acorex-platform-runtime.mjs +120 -9
  24. package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
  25. package/fesm2022/{acorex-platform-themes-default-entity-master-create-view.component-Cvvr4HnL.mjs → acorex-platform-themes-default-entity-master-create-view.component-Cx1lLUaR.mjs} +3 -3
  26. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-Cx1lLUaR.mjs.map +1 -0
  27. package/fesm2022/{acorex-platform-themes-default-entity-master-modify-view.component-TYoLN1Jq.mjs → acorex-platform-themes-default-entity-master-modify-view.component-AOrcgjDF.mjs} +3 -3
  28. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-AOrcgjDF.mjs.map +1 -0
  29. package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-C2z5Lq9y.mjs → acorex-platform-themes-default-entity-master-single-view.component-BfCeUU5F.mjs} +3 -3
  30. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-BfCeUU5F.mjs.map +1 -0
  31. package/fesm2022/acorex-platform-themes-default.mjs +26 -14
  32. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  33. package/fesm2022/{acorex-platform-themes-shared-settings.provider-DSs1o1M6.mjs → acorex-platform-themes-shared-settings.provider-D13QB3Hr.mjs} +2 -2
  34. package/fesm2022/acorex-platform-themes-shared-settings.provider-D13QB3Hr.mjs.map +1 -0
  35. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-D566Kdvy.mjs +94 -0
  36. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-D566Kdvy.mjs.map +1 -0
  37. package/fesm2022/{acorex-platform-themes-shared-theme-color-chooser-view.component-BSmvnUVq.mjs → acorex-platform-themes-shared-theme-color-chooser-view.component-D7-rCGl7.mjs} +38 -16
  38. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-D7-rCGl7.mjs.map +1 -0
  39. package/fesm2022/acorex-platform-themes-shared.mjs +183 -84
  40. package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
  41. package/fesm2022/acorex-platform-workflow.mjs +75 -15
  42. package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
  43. package/package.json +1 -1
  44. package/types/acorex-platform-common.d.ts +11 -6
  45. package/types/acorex-platform-core.d.ts +67 -101
  46. package/types/acorex-platform-domain.d.ts +28 -2
  47. package/types/acorex-platform-layout-builder.d.ts +41 -28
  48. package/types/acorex-platform-layout-components.d.ts +4 -3
  49. package/types/acorex-platform-layout-designer.d.ts +56 -16
  50. package/types/acorex-platform-layout-entity.d.ts +180 -40
  51. package/types/acorex-platform-layout-views.d.ts +31 -29
  52. package/types/acorex-platform-layout-widget-core.d.ts +81 -52
  53. package/types/acorex-platform-layout-widgets.d.ts +42 -16
  54. package/types/acorex-platform-runtime.d.ts +156 -61
  55. package/types/acorex-platform-themes-default.d.ts +1 -0
  56. package/types/acorex-platform-workflow.d.ts +64 -52
  57. package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-9uCkMxcc.mjs.map +0 -1
  58. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-Cvvr4HnL.mjs.map +0 -1
  59. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-TYoLN1Jq.mjs.map +0 -1
  60. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-C2z5Lq9y.mjs.map +0 -1
  61. package/fesm2022/acorex-platform-themes-shared-settings.provider-DSs1o1M6.mjs.map +0 -1
  62. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-CHfrTtol.mjs +0 -65
  63. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-CHfrTtol.mjs.map +0 -1
  64. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-BSmvnUVq.mjs.map +0 -1
@@ -1,17 +1,17 @@
1
1
  import { AXToastService } from '@acorex/components/toast';
2
2
  import * as i6 from '@acorex/core/translation';
3
- import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
3
+ import { AXTranslationService, AXTranslationModule, resolveMultiLanguageString } from '@acorex/core/translation';
4
4
  import * as i4$4 from '@acorex/platform/common';
5
5
  import { AXPSettingsService, AXPCommonSettings, AXPFilterOperatorMiddlewareService, AXPEntityCommandScope, getEntityInfo, AXPRefreshEvent, AXPReloadEvent, AXPCleanNestedFilters, AXPDefaultMultiLanguageConfigService, withDefaultMultiLanguageOnWidgetNodeTree, AXPEntityQueryType, AXPWorkflowNavigateAction, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER, AXPMenuItemsDataSourceDefinition } from '@acorex/platform/common';
6
6
  import * as i0 from '@angular/core';
7
- import { InjectionToken, inject, Injector, runInInjectionContext, Injectable, input, viewChild, signal, ElementRef, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent, computed, ChangeDetectorRef, effect, Input, afterNextRender, untracked, ViewEncapsulation, viewChildren, linkedSignal, HostBinding, output, NgModule, makeEnvironmentProviders } from '@angular/core';
7
+ import { InjectionToken, inject, Injector, runInInjectionContext, Injectable, input, viewChild, signal, computed, ElementRef, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent, ChangeDetectorRef, effect, Input, afterNextRender, untracked, ViewEncapsulation, viewChildren, linkedSignal, HostBinding, output, NgModule, makeEnvironmentProviders } from '@angular/core';
8
8
  import { Subject, takeUntil } from 'rxjs';
9
9
  import { AXPLayoutBuilderService, LayoutBuilderModule } from '@acorex/platform/layout/builder';
10
- import { AXPDeviceService, AXPBroadcastEventService, AXPResolveMultiLanguageStringPipe, applyFilterArray, applySortArray, resolveActionLook, AXPExpressionEvaluatorService, AXPDistributedEventListenerService, AXPPlatformScope, resolveMultiLanguageString, AXPMultiLanguageStringResolverService, AXHighlightService, extractValue, setSmart, getChangedPaths, AXPColumnWidthService, AXPModuleManifestRegistry, defaultColumnWidthProvider, AXP_COLUMN_WIDTH_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXPModuleManifestsDataSourceDefinition, AXPSystemActionType } from '@acorex/platform/core';
10
+ import { AXPDeviceService, AXPBroadcastEventService, applyFilterArray, applySortArray, resolveActionLook, AXPExpressionEvaluatorService, AXPDistributedEventListenerService, AXPPlatformScope, AXHighlightService, extractValue, setSmart, getChangedPaths, objectKeyValueTransforms, AXPColumnWidthService, AXPModuleManifestRegistry, defaultColumnWidthProvider, AXP_COLUMN_WIDTH_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXPModuleManifestsDataSourceDefinition, AXPSystemActionType } from '@acorex/platform/core';
11
11
  import { merge, get, castArray, cloneDeep, set, orderBy, omit, isNil, isEmpty, isEqual } from 'lodash-es';
12
12
  import { AXPSessionService, AXPAuthGuard, AXPPermissionDefinitionsDataSourceDefinition } from '@acorex/platform/auth';
13
13
  import { Router, ActivatedRoute, RouterModule, ROUTES } from '@angular/router';
14
- import { defineCommand, AXPCommandService, AXPQueryService, AXPQueryExecutor, provideCommandSetups, provideQuerySetups, AXPCommandRegistry, AXPQueryRegistry } from '@acorex/platform/runtime';
14
+ import { defineCommand, AXP_COMMAND_DEFINITION_CATEGORY_ENTITY, AXPCommandService, AXPQueryService, AXPQueryExecutor, provideCommandSetups, provideQuerySetups, AXPCommandRegistry, AXPQueryRegistry } from '@acorex/platform/runtime';
15
15
  import * as i1 from '@acorex/components/button';
16
16
  import { AXButtonModule } from '@acorex/components/button';
17
17
  import * as i4 from '@acorex/components/loading';
@@ -119,6 +119,28 @@ const AXP_ENTITY_ACTION_PLUGIN = new InjectionToken('AXP_ENTITY_ACTION_PLUGIN');
119
119
  function createModifierContext(entity) {
120
120
  const ctx = {
121
121
  entity,
122
+ plugins: {
123
+ list: () => entity.plugins ?? [],
124
+ add: (...items) => {
125
+ entity.plugins ??= [];
126
+ entity.plugins.push(...items);
127
+ return ctx;
128
+ },
129
+ remove: (predicate) => {
130
+ if (entity.plugins)
131
+ entity.plugins = entity.plugins.filter((p) => !predicate(p));
132
+ return ctx;
133
+ },
134
+ find: (name) => ({
135
+ get: () => entity.plugins?.find((p) => p.name === name),
136
+ update: (updater) => {
137
+ const index = entity.plugins?.findIndex((p) => p.name === name);
138
+ if (index !== undefined && index !== -1 && entity.plugins)
139
+ entity.plugins[index] = updater(entity.plugins[index]);
140
+ return ctx;
141
+ },
142
+ }),
143
+ },
122
144
  title: {
123
145
  get: () => entity.title,
124
146
  set: (newTitle) => {
@@ -282,7 +304,7 @@ function createModifierContext(entity) {
282
304
  },
283
305
  },
284
306
  modify: {
285
- get: () => entity.interfaces?.master?.create,
307
+ get: () => entity.interfaces?.master?.update,
286
308
  update: (updater) => {
287
309
  entity.interfaces ??= {};
288
310
  entity.interfaces.master ??= {};
@@ -781,6 +803,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
781
803
  }]
782
804
  }] });
783
805
 
806
+ /**
807
+ * Maps entity property `description` (or any i18n key / multi-language payload) to `form-field`
808
+ * widget options. Returns `undefined` when there is nothing to show.
809
+ */
810
+ function hintFormFieldOptionsFromDescription(description) {
811
+ if (description == null) {
812
+ return undefined;
813
+ }
814
+ if (typeof description === 'string' && description.trim() === '') {
815
+ return undefined;
816
+ }
817
+ return { hint: description, hintDisplayMode: 'icon' };
818
+ }
819
+ //#endregion
820
+
784
821
  //#endregion
785
822
  class AXPEntityFormBuilderService {
786
823
  constructor() {
@@ -851,6 +888,9 @@ class InterfaceSelector {
851
888
  recordId = data['id'] || data['_id'];
852
889
  }
853
890
  const filter = new PropertyFilter(this.entityRegistry, this.layoutBuilder, this.deviceService, this.fullName, 'update', recordId, this.formBuilderService);
891
+ if (Object.keys(initialData).length > 0) {
892
+ filter.context(initialData);
893
+ }
854
894
  return filter;
855
895
  }
856
896
  single(data) {
@@ -936,21 +976,16 @@ class PropertyFilter {
936
976
  }
937
977
  async show() {
938
978
  const dialog = await this.buildDialog();
939
- // Context: load record by id for update/single and merge with provided context (context overrides)
979
+ // Context: always load by key when we have a record id (authoritative full row), then merge any
980
+ // caller/list row context. Skipping fetch when initialContext was non-empty left dialogs without
981
+ // fields not present on the passed row (e.g. Entity:View single() with partial list payload).
940
982
  let baseContext = {};
941
- // Only fetch by key if we don't already have initial data
942
- const hasInitialData = this.initialContext && Object.keys(this.initialContext).length > 0;
943
- if ((this.kind === 'update' || this.kind === 'single') && !hasInitialData) {
983
+ if ((this.kind === 'update' || this.kind === 'single') && this.recordId) {
944
984
  const id = this.recordId;
945
- if (!id) {
946
- throw new Error(`Record id is required for ${this.kind}().`);
947
- }
948
- // Use the public method if service is available, otherwise fallback to direct entity access
949
985
  if (this.formBuilderService) {
950
986
  baseContext = await this.formBuilderService.getRecordById(this.fullName, id);
951
987
  }
952
988
  else {
953
- // Fallback to original implementation if service is not available
954
989
  const { moduleName, entityName } = parseEntityFullName(this.fullName);
955
990
  const entity = await this.entityRegistry.resolve(moduleName, entityName);
956
991
  try {
@@ -964,7 +999,7 @@ class PropertyFilter {
964
999
  }
965
1000
  }
966
1001
  }
967
- const effectiveContext = merge({}, baseContext, this.initialContext);
1002
+ const effectiveContext = merge({}, this.initialContext, baseContext);
968
1003
  dialog.setContext(effectiveContext);
969
1004
  return await dialog.show();
970
1005
  }
@@ -1185,9 +1220,24 @@ class PropertyFilter {
1185
1220
  }
1186
1221
  const sectionLayout = section.layout ?? undefined;
1187
1222
  grid.item(sectionLayout, (fs) => {
1223
+ const sectionVisible = section.layout?.visible;
1224
+ if (sectionVisible !== undefined && sectionVisible !== null) {
1225
+ fs.visible(sectionVisible);
1226
+ }
1188
1227
  fs.setLook('fieldset');
1189
1228
  fs.setTitle((getGroupTitleFromList(allGroups, groupId) || groupId));
1190
1229
  fs.setCols(12);
1230
+ // Section label visibility (fieldset title/legend)
1231
+ // Prefer current interface (create/update/single) section layout, fallback to master.single section layout.
1232
+ const sectionLabelVisible = section?.layout?.label?.visible ??
1233
+ entity?.interfaces?.master?.single?.sections?.find((s) => s?.id === groupId)?.layout?.label
1234
+ ?.visible;
1235
+ if (sectionLabelVisible === false) {
1236
+ // Different parts of the system refer to this concept with different keys.
1237
+ // - Fieldset view renderer currently uses `showTitle`
1238
+ // - Fieldset designer/property system uses `showHeader`
1239
+ fs.setOptions({ showTitle: false, showHeader: false });
1240
+ }
1191
1241
  // Sort properties by order within section
1192
1242
  const orderedProps = [...sectionProps].sort((a, b) => {
1193
1243
  const aOrder = a.__order ?? Infinity;
@@ -1218,6 +1268,10 @@ class PropertyFilter {
1218
1268
  if (fieldLayout?.label?.visible === false) {
1219
1269
  field.setShowLabel(false);
1220
1270
  }
1271
+ const hintOpts = hintFormFieldOptionsFromDescription(prop.description);
1272
+ if (hintOpts) {
1273
+ field.setOptions(hintOpts);
1274
+ }
1221
1275
  const widgetType = prop.schema?.interface?.type || '';
1222
1276
  const widgetOptions = buildWidgetOptions(prop);
1223
1277
  const extendedProperties = buildWidgetExtendedProperties(prop);
@@ -1909,6 +1963,7 @@ const axpCreateEntityCommandDefinition = defineCommand({
1909
1963
  summary: 'Dialog submit persists entity; navigation/toast behavior per entity form builder and settings.',
1910
1964
  derivesFrom: 'AXPExecuteCommandResult<any> from entity form chain and AXPOpenEntityDetailsCommand',
1911
1965
  },
1966
+ capabilities: ['ai'],
1912
1967
  ai: {
1913
1968
  shortDescription: 'Opens create dialog with pre-filled data; execution waits until the user submits or cancels, then returns—use for human-confirmed inserts into mock storage.',
1914
1969
  usage: {
@@ -1923,6 +1978,7 @@ const axpCreateEntityCommandDefinition = defineCommand({
1923
1978
  tags: ['entity', 'create', 'form', 'dialog', 'human-in-the-loop', 'mock', 'entity-storage', 'wait-user'],
1924
1979
  toolInputDefaults: { ...axpCreateEntityAiToolInputDefaults },
1925
1980
  },
1981
+ categories: [AXP_COMMAND_DEFINITION_CATEGORY_ENTITY],
1926
1982
  });
1927
1983
 
1928
1984
  class AXPUpdateEntityCommand {
@@ -2191,6 +2247,18 @@ class AXPEntityDetailPopoverComponent {
2191
2247
  this.entityDetails = signal(null, ...(ngDevMode ? [{ debugName: "entityDetails" }] : /* istanbul ignore next */ []));
2192
2248
  this.isLoadingDetails = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingDetails" }] : /* istanbul ignore next */ []));
2193
2249
  this.isDetailPopoverOpen = signal(false, ...(ngDevMode ? [{ debugName: "isDetailPopoverOpen" }] : /* istanbul ignore next */ []));
2250
+ /**
2251
+ * Stable list of property widgets for the template. Must be a signal (computed), not a method:
2252
+ * calling a method from the template rebuilds nodes every CD cycle and can make the widget renderer loop.
2253
+ */
2254
+ this.entityPropertiesWithWidgets = computed(() => {
2255
+ const details = this.entityDetails();
2256
+ const data = details?.entityData;
2257
+ const entityDefinition = details?.entityDefinition;
2258
+ if (!data || !entityDefinition?.properties)
2259
+ return [];
2260
+ return this.buildEntityPropertiesWithWidgets(data, entityDefinition, this.textField(), this.valueField());
2261
+ }, ...(ngDevMode ? [{ debugName: "entityPropertiesWithWidgets" }] : /* istanbul ignore next */ []));
2194
2262
  }
2195
2263
  //#endregion
2196
2264
  //#region ---- Public Methods ----
@@ -2345,16 +2413,12 @@ class AXPEntityDetailPopoverComponent {
2345
2413
  }
2346
2414
  return 0;
2347
2415
  }
2348
- getEntityPropertiesWithWidgets() {
2349
- const data = this.entityDetails()?.entityData;
2350
- const entityDefinition = this.entityDetails()?.entityDefinition;
2351
- if (!data || !entityDefinition?.properties)
2352
- return [];
2416
+ buildEntityPropertiesWithWidgets(data, entityDefinition, textFieldValue, valueFieldValue) {
2353
2417
  // Use properties (not columns) for correct titles and schema; columns may have dataPath that doesn't match
2354
- const importantProperties = entityDefinition.properties
2418
+ return entityDefinition.properties
2355
2419
  .filter((prop) => {
2356
2420
  // Exclude technical fields
2357
- if (prop.name === 'id' || prop.name === this.textField() || prop.name === this.valueField()) {
2421
+ if (prop.name === 'id' || prop.name === textFieldValue || prop.name === valueFieldValue) {
2358
2422
  return false;
2359
2423
  }
2360
2424
  // Only include properties that have a meaningful value (using get for dotted paths)
@@ -2422,7 +2486,6 @@ class AXPEntityDetailPopoverComponent {
2422
2486
  node: widgetNode,
2423
2487
  };
2424
2488
  });
2425
- return importantProperties;
2426
2489
  }
2427
2490
  /**
2428
2491
  * Resolves the data path for a property. For lookups with expose, returns the expanded path
@@ -2445,19 +2508,11 @@ class AXPEntityDetailPopoverComponent {
2445
2508
  return prop.name;
2446
2509
  }
2447
2510
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailPopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2448
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPEntityDetailPopoverComponent, isStandalone: true, selector: "axp-entity-detail-popover", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: true, transformFunction: null }, entityId: { classPropertyName: "entityId", publicName: "entityId", isSignal: true, isRequired: true, transformFunction: null }, textField: { classPropertyName: "textField", publicName: "textField", isSignal: true, isRequired: false, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: true, isRequired: false, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: false, transformFunction: null }, breadcrumb: { classPropertyName: "breadcrumb", publicName: "breadcrumb", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "detailPopover", first: true, predicate: ["detailPopover"], descendants: true, isSignal: true }], ngImport: i0, template: "<ax-popover [openOn]=\"'manual'\" #detailPopover (openChange)=\"onDetailPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-border ax-rounded-lg ax-shadow-lg ax-p-4 ax-min-w-[400px]\">\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 {{\n (entityDetails()?.entityData?.[textField()] ?? item()?.[textField()]) | axpResolveMultiLanguageString\n }}\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-flex ax-items-center ax-justify-center ax-py-8\">\n <ax-loading>Loading details...</ax-loading>\n </div>\n } @else if (entityDetails()) {\n <div class=\"ax-space-y-3 ax-mb-4\">\n <!-- Important Entity Data -->\n @if (entityDetails()?.entityData) {\n <axp-widgets-container [context]=\"entityDetails()?.entityData\">\n <div class=\"ax-space-y-2\">\n @for (item of getEntityPropertiesWithWidgets(); track item.name) {\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <span class=\"ax-text-sm ax-font-medium\">{{ item.title | translate | async }}:</span>\n <div class=\"ax-flex-1 ax-ml-2 ax-max-w-48\">\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</ax-popover>\n", 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: AXPopoverModule }, { kind: "component", type: i2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "repositionOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i3.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i3.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AXPResolveMultiLanguageStringPipe, name: "axpResolveMultiLanguageString" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2511
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPEntityDetailPopoverComponent, isStandalone: true, selector: "axp-entity-detail-popover", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: true, transformFunction: null }, entityId: { classPropertyName: "entityId", publicName: "entityId", isSignal: true, isRequired: true, transformFunction: null }, textField: { classPropertyName: "textField", publicName: "textField", isSignal: true, isRequired: false, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: true, isRequired: false, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: false, transformFunction: null }, breadcrumb: { classPropertyName: "breadcrumb", publicName: "breadcrumb", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "detailPopover", first: true, predicate: ["detailPopover"], descendants: true, isSignal: true }], ngImport: i0, template: "<ax-popover [openOn]=\"'manual'\" #detailPopover (openChange)=\"onDetailPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-border ax-rounded-lg ax-shadow-lg ax-p-4 ax-min-w-[400px]\">\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 {{ entityDetails()?.entityData?.[textField()] ?? item()?.[textField()] | translate | async }}\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-flex ax-items-center ax-justify-center ax-py-8\">\n <ax-loading>Loading details...</ax-loading>\n </div>\n } @else if (entityDetails()) {\n <div class=\"ax-space-y-3 ax-mb-4\">\n <!-- Important Entity Data -->\n @if (entityDetails()?.entityData) {\n <axp-widgets-container [context]=\"entityDetails()?.entityData\">\n <div class=\"ax-space-y-2\">\n @for (item of entityPropertiesWithWidgets(); track item.name) {\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <span class=\"ax-text-sm ax-font-medium\">{{ item.title | translate | async }}:</span>\n <div class=\"ax-flex-1 ax-ml-2 ax-max-w-48\">\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</ax-popover>\n", 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: AXPopoverModule }, { kind: "component", type: i2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "repositionOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i3.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i3.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2449
2512
  }
2450
2513
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailPopoverComponent, decorators: [{
2451
2514
  type: Component,
2452
- args: [{ selector: 'axp-entity-detail-popover', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
2453
- CommonModule,
2454
- AXButtonModule,
2455
- AXPopoverModule,
2456
- AXPWidgetCoreModule,
2457
- AXTranslationModule,
2458
- AXLoadingModule,
2459
- AXPResolveMultiLanguageStringPipe,
2460
- ], template: "<ax-popover [openOn]=\"'manual'\" #detailPopover (openChange)=\"onDetailPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-border ax-rounded-lg ax-shadow-lg ax-p-4 ax-min-w-[400px]\">\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 {{\n (entityDetails()?.entityData?.[textField()] ?? item()?.[textField()]) | axpResolveMultiLanguageString\n }}\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-flex ax-items-center ax-justify-center ax-py-8\">\n <ax-loading>Loading details...</ax-loading>\n </div>\n } @else if (entityDetails()) {\n <div class=\"ax-space-y-3 ax-mb-4\">\n <!-- Important Entity Data -->\n @if (entityDetails()?.entityData) {\n <axp-widgets-container [context]=\"entityDetails()?.entityData\">\n <div class=\"ax-space-y-2\">\n @for (item of getEntityPropertiesWithWidgets(); track item.name) {\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <span class=\"ax-text-sm ax-font-medium\">{{ item.title | translate | async }}:</span>\n <div class=\"ax-flex-1 ax-ml-2 ax-max-w-48\">\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</ax-popover>\n" }]
2515
+ args: [{ selector: 'axp-entity-detail-popover', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, AXButtonModule, AXPopoverModule, AXPWidgetCoreModule, AXTranslationModule, AXLoadingModule], template: "<ax-popover [openOn]=\"'manual'\" #detailPopover (openChange)=\"onDetailPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-border ax-rounded-lg ax-shadow-lg ax-p-4 ax-min-w-[400px]\">\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 {{ entityDetails()?.entityData?.[textField()] ?? item()?.[textField()] | translate | async }}\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-flex ax-items-center ax-justify-center ax-py-8\">\n <ax-loading>Loading details...</ax-loading>\n </div>\n } @else if (entityDetails()) {\n <div class=\"ax-space-y-3 ax-mb-4\">\n <!-- Important Entity Data -->\n @if (entityDetails()?.entityData) {\n <axp-widgets-container [context]=\"entityDetails()?.entityData\">\n <div class=\"ax-space-y-2\">\n @for (item of entityPropertiesWithWidgets(); track item.name) {\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <span class=\"ax-text-sm ax-font-medium\">{{ item.title | translate | async }}:</span>\n <div class=\"ax-flex-1 ax-ml-2 ax-max-w-48\">\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</ax-popover>\n" }]
2461
2516
  }], 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 }] }], item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: false }] }], breadcrumb: [{ type: i0.Input, args: [{ isSignal: true, alias: "breadcrumb", required: false }] }], detailPopover: [{ type: i0.ViewChild, args: ['detailPopover', { isSignal: true }] }] } });
2462
2517
 
2463
2518
  class AXPEntityDetailPopoverService {
@@ -2658,6 +2713,23 @@ class AXMEntityCrudServiceImpl {
2658
2713
  async custom(request) { }
2659
2714
  }
2660
2715
 
2716
+ /**
2717
+ * Best-effort plain string for thrown {@link Error} messages from command results (no i18n lookup).
2718
+ */
2719
+ function commandMessageTextForError(value) {
2720
+ if (value == null) {
2721
+ return '';
2722
+ }
2723
+ if (typeof value === 'string') {
2724
+ return value;
2725
+ }
2726
+ if (typeof value === 'object' && !Array.isArray(value)) {
2727
+ const values = Object.values(value);
2728
+ const first = values.find((v) => typeof v === 'string' && v.length > 0);
2729
+ return first ?? '';
2730
+ }
2731
+ return String(value);
2732
+ }
2661
2733
  //#region ---- EntityDataAccessor ----
2662
2734
  /**
2663
2735
  * Data accessor for entity operations.
@@ -2754,7 +2826,7 @@ class EntityDataAccessor {
2754
2826
  else if (typeof execute === 'string') {
2755
2827
  const result = await this.commandService.execute(execute, data);
2756
2828
  if (!result?.success) {
2757
- throw new Error(result?.message?.text || 'Failed to create entity');
2829
+ throw new Error(commandMessageTextForError(result?.message?.text) || 'Failed to create entity');
2758
2830
  }
2759
2831
  return result.data?.id || result.data;
2760
2832
  }
@@ -2780,7 +2852,7 @@ class EntityDataAccessor {
2780
2852
  else if (typeof execute === 'string') {
2781
2853
  const result = await this.commandService.execute(execute, updateData);
2782
2854
  if (!result?.success) {
2783
- throw new Error(result?.message?.text || 'Failed to update entity');
2855
+ throw new Error(commandMessageTextForError(result?.message?.text) || 'Failed to update entity');
2784
2856
  }
2785
2857
  return result.data;
2786
2858
  }
@@ -2804,7 +2876,7 @@ class EntityDataAccessor {
2804
2876
  else if (typeof execute === 'string') {
2805
2877
  const result = await this.commandService.execute(execute, id);
2806
2878
  if (!result?.success) {
2807
- throw new Error(result?.message?.text || 'Failed to delete entity');
2879
+ throw new Error(commandMessageTextForError(result?.message?.text) || 'Failed to delete entity');
2808
2880
  }
2809
2881
  return;
2810
2882
  }
@@ -3698,6 +3770,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3698
3770
  }]
3699
3771
  }] });
3700
3772
 
3773
+ //#region ---- Imports ----
3774
+ //#endregion
3775
+ //#region ---- Master interface property sort order ----
3776
+ /**
3777
+ * Sort key for entries in `interfaces.master.{create|update|single}.properties`.
3778
+ * Uses `layout.order` when set and finite; otherwise the property index in that list.
3779
+ */
3780
+ function getMasterInterfacePropertySortKey(interfaceRow, indexInMasterInterfaceList) {
3781
+ const layout = interfaceRow?.layout;
3782
+ if (!layout) {
3783
+ return indexInMasterInterfaceList;
3784
+ }
3785
+ const o = layout.order;
3786
+ if (o !== undefined && o !== null) {
3787
+ const n = Number(o);
3788
+ if (Number.isFinite(n)) {
3789
+ return n;
3790
+ }
3791
+ }
3792
+ return indexInMasterInterfaceList;
3793
+ }
3794
+ //#endregion
3795
+
3701
3796
  class AXPEntityCreateViewSectionViewModel {
3702
3797
  constructor(entity, section) {
3703
3798
  this.entity = entity;
@@ -3711,18 +3806,30 @@ class AXPEntityCreateViewSectionViewModel {
3711
3806
  return this.group.description;
3712
3807
  }, ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
3713
3808
  this.layout = computed(() => {
3714
- const source = cloneDeep(this.section.layout ?? {});
3809
+ const source = cloneDeep(this.section.layout ?? {
3810
+ positions: {
3811
+ lg: {
3812
+ colSpan: 12,
3813
+ },
3814
+ },
3815
+ });
3715
3816
  set(source, 'positions.default.colSpan', 12);
3716
3817
  return source;
3717
3818
  }, ...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
3718
3819
  this.elements = computed(() => {
3719
3820
  const { interfaces, properties } = this.entity;
3720
3821
  const createProps = interfaces?.master?.create?.properties ?? [];
3721
- const createPropNames = new Set(createProps.map(({ name }) => name));
3722
- const filteredProperties = properties.filter(({ groupId, schema, name }) => groupId === this.group.id && createPropNames.has(name));
3723
- return filteredProperties.map((property) => {
3724
- const createProp = createProps.find(({ name }) => name === property.name);
3725
- return new AXPEntityCreateViewElementViewModel(this.entity, this, property, createProp);
3822
+ const propsByName = new Map(properties.map((p) => [p.name, p]));
3823
+ const ordered = createProps
3824
+ .map((cp, index) => ({ cp, index }))
3825
+ .filter(({ cp }) => {
3826
+ const p = propsByName.get(cp.name);
3827
+ return p !== undefined && p.groupId === this.group.id;
3828
+ })
3829
+ .sort((a, b) => getMasterInterfacePropertySortKey(a.cp, a.index) - getMasterInterfacePropertySortKey(b.cp, b.index));
3830
+ return ordered.map(({ cp }) => {
3831
+ const property = propsByName.get(cp.name);
3832
+ return new AXPEntityCreateViewElementViewModel(this.entity, this, property, cp);
3726
3833
  });
3727
3834
  }, ...(ngDevMode ? [{ debugName: "elements" }] : /* istanbul ignore next */ []));
3728
3835
  }
@@ -3788,7 +3895,6 @@ class AXPEntityMasterCreateViewModel {
3788
3895
  const createProps = interfaces?.master?.create?.properties?.map(({ name }) => name) ?? [];
3789
3896
  const visibleProperties = properties.filter(({ groupId, schema, name }) => groupId && createProps.includes(name));
3790
3897
  const sections = interfaces?.master?.create?.sections?.filter(({ id }) => visibleProperties.some(({ groupId }) => groupId === id)) ?? [];
3791
- console.log({ sections, visibleProperties });
3792
3898
  return sections.map((section) => new AXPEntityCreateViewSectionViewModel(this.entityDef, section));
3793
3899
  }, ...(ngDevMode ? [{ debugName: "sections" }] : /* istanbul ignore next */ []));
3794
3900
  if (!initialData)
@@ -3877,6 +3983,48 @@ class AXPEntityMasterListViewQueryViewModel {
3877
3983
  }
3878
3984
  }
3879
3985
  class AXPEntityMasterListViewModel {
3986
+ createExpressionScope(data) {
3987
+ return {
3988
+ context: {
3989
+ eval: (path) => get(data, path),
3990
+ },
3991
+ list: {
3992
+ view: () => this.view().name,
3993
+ views: () => this.views().map((v) => ({ name: v.name, title: v.title })),
3994
+ },
3995
+ };
3996
+ }
3997
+ async resolveCommandNameExpression(commandName, data) {
3998
+ if (!commandName || !commandName.includes('{{')) {
3999
+ return commandName;
4000
+ }
4001
+ const scope = this.createExpressionScope(data);
4002
+ const result = await this.expressionEvaluator.evaluate({ value: commandName }, scope);
4003
+ const resolved = result?.value;
4004
+ return typeof resolved === 'string' && resolved.trim() !== '' ? resolved : commandName;
4005
+ }
4006
+ async resolveTitleExpression(title, data) {
4007
+ if (!title || !title.includes('{{')) {
4008
+ return title;
4009
+ }
4010
+ const scope = this.createExpressionScope(data);
4011
+ const result = await this.expressionEvaluator.evaluate({ value: title }, scope);
4012
+ const resolved = result?.value;
4013
+ return typeof resolved === 'string' && resolved.trim() !== '' ? resolved : title;
4014
+ }
4015
+ async resolveTriggerName(triggerName, data) {
4016
+ if (!triggerName) {
4017
+ return triggerName;
4018
+ }
4019
+ const ampIndex = triggerName.indexOf('&');
4020
+ if (ampIndex < 0) {
4021
+ return await this.resolveCommandNameExpression(triggerName, data);
4022
+ }
4023
+ const commandPart = triggerName.slice(0, ampIndex);
4024
+ const suffix = triggerName.slice(ampIndex); // includes '&'
4025
+ const resolvedCommand = await this.resolveCommandNameExpression(commandPart, data);
4026
+ return `${resolvedCommand}${suffix}`;
4027
+ }
3880
4028
  async setView(viewName = null) {
3881
4029
  const entitySetting = await this.settings.get(this.settingEntityKey);
3882
4030
  const selectedViewName = entitySetting?.list?.currentView;
@@ -4064,14 +4212,9 @@ class AXPEntityMasterListViewModel {
4064
4212
  return this.sortedFields().filter((i) => i.dir).length;
4065
4213
  };
4066
4214
  this.sortedFields = signal([], ...(ngDevMode ? [{ debugName: "sortedFields" }] : /* istanbul ignore next */ []));
4215
+ //#endregion
4067
4216
  this.evaluateExpressions = async (options, data) => {
4068
- const scope = {
4069
- context: {
4070
- eval: (path) => {
4071
- return get(data, path);
4072
- },
4073
- },
4074
- };
4217
+ const scope = this.createExpressionScope(data);
4075
4218
  return await this.expressionEvaluator.evaluate(options, scope);
4076
4219
  };
4077
4220
  this.workflow.events$
@@ -4243,7 +4386,7 @@ class AXPEntityMasterListViewModel {
4243
4386
  this.selectedCategory.set(category);
4244
4387
  }
4245
4388
  async getPrimaryActions() {
4246
- const scope = {};
4389
+ const scope = this.createExpressionScope(null);
4247
4390
  const actions = await Promise.all(this.allActions()
4248
4391
  .filter((a) => a.priority == 'primary' &&
4249
4392
  ((a.scope == AXPEntityCommandScope.Selected && this.hasSelectedItems()) ||
@@ -4253,12 +4396,14 @@ class AXPEntityMasterListViewModel {
4253
4396
  if (isHidden)
4254
4397
  return null;
4255
4398
  const disabled = await this.expressionEvaluator.evaluate(a.disabled, scope);
4256
- return { ...a, disabled };
4399
+ const name = await this.resolveTriggerName(a.name, null);
4400
+ const title = await this.resolveTitleExpression(a.title, null);
4401
+ return { ...a, disabled, name, title };
4257
4402
  }));
4258
- return actions;
4403
+ return actions.filter(Boolean);
4259
4404
  }
4260
4405
  async getSecondaryActions() {
4261
- const scope = {};
4406
+ const scope = this.createExpressionScope(null);
4262
4407
  const actions = await Promise.all(this.allActions()
4263
4408
  .filter((a) => a.priority == 'secondary' &&
4264
4409
  ((a.scope == AXPEntityCommandScope.Selected && this.hasSelectedItems()) ||
@@ -4268,16 +4413,14 @@ class AXPEntityMasterListViewModel {
4268
4413
  if (isHidden)
4269
4414
  return null;
4270
4415
  const disabled = await this.expressionEvaluator.evaluate(a.disabled, scope);
4271
- return { ...a, disabled };
4416
+ const name = await this.resolveTriggerName(a.name, null);
4417
+ const title = await this.resolveTitleExpression(a.title, null);
4418
+ return { ...a, disabled, name, title };
4272
4419
  }));
4273
- return actions;
4420
+ return actions.filter(Boolean);
4274
4421
  }
4275
4422
  async secondaryRowActions(rowData) {
4276
- const scope = {
4277
- context: {
4278
- eval: (path) => get(rowData, path),
4279
- },
4280
- };
4423
+ const scope = this.createExpressionScope(rowData);
4281
4424
  const actions = await Promise.all(this.allActions()
4282
4425
  .filter((a) => a.scope === AXPEntityCommandScope.Individual && a.priority === 'secondary')
4283
4426
  .map(async (a) => {
@@ -4285,7 +4428,9 @@ class AXPEntityMasterListViewModel {
4285
4428
  if (isHidden)
4286
4429
  return null;
4287
4430
  const disabled = await this.expressionEvaluator.evaluate(a.disabled, scope);
4288
- return { ...a, disabled };
4431
+ const name = await this.resolveTriggerName(a.name, rowData);
4432
+ const title = await this.resolveTitleExpression(a.title, rowData);
4433
+ return { ...a, disabled, name, title };
4289
4434
  }));
4290
4435
  return actions.filter(Boolean);
4291
4436
  }
@@ -4536,10 +4681,12 @@ class AXPEntityMasterListViewModel {
4536
4681
  : c.scope == AXPEntityCommandScope.Individual) ||
4537
4682
  c.scope == AXPEntityCommandScope.TypeLevel));
4538
4683
  });
4539
- const command = commandName.split('&')[0];
4684
+ const resolvedTriggerName = await this.resolveTriggerName(commandName, data);
4685
+ const command = resolvedTriggerName.split('&')[0];
4540
4686
  const options = await this.evaluateExpressions(action?.options, data);
4541
4687
  const baseData = action?.scope == AXPEntityCommandScope.Selected ? this.selectedItems() : data;
4542
- const commandData = this.mergeDefaultCategoryForCreate(command, baseData);
4688
+ let commandData = this.mergeViewConditionsForCreate(command, baseData);
4689
+ commandData = this.mergeDefaultCategoryForCreate(command, commandData);
4543
4690
  if (this.workflow.exists(command)) {
4544
4691
  await this.workflow.execute(command, {
4545
4692
  entity: getEntityInfo(this.entityDef).source,
@@ -4621,6 +4768,38 @@ class AXPEntityMasterListViewModel {
4621
4768
  }
4622
4769
  return baseData;
4623
4770
  }
4771
+ //#region ---- Create command defaults from list view ----
4772
+ /**
4773
+ * Seeds create payloads with fixed list-view conditions (e.g. scope=T on the tenant dashboards view)
4774
+ * so new rows match the view context and downstream queries (such as home dashboard) can find them.
4775
+ */
4776
+ mergeViewConditionsForCreate(command, baseData) {
4777
+ const isCreateCommand = command === 'Entity:Create' || command === 'create-entity';
4778
+ if (!isCreateCommand) {
4779
+ return baseData;
4780
+ }
4781
+ const conditions = this.view()?.conditions ?? [];
4782
+ if (conditions.length === 0) {
4783
+ return baseData;
4784
+ }
4785
+ const seed = {};
4786
+ for (const c of conditions) {
4787
+ if (!c?.name || c.operator?.type !== 'equal' || c.value === undefined) {
4788
+ continue;
4789
+ }
4790
+ seed[c.name] = c.value;
4791
+ }
4792
+ if (Object.keys(seed).length === 0) {
4793
+ return baseData;
4794
+ }
4795
+ if (baseData == null) {
4796
+ return seed;
4797
+ }
4798
+ if (typeof baseData === 'object' && !Array.isArray(baseData)) {
4799
+ return { ...seed, ...baseData };
4800
+ }
4801
+ return baseData;
4802
+ }
4624
4803
  async execute(command) {
4625
4804
  switch (command?.name) {
4626
4805
  case 'navigate':
@@ -4878,10 +5057,16 @@ class AXPEntityUpdateViewSectionViewModel {
4878
5057
  this.elements = computed(() => {
4879
5058
  const { interfaces, properties } = this.entity;
4880
5059
  const updateProps = interfaces?.master?.update?.properties ?? [];
4881
- const updatePropNames = new Set(updateProps.map(({ name }) => name));
4882
- const filteredProperties = properties.filter(({ groupId, schema, name }) => groupId === this.group.id && schema.visible !== false && updatePropNames.has(name));
4883
- return filteredProperties.map((property) => {
4884
- const updateProp = updateProps.find(({ name }) => name === property.name);
5060
+ const propsByName = new Map(properties.map((p) => [p.name, p]));
5061
+ const ordered = updateProps
5062
+ .map((up, index) => ({ up, index }))
5063
+ .filter(({ up }) => {
5064
+ const p = propsByName.get(up.name);
5065
+ return p !== undefined && p.groupId === this.group.id && p.schema.visible !== false;
5066
+ })
5067
+ .sort((a, b) => getMasterInterfacePropertySortKey(a.up, a.index) - getMasterInterfacePropertySortKey(b.up, b.index));
5068
+ return ordered.map(({ up }) => {
5069
+ const property = propsByName.get(up.name);
4885
5070
  return new AXPEntityMasterUpdateElementViewModel(this.entity, property);
4886
5071
  });
4887
5072
  }, ...(ngDevMode ? [{ debugName: "elements" }] : /* istanbul ignore next */ []));
@@ -5133,17 +5318,31 @@ class AXPEntityMasterSingleViewGroupViewModel {
5133
5318
  }, ...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
5134
5319
  this.props = computed(() => {
5135
5320
  const { properties, interfaces } = this.entity;
5136
- const groupProperties = properties
5137
- .filter(({ groupId, schema }) => groupId === this.group.id && schema.visible !== false)
5138
- .map(({ name }) => name);
5139
- const viewProperties = interfaces?.master?.single?.properties?.filter(({ name }) => groupProperties.includes(name)) ?? [];
5140
- return viewProperties.map((prop) => new AXPEntityMasterSingleElementViewModel(this.entity, this, prop));
5321
+ const groupPropertyNames = new Set(properties.filter(({ groupId, schema }) => groupId === this.group.id && schema.visible !== false).map((p) => p.name));
5322
+ const singleProps = interfaces?.master?.single?.properties ?? [];
5323
+ const ordered = singleProps
5324
+ .map((vp, index) => ({ vp, index }))
5325
+ .filter(({ vp }) => groupPropertyNames.has(vp.name))
5326
+ .sort((a, b) => getMasterInterfacePropertySortKey(a.vp, a.index) - getMasterInterfacePropertySortKey(b.vp, b.index));
5327
+ return ordered.map(({ vp }) => new AXPEntityMasterSingleElementViewModel(this.entity, this, vp));
5141
5328
  }, ...(ngDevMode ? [{ debugName: "props" }] : /* istanbul ignore next */ []));
5142
5329
  this.editableProps = computed(() => {
5143
5330
  const { properties, interfaces } = this.entity;
5144
- const editablePropertyNames = interfaces?.master?.update?.properties?.map(({ name }) => name) ?? [];
5145
- const filteredProperties = properties.filter(({ groupId, schema, name }) => groupId === this.group.id && schema.visible !== false && editablePropertyNames.includes(name));
5146
- return filteredProperties.map((prop) => new AXPEntityMasterSingleElementViewModel(this.entity, this, prop));
5331
+ const singleViews = interfaces?.master?.single?.properties ?? [];
5332
+ const updateViews = interfaces?.master?.update?.properties ?? [];
5333
+ const propsByName = new Map(properties.map((p) => [p.name, p]));
5334
+ const ordered = updateViews
5335
+ .map((up, index) => ({ up, index }))
5336
+ .filter(({ up }) => {
5337
+ const p = propsByName.get(up.name);
5338
+ return p !== undefined && p.groupId === this.group.id && p.schema.visible !== false;
5339
+ })
5340
+ .sort((a, b) => getMasterInterfacePropertySortKey(a.up, a.index) - getMasterInterfacePropertySortKey(b.up, b.index));
5341
+ return ordered.map(({ up }) => {
5342
+ const viewProp = singleViews.find((s) => s.name === up.name) ??
5343
+ { name: up.name, layout: up.layout };
5344
+ return new AXPEntityMasterSingleElementViewModel(this.entity, this, viewProp);
5345
+ });
5147
5346
  }, ...(ngDevMode ? [{ debugName: "editableProps" }] : /* istanbul ignore next */ []));
5148
5347
  this.editable = computed(() => {
5149
5348
  return this.editableProps().length > 0;
@@ -5829,7 +6028,6 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
5829
6028
  /** i18n key for the synthetic "all items" root row; resolved in the template with the translate pipe. */
5830
6029
  this.categoryTreeRootTitleI18nKey = AXP_CATEGORY_TREE_ROOT_TITLE_I18N_KEY;
5831
6030
  this.translationService = inject(AXTranslationService);
5832
- this.mlsResolver = inject(AXPMultiLanguageStringResolverService);
5833
6031
  this.highlightService = inject(AXHighlightService);
5834
6032
  this.changeDetectorRef = inject(ChangeDetectorRef);
5835
6033
  //#endregion
@@ -7385,7 +7583,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
7385
7583
  const nodeData = pathNode['data'];
7386
7584
  const pathTitle = nodeData
7387
7585
  ? this.getNodeTitle(nodeData)
7388
- : this.mlsResolver.resolve(pathNode['title']);
7586
+ : this.translationService.resolve(pathNode['title']);
7389
7587
  if (pathTitle) {
7390
7588
  titlePath.push(pathTitle);
7391
7589
  }
@@ -7468,7 +7666,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
7468
7666
  }
7469
7667
  const textField = this.treeConfig.textField || 'title';
7470
7668
  const raw = nodeData[textField];
7471
- return this.mlsResolver.resolve(raw);
7669
+ return this.translationService.resolve(raw);
7472
7670
  }
7473
7671
  async getSelectedItems() {
7474
7672
  // selectedNodeIds now only contains LEAF nodes (already filtered)
@@ -7544,7 +7742,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
7544
7742
  } @else if (searchValue().trim() && !isSearching()) {
7545
7743
  <div class="ax-text-xs ax-text-muted ax-flex ax-items-center ax-gap-1">
7546
7744
  @if (searchResultCount() > 0) {
7547
- <span>{{ resultsFoundText() }}</span>
7745
+ <span>{{ resultsFoundText() | translate | async }}</span>
7548
7746
  }
7549
7747
  </div>
7550
7748
  }
@@ -7598,7 +7796,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
7598
7796
  @if (node.id === 'all') {
7599
7797
  {{ categoryTreeRootTitleI18nKey | translate | async }}
7600
7798
  } @else {
7601
- {{ rawLabel | axpResolveMultiLanguageString }}
7799
+ {{ rawLabel | translate | async }}
7602
7800
  }
7603
7801
  </span>
7604
7802
  </div>
@@ -7651,7 +7849,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
7651
7849
  ></ax-button>
7652
7850
  </ax-suffix>
7653
7851
  </ax-footer>
7654
- `, 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$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$1.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$1.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: i5$1.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"], outputs: ["datasourceChange", "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", "variant"] }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AXPResolveMultiLanguageStringPipe, name: "axpResolveMultiLanguageString" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7852
+ `, 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$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$1.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$1.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: i5$1.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"], outputs: ["datasourceChange", "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", "variant"] }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7655
7853
  }
7656
7854
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityCategoryTreeSelectorComponent, decorators: [{
7657
7855
  type: Component,
@@ -7681,7 +7879,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7681
7879
  } @else if (searchValue().trim() && !isSearching()) {
7682
7880
  <div class="ax-text-xs ax-text-muted ax-flex ax-items-center ax-gap-1">
7683
7881
  @if (searchResultCount() > 0) {
7684
- <span>{{ resultsFoundText() }}</span>
7882
+ <span>{{ resultsFoundText() | translate | async }}</span>
7685
7883
  }
7686
7884
  </div>
7687
7885
  }
@@ -7735,7 +7933,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7735
7933
  @if (node.id === 'all') {
7736
7934
  {{ categoryTreeRootTitleI18nKey | translate | async }}
7737
7935
  } @else {
7738
- {{ rawLabel | axpResolveMultiLanguageString }}
7936
+ {{ rawLabel | translate | async }}
7739
7937
  }
7740
7938
  </span>
7741
7939
  </div>
@@ -7801,7 +7999,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7801
7999
  AXTreeViewComponent,
7802
8000
  AXTranslationModule,
7803
8001
  AXPStateMessageComponent,
7804
- AXPResolveMultiLanguageStringPipe,
7805
8002
  FormsModule,
7806
8003
  ],
7807
8004
  }]
@@ -7941,16 +8138,14 @@ class AXPEntityCategoryBatchResolverService {
7941
8138
  items = result?.items ?? [];
7942
8139
  allItems = items;
7943
8140
  }
7944
- const pathMap = parentKey
7945
- ? this.buildPathMap(allItems, valueField, textField, parentKey)
7946
- : null;
8141
+ const pathMap = parentKey ? this.buildPathMap(allItems, valueField, textField, parentKey) : null;
7947
8142
  const result = new Map();
7948
8143
  for (const item of items) {
7949
8144
  const id = String(get(item, valueField));
7950
8145
  const rawTitle = get(item, textField);
7951
8146
  const titleText = this.resolveCategoryLabel(rawTitle);
7952
8147
  const path = pathMap
7953
- ? pathMap.get(id) ?? (rawTitle != null && rawTitle !== '' ? [titleText] : [])
8148
+ ? (pathMap.get(id) ?? (rawTitle != null && rawTitle !== '' ? [titleText] : []))
7954
8149
  : rawTitle != null && rawTitle !== ''
7955
8150
  ? [titleText]
7956
8151
  : [];
@@ -7983,10 +8178,7 @@ class AXPEntityCategoryBatchResolverService {
7983
8178
  return [];
7984
8179
  const parentId = get(item, parentKey);
7985
8180
  const title = this.resolveCategoryLabel(get(item, textField));
7986
- if (parentId == null ||
7987
- parentId === '' ||
7988
- parentId === 'all' ||
7989
- String(parentId) === id) {
8181
+ if (parentId == null || parentId === '' || parentId === 'all' || String(parentId) === id) {
7990
8182
  const path = title ? [title] : [];
7991
8183
  pathMap.set(id, path);
7992
8184
  visited.add(id);
@@ -8427,7 +8619,7 @@ var entityCategoryWidgetColumn_component = /*#__PURE__*/Object.freeze({
8427
8619
  class AXPTruncatedBreadcrumbComponent {
8428
8620
  //#endregion
8429
8621
  constructor() {
8430
- this.mlsResolver = inject(AXPMultiLanguageStringResolverService);
8622
+ this.mlsResolver = inject(AXTranslationService);
8431
8623
  /** Plain string or locale map per segment; truncation uses resolved text (see {@link resolvedSectionTexts}). */
8432
8624
  this.sections = input([], ...(ngDevMode ? [{ debugName: "sections" }] : /* istanbul ignore next */ []));
8433
8625
  this.characterLimit = input(20, ...(ngDevMode ? [{ debugName: "characterLimit" }] : /* istanbul ignore next */ []));
@@ -8450,7 +8642,7 @@ class AXPTruncatedBreadcrumbComponent {
8450
8642
  if (this.sectionLimit() === 'auto') {
8451
8643
  const sections = this.resolvedSectionTexts();
8452
8644
  // Return the maximum length of any section to prevent truncation
8453
- return sections.length > 0 ? Math.max(...sections.map(s => s.length)) : Number.MAX_SAFE_INTEGER;
8645
+ return sections.length > 0 ? Math.max(...sections.map((s) => s.length)) : Number.MAX_SAFE_INTEGER;
8454
8646
  }
8455
8647
  // If only characterLimit is auto, calculate based on container width
8456
8648
  const width = this.containerWidth();
@@ -8554,7 +8746,7 @@ class AXPTruncatedBreadcrumbComponent {
8554
8746
  } @else {
8555
8747
  @if (isExpanded() && canToggle()) {
8556
8748
  @for (section of sections(); track $index; let isLast = $last) {
8557
- <span class="ax-text-sm">{{ section | axpResolveMultiLanguageString }}</span>
8749
+ <span class="ax-text-sm">{{ section | translate | async }}</span>
8558
8750
  @if (!isLast) {
8559
8751
  <ax-icon [class]="separatorIcon()" class="rtl:ax-rotate-180 ax-text-muted ax-text-xs"></ax-icon>
8560
8752
  }
@@ -8594,7 +8786,7 @@ class AXPTruncatedBreadcrumbComponent {
8594
8786
  }
8595
8787
  }
8596
8788
  </div>
8597
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "pipe", type: AXPResolveMultiLanguageStringPipe, name: "axpResolveMultiLanguageString" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
8789
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
8598
8790
  }
8599
8791
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTruncatedBreadcrumbComponent, decorators: [{
8600
8792
  type: Component,
@@ -8610,7 +8802,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
8610
8802
  } @else {
8611
8803
  @if (isExpanded() && canToggle()) {
8612
8804
  @for (section of sections(); track $index; let isLast = $last) {
8613
- <span class="ax-text-sm">{{ section | axpResolveMultiLanguageString }}</span>
8805
+ <span class="ax-text-sm">{{ section | translate | async }}</span>
8614
8806
  @if (!isLast) {
8615
8807
  <ax-icon [class]="separatorIcon()" class="rtl:ax-rotate-180 ax-text-muted ax-text-xs"></ax-icon>
8616
8808
  }
@@ -8652,7 +8844,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
8652
8844
  </div>
8653
8845
  `,
8654
8846
  changeDetection: ChangeDetectionStrategy.OnPush,
8655
- imports: [AXDecoratorModule, AXPResolveMultiLanguageStringPipe],
8847
+ imports: [AXDecoratorModule, AXTranslationModule, AsyncPipe],
8656
8848
  }]
8657
8849
  }], ctorParameters: () => [], propDecorators: { sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], characterLimit: [{ type: i0.Input, args: [{ isSignal: true, alias: "characterLimit", required: false }] }], sectionLimit: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionLimit", required: false }] }], separatorIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "separatorIcon", required: false }] }], ellipsisIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "ellipsisIcon", required: false }] }], eyeIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "eyeIcon", required: false }] }], container: [{ type: i0.ViewChild, args: ['container', { isSignal: true }] }] } });
8658
8850
 
@@ -9112,7 +9304,11 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
9112
9304
  }
9113
9305
  // Return item with path array, or just the item title if no path
9114
9306
  const rawLeafTitle = get(item, textField);
9115
- const pathArray = path.length > 0 ? path : rawLeafTitle != null && rawLeafTitle !== '' ? [rawLeafTitle] : [];
9307
+ const pathArray = path.length > 0
9308
+ ? path
9309
+ : rawLeafTitle != null && rawLeafTitle !== ''
9310
+ ? [rawLeafTitle]
9311
+ : [];
9116
9312
  return { ...item, path: pathArray };
9117
9313
  }
9118
9314
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityCategoryWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
@@ -9233,7 +9429,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
9233
9429
  AXFormModule,
9234
9430
  AXTagBoxModule,
9235
9431
  AXTranslationModule,
9236
- AXPTruncatedBreadcrumbComponent
9432
+ AXPTruncatedBreadcrumbComponent,
9237
9433
  ],
9238
9434
  }]
9239
9435
  }], propDecorators: { tagBox: [{ type: i0.ViewChild, args: ['tagBoxComponent', { isSignal: true }] }] } });
@@ -9326,21 +9522,18 @@ class AXPEntityCategoryWidgetViewComponent extends AXPValueWidgetComponent {
9326
9522
  } @else {
9327
9523
  @if (displayItems().length > 1) {
9328
9524
  @for (item of displayItems(); track item.id) {
9329
- <ax-badge
9330
- class="ax-p-0.5 {{ badgeClass() }}"
9331
- [text]="item.titleRaw | axpResolveMultiLanguageString"
9332
- ></ax-badge>
9525
+ <ax-badge class="ax-p-0.5 {{ badgeClass() }}" [text]="(item.titleRaw | translate | async) || ''"></ax-badge>
9333
9526
  }
9334
9527
  } @else if (displayItems().length == 1) {
9335
9528
  <ax-badge
9336
9529
  class="ax-p-0.5 {{ badgeClass() }}"
9337
- [text]="displayItems()[0].titleRaw | axpResolveMultiLanguageString"
9530
+ [text]="(displayItems()[0].titleRaw | translate | async) || ''"
9338
9531
  ></ax-badge>
9339
9532
  } @else {
9340
9533
  <span class="ax-text-muted">---</span>
9341
9534
  }
9342
9535
  }
9343
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$1.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "pipe", type: AXPResolveMultiLanguageStringPipe, name: "axpResolveMultiLanguageString" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
9536
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$1.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
9344
9537
  }
9345
9538
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityCategoryWidgetViewComponent, decorators: [{
9346
9539
  type: Component,
@@ -9352,15 +9545,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
9352
9545
  } @else {
9353
9546
  @if (displayItems().length > 1) {
9354
9547
  @for (item of displayItems(); track item.id) {
9355
- <ax-badge
9356
- class="ax-p-0.5 {{ badgeClass() }}"
9357
- [text]="item.titleRaw | axpResolveMultiLanguageString"
9358
- ></ax-badge>
9548
+ <ax-badge class="ax-p-0.5 {{ badgeClass() }}" [text]="(item.titleRaw | translate | async) || ''"></ax-badge>
9359
9549
  }
9360
9550
  } @else if (displayItems().length == 1) {
9361
9551
  <ax-badge
9362
9552
  class="ax-p-0.5 {{ badgeClass() }}"
9363
- [text]="displayItems()[0].titleRaw | axpResolveMultiLanguageString"
9553
+ [text]="(displayItems()[0].titleRaw | translate | async) || ''"
9364
9554
  ></ax-badge>
9365
9555
  } @else {
9366
9556
  <span class="ax-text-muted">---</span>
@@ -9368,7 +9558,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
9368
9558
  }
9369
9559
  `,
9370
9560
  changeDetection: ChangeDetectionStrategy.OnPush,
9371
- imports: [AXLoadingModule, AXBadgeModule, AXPResolveMultiLanguageStringPipe],
9561
+ imports: [AXLoadingModule, AXBadgeModule, AXTranslationModule, AsyncPipe],
9372
9562
  }]
9373
9563
  }] });
9374
9564
 
@@ -9763,7 +9953,7 @@ class AXPEntityListTableService {
9763
9953
  animation: true,
9764
9954
  },
9765
9955
  // 🎪 Events
9766
- ...this.createDefaultEvents(entity, allActions),
9956
+ ...this.createDefaultEvents(entity, allActions, options?.excludeProperties),
9767
9957
  };
9768
9958
  console.log('listOptions', listOptions);
9769
9959
  return listOptions;
@@ -9853,7 +10043,7 @@ class AXPEntityListTableService {
9853
10043
  /**
9854
10044
  * Handle execution of a row command (shared by double-click and command handlers)
9855
10045
  */
9856
- async handleRowCommand(e, selectedRows, entity, allActions) {
10046
+ async handleRowCommand(e, selectedRows, entity, allActions, relatedListExcludeProperties) {
9857
10047
  const data = e.data;
9858
10048
  const commandName = e.name;
9859
10049
  const action = allActions.find((c) => {
@@ -9864,7 +10054,8 @@ class AXPEntityListTableService {
9864
10054
  c.scope == AXPEntityCommandScope.TypeLevel));
9865
10055
  });
9866
10056
  const command = commandName.split('&')[0];
9867
- const options = await this.evaluateExpressions(action?.options, data);
10057
+ const evaluatedOptions = await this.evaluateExpressions(action?.options, data);
10058
+ const options = this.mergeRelatedListFormOptions(command, evaluatedOptions, relatedListExcludeProperties);
9868
10059
  if (this.commandService.exists(command)) {
9869
10060
  await this.commandService.execute(command, {
9870
10061
  __context__: {
@@ -9900,10 +10091,25 @@ class AXPEntityListTableService {
9900
10091
  });
9901
10092
  }
9902
10093
  }
10094
+ /**
10095
+ * When a related entity list declares `excludeProperties`, row commands bypass the details page
10096
+ * `execute()` merge — apply the same exclusions for embedded create/update commands.
10097
+ */
10098
+ mergeRelatedListFormOptions(command, evaluatedOptions, relatedListExcludeProperties) {
10099
+ const exclusions = relatedListExcludeProperties?.filter(Boolean);
10100
+ if (!exclusions?.length ||
10101
+ (command !== 'Entity:Create' && command !== 'Entity:Update')) {
10102
+ return evaluatedOptions;
10103
+ }
10104
+ return {
10105
+ ...evaluatedOptions,
10106
+ excludeProperties: exclusions,
10107
+ };
10108
+ }
9903
10109
  /**
9904
10110
  * Create default events
9905
10111
  */
9906
- createDefaultEvents(entity, allActions) {
10112
+ createDefaultEvents(entity, allActions, relatedListExcludeProperties) {
9907
10113
  return {
9908
10114
  onRowClick: (row) => {
9909
10115
  console.log('Entity List - Row clicked:', row);
@@ -9922,13 +10128,13 @@ class AXPEntityListTableService {
9922
10128
  name: defaultAction.name,
9923
10129
  data: e.data,
9924
10130
  };
9925
- this.handleRowCommand(d, undefined, entity, allActions);
10131
+ this.handleRowCommand(d, undefined, entity, allActions, relatedListExcludeProperties);
9926
10132
  },
9927
10133
  onSelectionChange: (selectedRows) => {
9928
10134
  console.log('Entity List - Selection changed:', selectedRows);
9929
10135
  },
9930
10136
  onRowCommand: async (e, selectedRows) => {
9931
- await this.handleRowCommand(e, selectedRows, entity, allActions);
10137
+ await this.handleRowCommand(e, selectedRows, entity, allActions, relatedListExcludeProperties);
9932
10138
  },
9933
10139
  };
9934
10140
  }
@@ -10285,7 +10491,12 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
10285
10491
  const commandData = action?.scope == AXPEntityCommandScope.Selected
10286
10492
  ? this.selectedItems()
10287
10493
  : action?.options?.['process']?.data || null;
10288
- const options = await this.evaluateToolbarExpressions(action?.options, commandData);
10494
+ const evaluatedToolbarOptions = await this.evaluateToolbarExpressions(action?.options, commandData);
10495
+ const relatedExcludes = this.options()['excludeProperties'];
10496
+ const exclusions = relatedExcludes?.filter(Boolean);
10497
+ const options = exclusions?.length && (command === 'Entity:Create' || command === 'Entity:Update')
10498
+ ? { ...evaluatedToolbarOptions, excludeProperties: exclusions }
10499
+ : evaluatedToolbarOptions;
10289
10500
  if (this.commandService.exists(command)) {
10290
10501
  await this.commandService.execute(command, {
10291
10502
  __context__: {
@@ -10434,6 +10645,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
10434
10645
  includeColumns: this.includeColumns(),
10435
10646
  relatedTableColumns: this.relatedTableColumns(),
10436
10647
  customFilterDefinitions: this.customFilterDefinitions(),
10648
+ excludeProperties: this.options()['excludeProperties'],
10437
10649
  };
10438
10650
  const listOptions = await this.entityListTableService.convertEntityToListOptions(resolvedEntity, options, this.allActions());
10439
10651
  const toolbarOptions = await this.entityListToolbarService.convertEntityToolbarOptions(resolvedEntity, options);
@@ -10501,7 +10713,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
10501
10713
  [class.ax-sm]="deviceService.isSmall()"
10502
10714
  [iconOnly]="deviceService.isSmall()"
10503
10715
  [disabled]="action.disabled"
10504
- [text]="action.title"
10716
+ [text]="(action.title | translate | async)!"
10505
10717
  [look]="'solid'"
10506
10718
  [color]="action.color"
10507
10719
  (onClick)="handleActionClick(action)"
@@ -10515,7 +10727,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
10515
10727
  @for (sub of action?.items; track $index) {
10516
10728
  @if (sub.visible != false) {
10517
10729
  <ax-button-item
10518
- [text]="sub.title"
10730
+ [text]="(sub.title | translate | async)!"
10519
10731
  [color]="sub.color"
10520
10732
  [disabled]="sub.disabled"
10521
10733
  (onClick)="handleActionClick(sub)"
@@ -10551,7 +10763,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
10551
10763
  @for (item of secondaryActions(); track $index) {
10552
10764
  @if (item.visible != false) {
10553
10765
  <ax-button-item
10554
- [text]="item.title"
10766
+ [text]="(item.title | translate | async)!"
10555
10767
  [color]="item.color"
10556
10768
  [disabled]="item.disabled"
10557
10769
  (onClick)="handleSecondaryActionClick(item)"
@@ -10618,7 +10830,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
10618
10830
  [class.ax-sm]="deviceService.isSmall()"
10619
10831
  [iconOnly]="deviceService.isSmall()"
10620
10832
  [disabled]="action.disabled"
10621
- [text]="action.title"
10833
+ [text]="(action.title | translate | async)!"
10622
10834
  [look]="'solid'"
10623
10835
  [color]="action.color"
10624
10836
  (onClick)="handleActionClick(action)"
@@ -10632,7 +10844,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
10632
10844
  @for (sub of action?.items; track $index) {
10633
10845
  @if (sub.visible != false) {
10634
10846
  <ax-button-item
10635
- [text]="sub.title"
10847
+ [text]="(sub.title | translate | async)!"
10636
10848
  [color]="sub.color"
10637
10849
  [disabled]="sub.disabled"
10638
10850
  (onClick)="handleActionClick(sub)"
@@ -10668,7 +10880,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
10668
10880
  @for (item of secondaryActions(); track $index) {
10669
10881
  @if (item.visible != false) {
10670
10882
  <ax-button-item
10671
- [text]="item.title"
10883
+ [text]="(item.title | translate | async)!"
10672
10884
  [color]="item.color"
10673
10885
  [disabled]="item.disabled"
10674
10886
  (onClick)="handleSecondaryActionClick(item)"
@@ -10751,7 +10963,7 @@ const AXPEntityListWidget = {
10751
10963
  type: 'view',
10752
10964
  categories: [],
10753
10965
  groups: [AXPWidgetGroupEnum.EntityWidget],
10754
- icon: 'fa-solid fa-square',
10966
+ icon: 'fa-light fa-square',
10755
10967
  properties: [AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY],
10756
10968
  components: {
10757
10969
  view: {
@@ -10784,7 +10996,10 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
10784
10996
  return template ? template.replace(/\{/g, '{{').replace(/\}/g, '}}') : undefined;
10785
10997
  }, ...(ngDevMode ? [{ debugName: "displayFormat" }] : /* istanbul ignore next */ []));
10786
10998
  this.displayField = computed(() => {
10787
- return this.textField() ?? this.entityDef()?.formats.lookup ?? this.entityDef()?.properties.find((c) => c.name != 'id')?.name ?? 'title';
10999
+ return (this.textField() ??
11000
+ this.entityDef()?.formats.lookup ??
11001
+ this.entityDef()?.properties.find((c) => c.name != 'id')?.name ??
11002
+ 'title');
10788
11003
  }, ...(ngDevMode ? [{ debugName: "displayField" }] : /* istanbul ignore next */ []));
10789
11004
  this.loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
10790
11005
  this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : /* istanbul ignore next */ []));
@@ -10827,9 +11042,6 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
10827
11042
  text: item,
10828
11043
  };
10829
11044
  }
10830
- /**
10831
- * Raw label for {@link AXPResolveMultiLanguageStringPipe} (handles {@link AXPMultiLanguageString} and plain strings).
10832
- */
10833
11045
  getDisplayRaw(item) {
10834
11046
  if (!item) {
10835
11047
  return '';
@@ -10861,50 +11073,48 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
10861
11073
  }
10862
11074
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
10863
11075
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLookupWidgetViewComponent, isStandalone: true, selector: "axp-lookup-widget-view", host: { properties: { "class": "this.__class" } }, usesInheritance: true, ngImport: i0, template: `
10864
- @if(loading())
10865
- {
11076
+ @if (loading()) {
10866
11077
  <ax-loading></ax-loading>
10867
- }
10868
- @else{
10869
- @if(displayItems().length > 1) {
10870
- @for (item of displayItems(); track $index) {
10871
- <ax-badge class="ax-p-0.5 {{badgeClass()}}" [text]="item.text | axpResolveMultiLanguageString" ></ax-badge>
10872
- }
10873
- }
10874
- @else if(displayItems().length == 1) {
10875
- <ax-badge class="ax-p-0.5 {{badgeClass()}}" [text]="displayItems()[0].text | axpResolveMultiLanguageString" ></ax-badge>
10876
- }
10877
- @else {
10878
- <span class="ax-text-muted">---</span>
11078
+ } @else {
11079
+ @if (displayItems().length > 1) {
11080
+ @for (item of displayItems(); track $index) {
11081
+ <ax-badge class="ax-p-0.5 {{ badgeClass() }}" [text]="(item.text | translate | async) || ''"></ax-badge>
10879
11082
  }
11083
+ } @else if (displayItems().length == 1) {
11084
+ <ax-badge
11085
+ class="ax-p-0.5 {{ badgeClass() }}"
11086
+ [text]="(displayItems()[0].text | translate | async) || ''"
11087
+ ></ax-badge>
11088
+ } @else {
11089
+ <span class="ax-text-muted">---</span>
11090
+ }
10880
11091
  }
10881
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$1.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "pipe", type: AXPResolveMultiLanguageStringPipe, name: "axpResolveMultiLanguageString" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
11092
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$1.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
10882
11093
  }
10883
11094
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetViewComponent, decorators: [{
10884
11095
  type: Component,
10885
11096
  args: [{
10886
11097
  selector: 'axp-lookup-widget-view',
10887
11098
  template: `
10888
- @if(loading())
10889
- {
11099
+ @if (loading()) {
10890
11100
  <ax-loading></ax-loading>
10891
- }
10892
- @else{
10893
- @if(displayItems().length > 1) {
10894
- @for (item of displayItems(); track $index) {
10895
- <ax-badge class="ax-p-0.5 {{badgeClass()}}" [text]="item.text | axpResolveMultiLanguageString" ></ax-badge>
10896
- }
10897
- }
10898
- @else if(displayItems().length == 1) {
10899
- <ax-badge class="ax-p-0.5 {{badgeClass()}}" [text]="displayItems()[0].text | axpResolveMultiLanguageString" ></ax-badge>
10900
- }
10901
- @else {
10902
- <span class="ax-text-muted">---</span>
11101
+ } @else {
11102
+ @if (displayItems().length > 1) {
11103
+ @for (item of displayItems(); track $index) {
11104
+ <ax-badge class="ax-p-0.5 {{ badgeClass() }}" [text]="(item.text | translate | async) || ''"></ax-badge>
10903
11105
  }
11106
+ } @else if (displayItems().length == 1) {
11107
+ <ax-badge
11108
+ class="ax-p-0.5 {{ badgeClass() }}"
11109
+ [text]="(displayItems()[0].text | translate | async) || ''"
11110
+ ></ax-badge>
11111
+ } @else {
11112
+ <span class="ax-text-muted">---</span>
11113
+ }
10904
11114
  }
10905
11115
  `,
10906
11116
  changeDetection: ChangeDetectionStrategy.OnPush,
10907
- imports: [AXLoadingModule, AXBadgeModule, AXPResolveMultiLanguageStringPipe]
11117
+ imports: [AXLoadingModule, AXBadgeModule, AXTranslationModule, AsyncPipe],
10908
11118
  }]
10909
11119
  }], propDecorators: { __class: [{
10910
11120
  type: HostBinding,
@@ -11351,7 +11561,7 @@ class LookupWidgetLookBase {
11351
11561
  class AXPLookupWidgetSelectComponent extends LookupWidgetLookBase {
11352
11562
  constructor() {
11353
11563
  super(...arguments);
11354
- this.mlsResolver = inject(AXPMultiLanguageStringResolverService);
11564
+ this.mlsResolver = inject(AXTranslationService);
11355
11565
  //#region ---- Inputs ----
11356
11566
  this.entityDef = input.required(...(ngDevMode ? [{ debugName: "entityDef" }] : /* istanbul ignore next */ []));
11357
11567
  this.customFilter = input.required(...(ngDevMode ? [{ debugName: "customFilter" }] : /* istanbul ignore next */ []));
@@ -11361,6 +11571,7 @@ class AXPLookupWidgetSelectComponent extends LookupWidgetLookBase {
11361
11571
  this.disabled = input.required(...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
11362
11572
  this.multiple = input.required(...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
11363
11573
  this.validationRules = input.required(...(ngDevMode ? [{ debugName: "validationRules" }] : /* istanbul ignore next */ []));
11574
+ this.placeholder = input(...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ []));
11364
11575
  this.hasClearButton = input(false, ...(ngDevMode ? [{ debugName: "hasClearButton" }] : /* istanbul ignore next */ []));
11365
11576
  this.allowCreate = input('none', ...(ngDevMode ? [{ debugName: "allowCreate" }] : /* istanbul ignore next */ []));
11366
11577
  //#endregion
@@ -11378,6 +11589,7 @@ class AXPLookupWidgetSelectComponent extends LookupWidgetLookBase {
11378
11589
  this.disabledValue = computed(() => this.disabled()(), ...(ngDevMode ? [{ debugName: "disabledValue" }] : /* istanbul ignore next */ []));
11379
11590
  this.multipleValue = computed(() => this.multiple()(), ...(ngDevMode ? [{ debugName: "multipleValue" }] : /* istanbul ignore next */ []));
11380
11591
  this.validationRulesValue = computed(() => this.validationRules()(), ...(ngDevMode ? [{ debugName: "validationRulesValue" }] : /* istanbul ignore next */ []));
11592
+ this.placeholderValue = computed(() => this.placeholder()?.() ?? '', ...(ngDevMode ? [{ debugName: "placeholderValue" }] : /* istanbul ignore next */ []));
11381
11593
  /**
11382
11594
  * Get default sort order from entity's first list view
11383
11595
  */
@@ -11507,18 +11719,18 @@ class AXPLookupWidgetSelectComponent extends LookupWidgetLookBase {
11507
11719
  this.dataSource()?.refresh();
11508
11720
  }
11509
11721
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
11510
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLookupWidgetSelectComponent, isStandalone: true, selector: "axp-lookup-widget-select", inputs: { entityDef: { classPropertyName: "entityDef", publicName: "entityDef", isSignal: true, isRequired: true, transformFunction: null }, customFilter: { classPropertyName: "customFilter", publicName: "customFilter", isSignal: true, isRequired: true, transformFunction: null }, 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 }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: true, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: true, transformFunction: null }, validationRules: { classPropertyName: "validationRules", publicName: "validationRules", isSignal: true, isRequired: true, transformFunction: null }, hasClearButton: { classPropertyName: "hasClearButton", publicName: "hasClearButton", isSignal: true, isRequired: false, transformFunction: null }, allowCreate: { classPropertyName: "allowCreate", publicName: "allowCreate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChanged: "valueChanged" }, providers: [
11722
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLookupWidgetSelectComponent, isStandalone: true, selector: "axp-lookup-widget-select", inputs: { entityDef: { classPropertyName: "entityDef", publicName: "entityDef", isSignal: true, isRequired: true, transformFunction: null }, customFilter: { classPropertyName: "customFilter", publicName: "customFilter", isSignal: true, isRequired: true, transformFunction: null }, 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 }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: true, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", 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 } }, outputs: { valueChanged: "valueChanged" }, providers: [
11511
11723
  {
11512
11724
  provide: LookupWidgetLookBase,
11513
11725
  useExisting: AXPLookupWidgetSelectComponent,
11514
- }
11726
+ },
11515
11727
  ], viewQueries: [{ propertyName: "selectBox", first: true, predicate: ["selectBox"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
11516
11728
  @if (dataSource()) {
11517
11729
  <div class="ax-flex ax-items-center ax-gap-1 ax-w-full">
11518
11730
  <ax-select-box
11519
11731
  #selectBox
11520
11732
  class="ax-flex-1 ax-min-w-0"
11521
- [placeholder]="('@general:widgets.lookup.placeholder' | translate | async)!"
11733
+ [placeholder]="placeholderValue() || (('@general:widgets.lookup.placeholder' | translate | async) ?? '')"
11522
11734
  [dataSource]="dataSource()!"
11523
11735
  [ngModel]="selectedItemsValue()"
11524
11736
  [textField]="displayFieldValue()"
@@ -11528,11 +11740,9 @@ class AXPLookupWidgetSelectComponent extends LookupWidgetLookBase {
11528
11740
  (onValueChanged)="handleValueChanged($event)"
11529
11741
  >
11530
11742
  @if (hasClearButton()) {
11531
- <ax-clear-button ></ax-clear-button>
11743
+ <ax-clear-button></ax-clear-button>
11532
11744
  }
11533
- <ax-search-box
11534
- [placeholder]="('@general:widgets.lookup.search.placeholder' | translate | async)!"
11535
- >
11745
+ <ax-search-box [placeholder]="('@general:widgets.lookup.search.placeholder' | translate | async)!">
11536
11746
  <ax-clear-button></ax-clear-button>
11537
11747
  </ax-search-box>
11538
11748
  @for (validation of validationRulesValue(); track $index) {
@@ -11543,7 +11753,6 @@ class AXPLookupWidgetSelectComponent extends LookupWidgetLookBase {
11543
11753
  ></ax-validation-rule>
11544
11754
  }
11545
11755
  </ax-select-box>
11546
-
11547
11756
  </div>
11548
11757
  }
11549
11758
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$2.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i2$2.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "itemHeight", "maxVisibleItems", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed", "onItemSelected", "onItemClick"] }, { kind: "component", type: 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: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
@@ -11558,7 +11767,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
11558
11767
  <ax-select-box
11559
11768
  #selectBox
11560
11769
  class="ax-flex-1 ax-min-w-0"
11561
- [placeholder]="('@general:widgets.lookup.placeholder' | translate | async)!"
11770
+ [placeholder]="placeholderValue() || (('@general:widgets.lookup.placeholder' | translate | async) ?? '')"
11562
11771
  [dataSource]="dataSource()!"
11563
11772
  [ngModel]="selectedItemsValue()"
11564
11773
  [textField]="displayFieldValue()"
@@ -11568,11 +11777,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
11568
11777
  (onValueChanged)="handleValueChanged($event)"
11569
11778
  >
11570
11779
  @if (hasClearButton()) {
11571
- <ax-clear-button ></ax-clear-button>
11780
+ <ax-clear-button></ax-clear-button>
11572
11781
  }
11573
- <ax-search-box
11574
- [placeholder]="('@general:widgets.lookup.search.placeholder' | translate | async)!"
11575
- >
11782
+ <ax-search-box [placeholder]="('@general:widgets.lookup.search.placeholder' | translate | async)!">
11576
11783
  <ax-clear-button></ax-clear-button>
11577
11784
  </ax-search-box>
11578
11785
  @for (validation of validationRulesValue(); track $index) {
@@ -11583,7 +11790,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
11583
11790
  ></ax-validation-rule>
11584
11791
  }
11585
11792
  </ax-select-box>
11586
-
11587
11793
  </div>
11588
11794
  }
11589
11795
  `,
@@ -11603,10 +11809,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
11603
11809
  {
11604
11810
  provide: LookupWidgetLookBase,
11605
11811
  useExisting: AXPLookupWidgetSelectComponent,
11606
- }
11812
+ },
11607
11813
  ],
11608
11814
  }]
11609
- }], propDecorators: { entityDef: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityDef", required: true }] }], customFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "customFilter", required: true }] }], 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: true }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: true }] }], validationRules: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationRules", required: true }] }], hasClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasClearButton", required: false }] }], allowCreate: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowCreate", required: false }] }], valueChanged: [{ type: i0.Output, args: ["valueChanged"] }], selectBox: [{ type: i0.ViewChild, args: ['selectBox', { isSignal: true }] }] } });
11815
+ }], propDecorators: { entityDef: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityDef", required: true }] }], customFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "customFilter", required: true }] }], 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: true }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", 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 }] }], valueChanged: [{ type: i0.Output, args: ["valueChanged"] }], selectBox: [{ type: i0.ViewChild, args: ['selectBox', { isSignal: true }] }] } });
11610
11816
 
11611
11817
  class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
11612
11818
  constructor() {
@@ -11625,6 +11831,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
11625
11831
  this.multiple = input.required(...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
11626
11832
  this.isLoading = input.required(...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
11627
11833
  this.validationRules = input.required(...(ngDevMode ? [{ debugName: "validationRules" }] : /* istanbul ignore next */ []));
11834
+ this.placeholder = input(...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ []));
11628
11835
  this.hasClearButton = input(false, ...(ngDevMode ? [{ debugName: "hasClearButton" }] : /* istanbul ignore next */ []));
11629
11836
  this.allowCreate = input('none', ...(ngDevMode ? [{ debugName: "allowCreate" }] : /* istanbul ignore next */ []));
11630
11837
  // Entity and configuration data (for showSelector and searchByValue)
@@ -11675,6 +11882,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
11675
11882
  this.multipleValue = computed(() => this.multiple()(), ...(ngDevMode ? [{ debugName: "multipleValue" }] : /* istanbul ignore next */ []));
11676
11883
  this.isLoadingValue = computed(() => this.isLoading()(), ...(ngDevMode ? [{ debugName: "isLoadingValue" }] : /* istanbul ignore next */ []));
11677
11884
  this.validationRulesValue = computed(() => this.validationRules()(), ...(ngDevMode ? [{ debugName: "validationRulesValue" }] : /* istanbul ignore next */ []));
11885
+ this.placeholderValue = computed(() => this.placeholder()?.() ?? '', ...(ngDevMode ? [{ debugName: "placeholderValue" }] : /* istanbul ignore next */ []));
11678
11886
  }
11679
11887
  #focusEffect;
11680
11888
  focus() {
@@ -11855,7 +12063,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
11855
12063
  this.clear();
11856
12064
  }
11857
12065
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetTagboxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
11858
- 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 }, hasClearButton: { classPropertyName: "hasClearButton", publicName: "hasClearButton", isSignal: true, isRequired: false, transformFunction: null }, allowCreate: { classPropertyName: "allowCreate", publicName: "allowCreate", 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 }, onSetLoading: { classPropertyName: "onSetLoading", publicName: "onSetLoading", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { valueChanged: "valueChanged" }, providers: [
12066
+ 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 }, 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 }, onSetLoading: { classPropertyName: "onSetLoading", publicName: "onSetLoading", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { valueChanged: "valueChanged" }, providers: [
11859
12067
  {
11860
12068
  provide: LookupWidgetLookBase,
11861
12069
  useExisting: AXPLookupWidgetTagboxComponent,
@@ -11868,7 +12076,11 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
11868
12076
  [textField]="displayFieldValue()"
11869
12077
  [valueField]="valueFieldValue()"
11870
12078
  (onValueChanged)="handleValueChanged($event)"
11871
- [placeholder]="selectedItemsValue().length ? '' : ('@general:widgets.lookup.placeholder' | translate | async)!"
12079
+ [placeholder]="
12080
+ selectedItemsValue().length
12081
+ ? ''
12082
+ : (placeholderValue() || (('@general:widgets.lookup.placeholder' | translate | async) ?? ''))
12083
+ "
11872
12084
  [addOnEnter]="false"
11873
12085
  [addOnComma]="false"
11874
12086
  [disabled]="disabledValue()"
@@ -11904,13 +12116,13 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
11904
12116
  </ax-tag-box>
11905
12117
  <ng-template #tagTemplate let-item let-index="index">
11906
12118
  <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">
11907
- <span>{{ getDisplayRaw(item) | axpResolveMultiLanguageString }}</span>
12119
+ <span>{{ getDisplayRaw(item) | translate | async }}</span>
11908
12120
  <button type="button" (click)="tagBoxComponent.removeItem(index)">
11909
12121
  <ax-icon class="ax-icon ax-icon-close"></ax-icon>
11910
12122
  </button>
11911
12123
  </div>
11912
12124
  </ng-template>
11913
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$1.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$2.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXTagBoxModule }, { kind: "component", type: i6$1.AXTagBoxComponent, selector: "ax-tag-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "allowNull", "type", "look", "addOnComma", "addOnEnter", "valueField", "textField", "readonlyField", "allowDuplicateValues", "tagTemplate"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onTagClick", "onTagDblClick", "onTagContextMenu"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AXPResolveMultiLanguageStringPipe, name: "axpResolveMultiLanguageString" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
12125
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$1.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$2.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXTagBoxModule }, { kind: "component", type: i6$1.AXTagBoxComponent, selector: "ax-tag-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "allowNull", "type", "look", "addOnComma", "addOnEnter", "valueField", "textField", "readonlyField", "allowDuplicateValues", "tagTemplate"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onTagClick", "onTagDblClick", "onTagContextMenu"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
11914
12126
  }
11915
12127
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetTagboxComponent, decorators: [{
11916
12128
  type: Component,
@@ -11924,7 +12136,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
11924
12136
  [textField]="displayFieldValue()"
11925
12137
  [valueField]="valueFieldValue()"
11926
12138
  (onValueChanged)="handleValueChanged($event)"
11927
- [placeholder]="selectedItemsValue().length ? '' : ('@general:widgets.lookup.placeholder' | translate | async)!"
12139
+ [placeholder]="
12140
+ selectedItemsValue().length
12141
+ ? ''
12142
+ : (placeholderValue() || (('@general:widgets.lookup.placeholder' | translate | async) ?? ''))
12143
+ "
11928
12144
  [addOnEnter]="false"
11929
12145
  [addOnComma]="false"
11930
12146
  [disabled]="disabledValue()"
@@ -11960,7 +12176,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
11960
12176
  </ax-tag-box>
11961
12177
  <ng-template #tagTemplate let-item let-index="index">
11962
12178
  <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">
11963
- <span>{{ getDisplayRaw(item) | axpResolveMultiLanguageString }}</span>
12179
+ <span>{{ getDisplayRaw(item) | translate | async }}</span>
11964
12180
  <button type="button" (click)="tagBoxComponent.removeItem(index)">
11965
12181
  <ax-icon class="ax-icon ax-icon-close"></ax-icon>
11966
12182
  </button>
@@ -11978,7 +12194,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
11978
12194
  AXFormModule,
11979
12195
  AXTagBoxModule,
11980
12196
  AXTranslationModule,
11981
- AXPResolveMultiLanguageStringPipe,
11982
12197
  ],
11983
12198
  providers: [
11984
12199
  {
@@ -11987,7 +12202,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
11987
12202
  },
11988
12203
  ],
11989
12204
  }]
11990
- }], 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 }] }], hasClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasClearButton", required: false }] }], allowCreate: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowCreate", 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 }] }], 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 }] }] } });
12205
+ }], 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 }] }], 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 }] }], 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 }] }] } });
11991
12206
 
11992
12207
  class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
11993
12208
  constructor() {
@@ -11997,7 +12212,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
11997
12212
  this.entityResolver = inject(AXPEntityDefinitionRegistryService);
11998
12213
  this.entityService = inject(AXPEntityService);
11999
12214
  this.entityDataSelectorService = inject(AXPEntityDataSelectorService);
12000
- this.mlsResolver = inject(AXPMultiLanguageStringResolverService);
12215
+ this.mlsResolver = inject(AXTranslationService);
12001
12216
  //#endregion
12002
12217
  //#region ---- View Children ----
12003
12218
  this.componentLook = viewChild(LookupWidgetLookBase, ...(ngDevMode ? [{ debugName: "componentLook" }] : /* istanbul ignore next */ []));
@@ -12010,6 +12225,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
12010
12225
  this.textField = computed(() => this.options()['textField'] ?? '', ...(ngDevMode ? [{ debugName: "textField" }] : /* istanbul ignore next */ []));
12011
12226
  this.hasClearButton = computed(() => (!this.filterMode() && this.options()['hasClearButton']) ?? false, ...(ngDevMode ? [{ debugName: "hasClearButton" }] : /* istanbul ignore next */ []));
12012
12227
  this.customFilter = computed(() => this.options()['filter'], ...(ngDevMode ? [{ debugName: "customFilter" }] : /* istanbul ignore next */ []));
12228
+ this.placeholder = computed(() => this.options()['placeholder'] ?? '', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
12013
12229
  this.filterMode = computed(() => this.options()['filterMode'], ...(ngDevMode ? [{ debugName: "filterMode" }] : /* istanbul ignore next */ []));
12014
12230
  this.multiple = computed(() => (this.options()['multiple'] ?? false), ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
12015
12231
  this.look = computed(() => this.options()['look'] ?? 'lookup', ...(ngDevMode ? [{ debugName: "look" }] : /* istanbul ignore next */ []));
@@ -12288,6 +12504,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
12288
12504
  [valueField]="valueField"
12289
12505
  [disabled]="disabled"
12290
12506
  [multiple]="multiple"
12507
+ [placeholder]="placeholder"
12291
12508
  [validationRules]="validationRules"
12292
12509
  [hasClearButton]="hasClearButton()"
12293
12510
  [allowCreate]="allowCreate()"
@@ -12303,6 +12520,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
12303
12520
  [displayFormat]="displayFormat"
12304
12521
  [disabled]="disabled"
12305
12522
  [multiple]="multiple"
12523
+ [placeholder]="placeholder"
12306
12524
  [isLoading]="isLoading"
12307
12525
  [validationRules]="validationRules"
12308
12526
  [hasClearButton]="hasClearButton()"
@@ -12331,7 +12549,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
12331
12549
  }
12332
12550
  </div>
12333
12551
  }
12334
- `, 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$1.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", "hasClearButton", "allowCreate"], outputs: ["valueChanged"] }, { kind: "component", type: AXPLookupWidgetTagboxComponent, selector: "axp-lookup-widget-tagbox", inputs: ["selectedItems", "displayField", "valueField", "displayFormat", "disabled", "multiple", "isLoading", "validationRules", "hasClearButton", "allowCreate", "entityDef", "customFilter", "columns", "parentFilters", "onSetLoading"], outputs: ["valueChanged"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
12552
+ `, 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$1.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"], outputs: ["valueChanged"] }, { kind: "component", type: AXPLookupWidgetTagboxComponent, selector: "axp-lookup-widget-tagbox", inputs: ["selectedItems", "displayField", "valueField", "displayFormat", "disabled", "multiple", "isLoading", "validationRules", "placeholder", "hasClearButton", "allowCreate", "entityDef", "customFilter", "columns", "parentFilters", "onSetLoading"], outputs: ["valueChanged"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
12335
12553
  }
12336
12554
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetEditComponent, decorators: [{
12337
12555
  type: Component,
@@ -12351,6 +12569,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
12351
12569
  [valueField]="valueField"
12352
12570
  [disabled]="disabled"
12353
12571
  [multiple]="multiple"
12572
+ [placeholder]="placeholder"
12354
12573
  [validationRules]="validationRules"
12355
12574
  [hasClearButton]="hasClearButton()"
12356
12575
  [allowCreate]="allowCreate()"
@@ -12366,6 +12585,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
12366
12585
  [displayFormat]="displayFormat"
12367
12586
  [disabled]="disabled"
12368
12587
  [multiple]="multiple"
12588
+ [placeholder]="placeholder"
12369
12589
  [isLoading]="isLoading"
12370
12590
  [validationRules]="validationRules"
12371
12591
  [hasClearButton]="hasClearButton()"
@@ -12414,75 +12634,181 @@ var lookupWidgetEdit_component = /*#__PURE__*/Object.freeze({
12414
12634
 
12415
12635
  class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
12416
12636
  constructor() {
12417
- super(...arguments);
12418
- //#region ---- Dependencies ----
12637
+ super();
12638
+ //#region ---- Dependencies ----
12419
12639
  this.entityDetailPopoverService = inject(AXPEntityDetailPopoverService);
12420
- this.mlResolver = inject(AXPMultiLanguageStringResolverService);
12640
+ this.translation = inject(AXTranslationService);
12421
12641
  this.formatService = inject(AXFormatService);
12642
+ this.entityService = inject(AXPEntityService);
12643
+ this.queryExecutor = inject(AXPQueryExecutor);
12422
12644
  //#endregion
12423
- //#region ---- View Children ----
12645
+ //#region ---- View Children ----
12424
12646
  this.moreButton = viewChild('moreButton', ...(ngDevMode ? [{ debugName: "moreButton" }] : /* istanbul ignore next */ []));
12647
+ this.lazyTrigger = viewChild('lazyTrigger', ...(ngDevMode ? [{ debugName: "lazyTrigger" }] : /* istanbul ignore next */ []));
12425
12648
  this.morePopover = viewChild('morePopover', ...(ngDevMode ? [{ debugName: "morePopover" }] : /* istanbul ignore next */ []));
12426
12649
  //#endregion
12427
- //#region ---- Properties ----
12650
+ //#region ---- Properties ----
12428
12651
  this.host = inject(ElementRef);
12429
12652
  this.valueField = this.options['valueField'] ?? 'id';
12430
12653
  this.textField = this.options['textField'] ?? 'title';
12431
- this.entity = this.options['entity'] ?? 'title';
12654
+ this.entity = this.options['entity'] ?? '';
12432
12655
  this.columnName = this.options['columnName'] ?? 'title';
12433
12656
  this.maxVisible = this.options['maxVisible'] ?? 2;
12434
12657
  this.displayFormat = computed(() => {
12435
12658
  const template = this.options['displayFormat'];
12436
12659
  return template ? template.replace(/\{/g, '{{').replace(/\}/g, '}}') : undefined;
12437
12660
  }, ...(ngDevMode ? [{ debugName: "displayFormat" }] : /* istanbul ignore next */ []));
12438
- this.displayField = computed(() => {
12439
- return this.textField ?? 'title';
12440
- }, ...(ngDevMode ? [{ debugName: "displayField" }] : /* istanbul ignore next */ []));
12661
+ this.displayField = computed(() => this.textField ?? 'title', ...(ngDevMode ? [{ debugName: "displayField" }] : /* istanbul ignore next */ []));
12662
+ this.columnResolve = computed(() => this.options['columnResolve'], ...(ngDevMode ? [{ debugName: "columnResolve" }] : /* istanbul ignore next */ []));
12663
+ this.resolveStrategy = computed(() => {
12664
+ return this.columnResolve()?.strategy ?? 'hydrated';
12665
+ }, ...(ngDevMode ? [{ debugName: "resolveStrategy" }] : /* istanbul ignore next */ []));
12666
+ this.isHydratedStrategy = computed(() => this.resolveStrategy() === 'hydrated', ...(ngDevMode ? [{ debugName: "isHydratedStrategy" }] : /* istanbul ignore next */ []));
12441
12667
  //#endregion
12442
- //#region ---- Signals ----
12668
+ //#region ---- Signals ----
12443
12669
  this.isMorePopoverOpen = signal(false, ...(ngDevMode ? [{ debugName: "isMorePopoverOpen" }] : /* istanbul ignore next */ []));
12444
12670
  this.selectedItemIndex = signal(-1, ...(ngDevMode ? [{ debugName: "selectedItemIndex" }] : /* istanbul ignore next */ []));
12671
+ this.resolvedPopoverItems = signal([], ...(ngDevMode ? [{ debugName: "resolvedPopoverItems" }] : /* istanbul ignore next */ []));
12672
+ this.resolveStatus = signal('idle', ...(ngDevMode ? [{ debugName: "resolveStatus" }] : /* istanbul ignore next */ []));
12673
+ this.resolveError = signal(null, ...(ngDevMode ? [{ debugName: "resolveError" }] : /* istanbul ignore next */ []));
12674
+ this.summaryLabel = signal('', ...(ngDevMode ? [{ debugName: "summaryLabel" }] : /* istanbul ignore next */ []));
12675
+ this.popoverHeader = signal('', ...(ngDevMode ? [{ debugName: "popoverHeader" }] : /* istanbul ignore next */ []));
12445
12676
  //#endregion
12446
- //#region ---- Computed Properties ----
12677
+ //#region ---- Computed ----
12447
12678
  this.displayItems = computed(() => isNil(this.rawValue)
12448
12679
  ? []
12449
- : castArray(this.rawValue).map((item) => this.extractItem(item)).filter((c) => c != null), ...(ngDevMode ? [{ debugName: "displayItems" }] : /* istanbul ignore next */ []));
12680
+ : castArray(this.rawValue)
12681
+ .map((item) => this.extractItem(item))
12682
+ .filter((c) => c != null), ...(ngDevMode ? [{ debugName: "displayItems" }] : /* istanbul ignore next */ []));
12450
12683
  this.allItems = computed(() => this.displayItems(), ...(ngDevMode ? [{ debugName: "allItems" }] : /* istanbul ignore next */ []));
12451
12684
  this.visibleItems = computed(() => {
12452
12685
  const items = this.allItems();
12453
12686
  return items.slice(0, this.maxVisible);
12454
12687
  }, ...(ngDevMode ? [{ debugName: "visibleItems" }] : /* istanbul ignore next */ []));
12455
- this.hasMoreItems = computed(() => {
12456
- return this.allItems().length > this.maxVisible;
12457
- }, ...(ngDevMode ? [{ debugName: "hasMoreItems" }] : /* istanbul ignore next */ []));
12458
- this.remainingItemsCount = computed(() => {
12459
- return this.allItems().length - this.maxVisible;
12460
- }, ...(ngDevMode ? [{ debugName: "remainingItemsCount" }] : /* istanbul ignore next */ []));
12688
+ this.hasMoreItems = computed(() => this.allItems().length > this.maxVisible, ...(ngDevMode ? [{ debugName: "hasMoreItems" }] : /* istanbul ignore next */ []));
12689
+ this.idsFromRow = computed(() => {
12690
+ const cr = this.columnResolve();
12691
+ const path = cr?.idsPath;
12692
+ const source = path ? get(this.rowData, path) : this.rawValue;
12693
+ if (isNil(source)) {
12694
+ return [];
12695
+ }
12696
+ return castArray(source)
12697
+ .map((x) => (typeof x === 'object' && x != null ? get(x, this.valueField) : x))
12698
+ .filter((id) => id != null && id !== '');
12699
+ }, ...(ngDevMode ? [{ debugName: "idsFromRow" }] : /* istanbul ignore next */ []));
12700
+ this.displayCount = computed(() => {
12701
+ const cr = this.columnResolve();
12702
+ const countPath = cr?.countFieldPath;
12703
+ if (countPath) {
12704
+ const v = get(this.rowData, countPath);
12705
+ if (typeof v === 'number' && !Number.isNaN(v)) {
12706
+ return v;
12707
+ }
12708
+ if (typeof v === 'string' && v !== '') {
12709
+ const n = Number(v);
12710
+ return Number.isNaN(n) ? 0 : n;
12711
+ }
12712
+ return 0;
12713
+ }
12714
+ if (this.resolveStrategy() === 'idsWithCount') {
12715
+ return this.idsFromRow().length;
12716
+ }
12717
+ if (this.resolveStrategy() === 'countOnly') {
12718
+ return 0;
12719
+ }
12720
+ return 0;
12721
+ }, ...(ngDevMode ? [{ debugName: "displayCount" }] : /* istanbul ignore next */ []));
12722
+ this.popoverListItems = computed(() => {
12723
+ if (this.isHydratedStrategy()) {
12724
+ return this.allItems();
12725
+ }
12726
+ return this.resolvedPopoverItems();
12727
+ }, ...(ngDevMode ? [{ debugName: "popoverListItems" }] : /* istanbul ignore next */ []));
12728
+ //#endregion
12729
+ //#region ---- Constructor effects ----
12730
+ /** Avoid resetting lazy cache on every CD when `rowData` is a new object reference for the same row. */
12731
+ this.previousLazyRowId = undefined;
12732
+ effect(() => {
12733
+ const id = this.rowData?.['id'];
12734
+ const key = id != null && id !== '' ? String(id) : undefined;
12735
+ if (key === this.previousLazyRowId) {
12736
+ return;
12737
+ }
12738
+ this.previousLazyRowId = key;
12739
+ this.resetLazyState();
12740
+ });
12741
+ effect(() => {
12742
+ if (!this.isHydratedStrategy()) {
12743
+ const count = this.displayCount();
12744
+ void this.refreshSummaryLabel(count);
12745
+ }
12746
+ });
12747
+ effect(() => {
12748
+ const hydrated = this.isHydratedStrategy();
12749
+ const count = hydrated
12750
+ ? this.allItems().length
12751
+ : this.resolveStatus() === 'ready'
12752
+ ? this.resolvedPopoverItems().length
12753
+ : this.displayCount();
12754
+ void this.refreshPopoverHeader(count);
12755
+ });
12461
12756
  }
12462
12757
  //#endregion
12463
- //#region ---- Public Methods ----
12758
+ //#region ---- Public methods ----
12464
12759
  showMoreItems() {
12465
12760
  this.entityDetailPopoverService.hide();
12466
- this.openMorePopover();
12761
+ this.openPopoverFromRef(this.moreButton());
12467
12762
  }
12468
- onMorePopoverOpenChange(event) {
12469
- this.isMorePopoverOpen.set(event);
12763
+ openLazyPopover() {
12764
+ this.entityDetailPopoverService.hide();
12765
+ this.openPopoverFromRef(this.lazyTrigger());
12766
+ if (!this.isHydratedStrategy()) {
12767
+ void this.ensureLazyItemsLoaded();
12768
+ }
12769
+ }
12770
+ onPopoverOpenChange(event) {
12771
+ const open = this.coercePopoverOpenEvent(event);
12772
+ this.isMorePopoverOpen.set(open);
12773
+ if (open && !this.isHydratedStrategy()) {
12774
+ void this.ensureLazyItemsLoaded();
12775
+ }
12470
12776
  }
12471
12777
  async showItemDetail(item, index) {
12472
12778
  if (this.options['disableDetailPopover']) {
12473
12779
  return;
12474
12780
  }
12475
- const columnData = this.rowData[this.columnName];
12476
- const id = Array.isArray(columnData) ? columnData[index] : columnData;
12477
12781
  this.selectedItemIndex.set(index);
12478
12782
  this.closeMorePopover();
12479
- // Show entity detail popover using the service
12783
+ // Prefer the row's FK / stored value (columnName) first. List columns often use options.dataPath so
12784
+ // rawValue (and thus `item`) is only display text (e.g. manager.person.fullName) while managerId holds the real id.
12785
+ const columnData = this.rowData?.[this.columnName];
12786
+ let id;
12787
+ if (Array.isArray(columnData)) {
12788
+ const cell = columnData[index];
12789
+ id =
12790
+ typeof cell === 'object' && cell != null
12791
+ ? get(cell, this.valueField)
12792
+ : cell;
12793
+ }
12794
+ else if (!isNil(columnData) && columnData !== '') {
12795
+ id =
12796
+ typeof columnData === 'object' && columnData != null
12797
+ ? get(columnData, this.valueField)
12798
+ : columnData;
12799
+ }
12800
+ if (isNil(id) || id === '') {
12801
+ id = get(item, this.valueField);
12802
+ }
12803
+ if (isNil(id) || id === '') {
12804
+ return;
12805
+ }
12480
12806
  await this.entityDetailPopoverService.show(this.host, {
12481
12807
  entity: this.entity,
12482
- id: id,
12808
+ id,
12483
12809
  textField: this.textField,
12484
12810
  valueField: this.valueField,
12485
- item
12811
+ item,
12486
12812
  });
12487
12813
  }
12488
12814
  handleItemClick(index) {
@@ -12491,36 +12817,25 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
12491
12817
  }
12492
12818
  const items = this.allItems();
12493
12819
  if (index < items.length) {
12494
- const item = items[index];
12495
- this.showItemDetail(item, index);
12820
+ this.showItemDetail(items[index], index);
12496
12821
  }
12497
12822
  }
12498
- //#endregion
12499
- //#region ---- Private Methods ----
12500
- openMorePopover() {
12501
- if (this.morePopover() && this.moreButton()) {
12502
- this.morePopover().target = this.moreButton().nativeElement;
12503
- this.morePopover().open();
12504
- this.isMorePopoverOpen.set(true);
12823
+ handleResolvedItemClick(index) {
12824
+ if (this.options['disableDetailPopover']) {
12825
+ return;
12505
12826
  }
12506
- }
12507
- closeMorePopover() {
12508
- if (this.morePopover()) {
12509
- this.morePopover().close();
12510
- this.isMorePopoverOpen.set(false);
12827
+ const items = this.resolvedPopoverItems();
12828
+ if (index < items.length) {
12829
+ this.showItemDetail(items[index], index);
12511
12830
  }
12512
12831
  }
12513
- extractItem(item) {
12514
- if (isNil(item)) {
12515
- return null;
12832
+ handlePopoverItemClick(index) {
12833
+ if (this.isHydratedStrategy()) {
12834
+ this.handleItemClick(index);
12516
12835
  }
12517
- if (typeof item === 'object') {
12518
- return item;
12836
+ else {
12837
+ this.handleResolvedItemClick(index);
12519
12838
  }
12520
- return {
12521
- [this.valueField]: item,
12522
- [this.textField]: item,
12523
- };
12524
12839
  }
12525
12840
  getDisplayRaw(item) {
12526
12841
  if (isNil(item)) {
@@ -12538,6 +12853,178 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
12538
12853
  }
12539
12854
  return resolved ?? '';
12540
12855
  }
12856
+ //#endregion
12857
+ //#region ---- Private methods ----
12858
+ async refreshSummaryLabel(count) {
12859
+ const text = await this.translation.translateAsync('@general:widgets.lookup.column.items-count', {
12860
+ params: { count: String(count) },
12861
+ });
12862
+ this.summaryLabel.set(text);
12863
+ }
12864
+ async refreshPopoverHeader(count) {
12865
+ const text = await this.translation.translateAsync('@general:widgets.lookup.column.popover-title', {
12866
+ params: { count: String(count) },
12867
+ });
12868
+ this.popoverHeader.set(text);
12869
+ }
12870
+ resetLazyState() {
12871
+ this.resolvedPopoverItems.set([]);
12872
+ this.resolveStatus.set('idle');
12873
+ this.resolveError.set(null);
12874
+ }
12875
+ openPopoverFromRef(ref) {
12876
+ const popover = this.morePopover();
12877
+ if (popover && ref) {
12878
+ popover.target = ref.nativeElement;
12879
+ popover.open();
12880
+ this.isMorePopoverOpen.set(true);
12881
+ }
12882
+ }
12883
+ closeMorePopover() {
12884
+ const popover = this.morePopover();
12885
+ if (popover) {
12886
+ popover.close();
12887
+ this.isMorePopoverOpen.set(false);
12888
+ }
12889
+ }
12890
+ async ensureLazyItemsLoaded() {
12891
+ if (this.resolveStatus() === 'loading') {
12892
+ return;
12893
+ }
12894
+ const strategy = this.resolveStrategy();
12895
+ if (strategy === 'idsWithCount') {
12896
+ await this.loadByIds();
12897
+ return;
12898
+ }
12899
+ if (strategy === 'countOnly') {
12900
+ await this.loadByNamedQuery();
12901
+ }
12902
+ }
12903
+ /**
12904
+ * ax-popover may emit a boolean, CustomEvent with detail, or a DOM Event depending on version.
12905
+ */
12906
+ coercePopoverOpenEvent(event) {
12907
+ if (typeof event === 'boolean') {
12908
+ return event;
12909
+ }
12910
+ if (event && typeof event === 'object') {
12911
+ const o = event;
12912
+ if ('detail' in o) {
12913
+ return Boolean(o['detail']);
12914
+ }
12915
+ if ('open' in o) {
12916
+ return Boolean(o['open']);
12917
+ }
12918
+ }
12919
+ return false;
12920
+ }
12921
+ async loadByIds() {
12922
+ const ids = this.idsFromRow();
12923
+ if (!ids.length) {
12924
+ this.resolvedPopoverItems.set([]);
12925
+ this.resolveStatus.set('ready');
12926
+ return;
12927
+ }
12928
+ if (!this.entity?.includes('.')) {
12929
+ const msg = await this.translation.translateAsync('@general:widgets.lookup.column.load-failed');
12930
+ this.resolveError.set(msg);
12931
+ this.resolveStatus.set('error');
12932
+ return;
12933
+ }
12934
+ this.resolveStatus.set('loading');
12935
+ this.resolveError.set(null);
12936
+ try {
12937
+ const accessor = this.entityService.withEntity(this.entity).data();
12938
+ const results = await Promise.all(ids.map((id) => accessor.byKey(id)));
12939
+ this.resolvedPopoverItems.set(results.filter((item) => item != null));
12940
+ this.resolveStatus.set('ready');
12941
+ }
12942
+ catch {
12943
+ const msg = await this.translation.translateAsync('@general:widgets.lookup.column.load-failed');
12944
+ this.resolveError.set(msg);
12945
+ this.resolveStatus.set('error');
12946
+ this.resolvedPopoverItems.set([]);
12947
+ }
12948
+ }
12949
+ async loadByNamedQuery() {
12950
+ const cr = this.columnResolve();
12951
+ const key = cr?.queryKey;
12952
+ if (!key?.trim()) {
12953
+ const msg = await this.translation.translateAsync('@general:widgets.lookup.column.load-failed');
12954
+ this.resolveError.set(msg);
12955
+ this.resolveStatus.set('error');
12956
+ return;
12957
+ }
12958
+ this.resolveStatus.set('loading');
12959
+ this.resolveError.set(null);
12960
+ try {
12961
+ const input = this.buildNamedQueryInput();
12962
+ const result = await this.queryExecutor.fetch(key, input);
12963
+ const items = this.extractItemsFromQueryResult(result);
12964
+ this.resolvedPopoverItems.set(items);
12965
+ this.resolveStatus.set('ready');
12966
+ }
12967
+ catch {
12968
+ const msg = await this.translation.translateAsync('@general:widgets.lookup.column.load-failed');
12969
+ this.resolveError.set(msg);
12970
+ this.resolveStatus.set('error');
12971
+ this.resolvedPopoverItems.set([]);
12972
+ }
12973
+ }
12974
+ buildNamedQueryInput() {
12975
+ const map = this.parseQueryParamsMap();
12976
+ const row = this.rowData ?? {};
12977
+ if (!map) {
12978
+ return {};
12979
+ }
12980
+ const out = {};
12981
+ for (const [param, path] of Object.entries(map)) {
12982
+ out[param] = get(row, path);
12983
+ }
12984
+ return out;
12985
+ }
12986
+ parseQueryParamsMap() {
12987
+ const raw = this.columnResolve()?.queryParams;
12988
+ if (raw == null) {
12989
+ return null;
12990
+ }
12991
+ if (typeof raw === 'string') {
12992
+ try {
12993
+ const parsed = JSON.parse(raw);
12994
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
12995
+ ? parsed
12996
+ : null;
12997
+ }
12998
+ catch {
12999
+ return null;
13000
+ }
13001
+ }
13002
+ return raw;
13003
+ }
13004
+ extractItemsFromQueryResult(result) {
13005
+ if (result == null) {
13006
+ return [];
13007
+ }
13008
+ if (Array.isArray(result)) {
13009
+ return result;
13010
+ }
13011
+ const cr = this.columnResolve();
13012
+ const path = cr?.queryResultItemsPath ?? 'items';
13013
+ const nested = get(result, path);
13014
+ return Array.isArray(nested) ? nested : [];
13015
+ }
13016
+ extractItem(item) {
13017
+ if (isNil(item)) {
13018
+ return null;
13019
+ }
13020
+ if (typeof item === 'object') {
13021
+ return item;
13022
+ }
13023
+ return {
13024
+ [this.valueField]: item,
13025
+ [this.textField]: item,
13026
+ };
13027
+ }
12541
13028
  resolveDisplayValue(item) {
12542
13029
  if (isNil(item)) {
12543
13030
  return '';
@@ -12552,18 +13039,18 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
12552
13039
  if (!isNil(rawDisplayValue)) {
12553
13040
  return this.resolveDisplayValue(rawDisplayValue);
12554
13041
  }
12555
- if (this.mlResolver.isValidMultiLanguageObject(item)) {
12556
- return this.mlResolver.resolve(item);
13042
+ if (this.translation.isValidMultiLanguageObject(item)) {
13043
+ return this.translation.resolve(item);
12557
13044
  }
12558
13045
  return '';
12559
13046
  }
12560
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetColumnComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
12561
- 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: "morePopover", first: true, predicate: ["morePopover"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-flex ax-gap-1 ax-items-center\">\n <!-- Visible lookup chips (first N items) -->\n @for (item of visibleItems(); track $index) {\n @let label = getDisplayRaw(item);\n <span [class.ax-cursor-pointer]=\"!options['disableDetailPopover']\"\n [class.hover:ax-text-primary]=\"!options['disableDetailPopover']\"\n [class.hover:ax-underline]=\"!options['disableDetailPopover']\" (click)=\"handleItemClick($index)\">\n {{ label }}\n </span>\n <!-- Separator between chips -->\n @if ($index < visibleItems().length - 1) { <span class=\"ax-text-muted\">\u2022</span>\n }\n }\n <!-- No items -->\n @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n\n <!-- Overflow: open popover with full list -->\n @if (hasMoreItems()) {\n <span\n class=\"ax-absolute ax-flex ax-items-center ax-end-0 ax-px-1 ax-cursor-pointer ax-h-full hover:ax-primary-lighter\"\n (click)=\"showMoreItems()\" #moreButton>\n <i class=\"fa-light fa-ellipsis-vertical\"></i>\n </span>\n }\n</div>\n\n<!-- Full list when user expands overflow -->\n<ax-popover [openOn]=\"'manual'\" #morePopover (openChange)=\"onMorePopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-border ax-rounded-lg ax-shadow-lg ax-p-4 ax-min-w-[280px]\">\n <!-- Popover header -->\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold\">All {{ allItems().length }} Items</h3>\n </div>\n <!-- All items (scrollable) -->\n <div class=\"ax-max-h-64 ax-flex ax-flex-col ax-gap-3\">\n @for (item of allItems(); track $index) {\n @let label = getDisplayRaw(item);\n <span [class.ax-cursor-pointer]=\"!options['disableDetailPopover']\"\n [class.hover:ax-text-primary]=\"!options['disableDetailPopover']\"\n [class.hover:ax-underline]=\"!options['disableDetailPopover']\" (click)=\"showItemDetail(item, $index)\">\n {{ label }}\n </span>\n }\n </div>\n </div>\n</ax-popover>", dependencies: [{ kind: "ngmodule", type: AXBadgeModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "repositionOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13047
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetColumnComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
13048
+ 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\n [class.ax-cursor-pointer]=\"!options['disableDetailPopover']\"\n [class.hover:ax-text-primary]=\"!options['disableDetailPopover']\"\n [class.hover:ax-underline]=\"!options['disableDetailPopover']\"\n (click)=\"handleItemClick($index)\"\n >\n {{ label }}\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 ax-min-w-[280px] ax-rounded-lg ax-border ax-p-4 ax-shadow-lg\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold\">{{ popoverHeader() }}</h3>\n </div>\n\n @if (!isHydratedStrategy() && resolveStatus() === 'loading') {\n <div class=\"ax-flex ax-min-h-[120px] ax-items-center ax-justify-center\">\n <ax-loading></ax-loading>\n </div>\n } @else if (!isHydratedStrategy() && resolveStatus() === 'error') {\n <div class=\"ax-text-danger ax-text-sm\">{{ resolveError() }}</div>\n } @else {\n <div class=\"ax-flex ax-max-h-64 ax-flex-col ax-gap-3\">\n @for (item of popoverListItems(); track $index) {\n @let label = getDisplayRaw(item);\n <span\n [class.ax-cursor-pointer]=\"!options['disableDetailPopover']\"\n [class.hover:ax-text-primary]=\"!options['disableDetailPopover']\"\n [class.hover:ax-underline]=\"!options['disableDetailPopover']\"\n (click)=\"handlePopoverItemClick($index)\"\n >\n {{ label }}\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: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "repositionOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
12562
13049
  }
12563
13050
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetColumnComponent, decorators: [{
12564
13051
  type: Component,
12565
- args: [{ changeDetection: ChangeDetectionStrategy.OnPush, imports: [AXBadgeModule, AXButtonModule, AXPopoverModule], inputs: ['rawValue', 'rowData'], template: "<div class=\"ax-flex ax-gap-1 ax-items-center\">\n <!-- Visible lookup chips (first N items) -->\n @for (item of visibleItems(); track $index) {\n @let label = getDisplayRaw(item);\n <span [class.ax-cursor-pointer]=\"!options['disableDetailPopover']\"\n [class.hover:ax-text-primary]=\"!options['disableDetailPopover']\"\n [class.hover:ax-underline]=\"!options['disableDetailPopover']\" (click)=\"handleItemClick($index)\">\n {{ label }}\n </span>\n <!-- Separator between chips -->\n @if ($index < visibleItems().length - 1) { <span class=\"ax-text-muted\">\u2022</span>\n }\n }\n <!-- No items -->\n @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n\n <!-- Overflow: open popover with full list -->\n @if (hasMoreItems()) {\n <span\n class=\"ax-absolute ax-flex ax-items-center ax-end-0 ax-px-1 ax-cursor-pointer ax-h-full hover:ax-primary-lighter\"\n (click)=\"showMoreItems()\" #moreButton>\n <i class=\"fa-light fa-ellipsis-vertical\"></i>\n </span>\n }\n</div>\n\n<!-- Full list when user expands overflow -->\n<ax-popover [openOn]=\"'manual'\" #morePopover (openChange)=\"onMorePopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-border ax-rounded-lg ax-shadow-lg ax-p-4 ax-min-w-[280px]\">\n <!-- Popover header -->\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold\">All {{ allItems().length }} Items</h3>\n </div>\n <!-- All items (scrollable) -->\n <div class=\"ax-max-h-64 ax-flex ax-flex-col ax-gap-3\">\n @for (item of allItems(); track $index) {\n @let label = getDisplayRaw(item);\n <span [class.ax-cursor-pointer]=\"!options['disableDetailPopover']\"\n [class.hover:ax-text-primary]=\"!options['disableDetailPopover']\"\n [class.hover:ax-underline]=\"!options['disableDetailPopover']\" (click)=\"showItemDetail(item, $index)\">\n {{ label }}\n </span>\n }\n </div>\n </div>\n</ax-popover>" }]
12566
- }], propDecorators: { moreButton: [{ type: i0.ViewChild, args: ['moreButton', { isSignal: true }] }], morePopover: [{ type: i0.ViewChild, args: ['morePopover', { isSignal: true }] }] } });
13052
+ 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\n [class.ax-cursor-pointer]=\"!options['disableDetailPopover']\"\n [class.hover:ax-text-primary]=\"!options['disableDetailPopover']\"\n [class.hover:ax-underline]=\"!options['disableDetailPopover']\"\n (click)=\"handleItemClick($index)\"\n >\n {{ label }}\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 ax-min-w-[280px] ax-rounded-lg ax-border ax-p-4 ax-shadow-lg\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold\">{{ popoverHeader() }}</h3>\n </div>\n\n @if (!isHydratedStrategy() && resolveStatus() === 'loading') {\n <div class=\"ax-flex ax-min-h-[120px] ax-items-center ax-justify-center\">\n <ax-loading></ax-loading>\n </div>\n } @else if (!isHydratedStrategy() && resolveStatus() === 'error') {\n <div class=\"ax-text-danger ax-text-sm\">{{ resolveError() }}</div>\n } @else {\n <div class=\"ax-flex ax-max-h-64 ax-flex-col ax-gap-3\">\n @for (item of popoverListItems(); track $index) {\n @let label = getDisplayRaw(item);\n <span\n [class.ax-cursor-pointer]=\"!options['disableDetailPopover']\"\n [class.hover:ax-text-primary]=\"!options['disableDetailPopover']\"\n [class.hover:ax-underline]=\"!options['disableDetailPopover']\"\n (click)=\"handlePopoverItemClick($index)\"\n >\n {{ label }}\n </span>\n } @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n </div>\n }\n </div>\n</ax-popover>\n" }]
13053
+ }], 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 }] }] } });
12567
13054
 
12568
13055
  var lookupWidgetColumn_component = /*#__PURE__*/Object.freeze({
12569
13056
  __proto__: null,
@@ -12625,6 +13112,100 @@ const AXPLookupWidget = {
12625
13112
  },
12626
13113
  visible: true,
12627
13114
  },
13115
+ {
13116
+ name: 'columnResolveStrategy',
13117
+ title: 'Column resolve strategy',
13118
+ group: AXP_DATA_PROPERTY_GROUP,
13119
+ schema: {
13120
+ dataType: 'string',
13121
+ defaultValue: 'hydrated',
13122
+ interface: {
13123
+ name: 'columnResolveStrategy',
13124
+ path: 'options.columnResolve.strategy',
13125
+ type: AXPWidgetsCatalog.select,
13126
+ valueTransforms: objectKeyValueTransforms('id'),
13127
+ options: {
13128
+ dataSource: [
13129
+ { id: 'hydrated', title: 'Hydrated (titles on row)' },
13130
+ { id: 'idsWithCount', title: 'Ids + count on row (load titles on open)' },
13131
+ { id: 'countOnly', title: 'Count on row (named query on open)' },
13132
+ ],
13133
+ },
13134
+ },
13135
+ },
13136
+ visible: true,
13137
+ },
13138
+ {
13139
+ name: 'columnResolveCountFieldPath',
13140
+ title: 'Column resolve — count field path',
13141
+ group: AXP_DATA_PROPERTY_GROUP,
13142
+ schema: {
13143
+ dataType: 'string',
13144
+ interface: {
13145
+ name: 'columnResolveCountFieldPath',
13146
+ path: 'options.columnResolve.countFieldPath',
13147
+ type: AXPWidgetsCatalog.text,
13148
+ },
13149
+ },
13150
+ visible: true,
13151
+ },
13152
+ {
13153
+ name: 'columnResolveIdsPath',
13154
+ title: 'Column resolve — ids path',
13155
+ group: AXP_DATA_PROPERTY_GROUP,
13156
+ schema: {
13157
+ dataType: 'string',
13158
+ interface: {
13159
+ name: 'columnResolveIdsPath',
13160
+ path: 'options.columnResolve.idsPath',
13161
+ type: AXPWidgetsCatalog.text,
13162
+ },
13163
+ },
13164
+ visible: true,
13165
+ },
13166
+ {
13167
+ name: 'columnResolveQueryKey',
13168
+ title: 'Column resolve — query key (countOnly)',
13169
+ group: AXP_DATA_PROPERTY_GROUP,
13170
+ schema: {
13171
+ dataType: 'string',
13172
+ interface: {
13173
+ name: 'columnResolveQueryKey',
13174
+ path: 'options.columnResolve.queryKey',
13175
+ type: AXPWidgetsCatalog.text,
13176
+ },
13177
+ },
13178
+ visible: true,
13179
+ },
13180
+ {
13181
+ name: 'columnResolveQueryParams',
13182
+ title: 'Column resolve — query params (JSON: param → row path)',
13183
+ group: AXP_DATA_PROPERTY_GROUP,
13184
+ schema: {
13185
+ dataType: 'string',
13186
+ interface: {
13187
+ name: 'columnResolveQueryParams',
13188
+ path: 'options.columnResolve.queryParams',
13189
+ type: AXPWidgetsCatalog.text,
13190
+ },
13191
+ },
13192
+ visible: true,
13193
+ },
13194
+ {
13195
+ name: 'columnResolveQueryResultItemsPath',
13196
+ title: 'Column resolve — query result items path',
13197
+ group: AXP_DATA_PROPERTY_GROUP,
13198
+ schema: {
13199
+ dataType: 'string',
13200
+ defaultValue: 'items',
13201
+ interface: {
13202
+ name: 'columnResolveQueryResultItemsPath',
13203
+ path: 'options.columnResolve.queryResultItemsPath',
13204
+ type: AXPWidgetsCatalog.text,
13205
+ },
13206
+ },
13207
+ visible: true,
13208
+ },
12628
13209
  ],
12629
13210
  components: {
12630
13211
  view: {
@@ -12642,6 +13223,8 @@ const AXPLookupWidget = {
12642
13223
  },
12643
13224
  };
12644
13225
 
13226
+ //#endregion
13227
+
12645
13228
  /**
12646
13229
  * Source type
12647
13230
  */
@@ -15231,13 +15814,18 @@ class AXPDetailsViewBadgeStatusService {
15231
15814
  if (!entityDefinition) {
15232
15815
  return null;
15233
15816
  }
15234
- const statusPlugin = entityDefinition.plugins?.find((p) => p.name === 'status');
15235
- if (!statusPlugin?.options) {
15817
+ const statusPlugins = (entityDefinition.plugins ?? []).filter((p) => p.name === 'status');
15818
+ if (statusPlugins.length === 0) {
15236
15819
  return null;
15237
15820
  }
15238
- const statusOptions = statusPlugin.options;
15821
+ const explicitPrimary = statusPlugins.find((p) => p.options?.isPrimary === true);
15822
+ const primaryPlugin = explicitPrimary ??
15823
+ statusPlugins.find((p) => p.options?.isPrimary !== false) ??
15824
+ statusPlugins[0];
15825
+ const statusOptions = primaryPlugin.options;
15239
15826
  const statusField = statusOptions.field ?? 'statusId';
15240
15827
  const statusDefinitionKey = statusOptions.definition;
15828
+ const pluginReadonly = statusOptions.readonly === true;
15241
15829
  let definitionKey = typeof statusDefinitionKey === 'string' ? statusDefinitionKey : undefined;
15242
15830
  if (!definitionKey) {
15243
15831
  const statusProperty = entityDefinition.properties?.find((p) => p.name === statusField);
@@ -15258,7 +15846,7 @@ class AXPDetailsViewBadgeStatusService {
15258
15846
  definitionKey,
15259
15847
  value: String(value),
15260
15848
  dataPath: statusField,
15261
- readonly: currentPage?.isReadonly ?? false,
15849
+ readonly: pluginReadonly || (currentPage?.isReadonly ?? false),
15262
15850
  };
15263
15851
  }
15264
15852
  catch (error) {
@@ -15307,8 +15895,8 @@ class AXPLayoutAdapterBuilder {
15307
15895
  return this;
15308
15896
  }
15309
15897
  /**
15310
- * Sets the evaluated root title (e.g. "Robert Wilson") used when displaying the adapter title on mobile.
15311
- * Without this, the raw template expression would be shown when showPages is true.
15898
+ * Sets the evaluated root title (e.g. display name) used when displaying the adapter title on mobile.
15899
+ * Accepts a plain string, `@` i18n key, or locale map. Without this, the raw template expression would be shown when showPages is true.
15312
15900
  */
15313
15901
  setRootTitle(rootTitle) {
15314
15902
  this.rootTitle = rootTitle;
@@ -15441,34 +16029,35 @@ class AXPBaseRelatedEntityConverter {
15441
16029
  groups,
15442
16030
  };
15443
16031
  }
15444
- async createGridLayoutStructure(singleInterface, helpers, evaluateExpressions, includeProperties) {
15445
- return await this.createGridLayoutStructureInternal(singleInterface, helpers, evaluateExpressions, includeProperties);
16032
+ createGridLayoutStructure(singleInterface, helpers, includeProperties) {
16033
+ return this.createGridLayoutStructureInternal(singleInterface, helpers, includeProperties);
15446
16034
  }
15447
- //#region ---- Visible Evaluation Helpers ----
15448
- async getVisiblePropertiesByGroupId(sectionId, helpers, evaluateExpressions, includeProperties) {
16035
+ //#region ---- Property visibility (layout) ----
16036
+ /**
16037
+ * Chooses which properties appear in the related-entity grid layout.
16038
+ * Boolean `schema.visible === false` excludes a property. String templates are kept in the layout
16039
+ * and passed on `form-field.options.visible`; `AXPWidgetRendererDirective` uses
16040
+ * `AXPExpressionEvaluatorService` in `updateVisibility()` to evaluate them when context updates.
16041
+ */
16042
+ getVisiblePropertiesByGroupId(sectionId, helpers, includeProperties) {
15449
16043
  let properties = helpers.getPropertyByGroupId(sectionId) ?? [];
15450
16044
  // Filter by includeProperties if provided
15451
16045
  if (includeProperties && includeProperties.length > 0) {
15452
16046
  const includeSet = new Set(includeProperties);
15453
16047
  properties = properties.filter((p) => includeSet.has(p.name));
15454
16048
  }
15455
- const evaluated = await Promise.all(properties.map(async (property) => {
15456
- let visible = property?.schema?.visible;
15457
- if (typeof visible === 'string' && evaluateExpressions) {
15458
- try {
15459
- const result = await evaluateExpressions({ visible });
15460
- visible = result.visible;
15461
- }
15462
- catch {
15463
- visible = true;
15464
- }
16049
+ const evaluated = properties.map((property) => {
16050
+ const visible = property?.schema?.visible;
16051
+ if (typeof visible === 'string') {
16052
+ // Include in layout; runtime evaluation via `AXPExpressionEvaluatorService` (widget renderer).
16053
+ return { property, visible: true };
15465
16054
  }
15466
16055
  return { property, visible: visible ?? true };
15467
- }));
16056
+ });
15468
16057
  return evaluated.filter((x) => x.visible !== false).map((x) => x.property);
15469
16058
  }
15470
- async createPropertyGrid(sectionId, helpers, evaluateExpressions, includeProperties) {
15471
- const visibleProperties = await this.getVisiblePropertiesByGroupId(sectionId, helpers, evaluateExpressions, includeProperties);
16059
+ createPropertyGrid(sectionId, helpers, includeProperties) {
16060
+ const visibleProperties = this.getVisiblePropertiesByGroupId(sectionId, helpers, includeProperties);
15472
16061
  return {
15473
16062
  type: 'grid-layout',
15474
16063
  mode: 'edit',
@@ -15483,6 +16072,15 @@ class AXPBaseRelatedEntityConverter {
15483
16072
  },
15484
16073
  children: visibleProperties.map((p) => {
15485
16074
  const layout = helpers.getPropertyLayout(p.name);
16075
+ const sv = p.schema?.visible;
16076
+ let formFieldVisible;
16077
+ if (typeof sv === 'string') {
16078
+ // Evaluated by `AXPExpressionEvaluatorService` in `AXPWidgetRendererDirective.updateVisibility()`.
16079
+ formFieldVisible = sv;
16080
+ }
16081
+ else if (sv === false) {
16082
+ formFieldVisible = false;
16083
+ }
15486
16084
  return {
15487
16085
  type: 'grid-item-layout',
15488
16086
  name: p.name,
@@ -15497,6 +16095,8 @@ class AXPBaseRelatedEntityConverter {
15497
16095
  options: {
15498
16096
  label: p.title,
15499
16097
  showLabel: layout?.label?.visible ?? true,
16098
+ ...(formFieldVisible !== undefined ? { visible: formFieldVisible } : {}),
16099
+ ...(hintFormFieldOptionsFromDescription(p.description) ?? {}),
15500
16100
  },
15501
16101
  children: [
15502
16102
  {
@@ -15516,13 +16116,15 @@ class AXPBaseRelatedEntityConverter {
15516
16116
  }),
15517
16117
  };
15518
16118
  }
15519
- async createGridLayoutStructureInternal(singleInterface, helpers, evaluateExpressions, includeProperties) {
16119
+ createGridLayoutStructureInternal(singleInterface, helpers, includeProperties) {
15520
16120
  // Filter out empty sections (sections with no visible properties)
15521
- const sectionsWithProperties = await Promise.all((singleInterface?.sections ?? []).map(async (s) => {
15522
- const visibleProperties = await this.getVisiblePropertiesByGroupId(s.id, helpers, evaluateExpressions, includeProperties);
16121
+ const sectionsWithProperties = (singleInterface?.sections ?? []).map((s) => {
16122
+ const visibleProperties = this.getVisiblePropertiesByGroupId(s.id, helpers, includeProperties);
15523
16123
  return { section: s, hasProperties: visibleProperties.length > 0 };
15524
- }));
15525
- const validSections = sectionsWithProperties.filter((item) => item.hasProperties).map((item) => item.section);
16124
+ });
16125
+ const validSections = sectionsWithProperties
16126
+ .filter((item) => item.hasProperties)
16127
+ .map((item) => item.section);
15526
16128
  return {
15527
16129
  type: 'grid-layout',
15528
16130
  options: {
@@ -15534,7 +16136,7 @@ class AXPBaseRelatedEntityConverter {
15534
16136
  },
15535
16137
  },
15536
16138
  },
15537
- children: await Promise.all(validSections.map(async (s) => ({
16139
+ children: validSections.map((s) => ({
15538
16140
  type: 'grid-item-layout',
15539
16141
  name: s.id,
15540
16142
  options: {
@@ -15548,11 +16150,12 @@ class AXPBaseRelatedEntityConverter {
15548
16150
  options: {
15549
16151
  title: helpers.getGroupById(s.id)?.title ?? '',
15550
16152
  collapsible: true,
16153
+ showTitle: s.layout?.label?.visible ?? true,
15551
16154
  },
15552
- children: [await this.createPropertyGrid(s.id, helpers, evaluateExpressions, includeProperties)],
16155
+ children: [this.createPropertyGrid(s.id, helpers, includeProperties)],
15553
16156
  },
15554
16157
  ],
15555
- }))),
16158
+ })),
15556
16159
  };
15557
16160
  }
15558
16161
  }
@@ -15746,7 +16349,7 @@ class AXPPageDetailsConverter extends AXPBaseRelatedEntityConverter {
15746
16349
  const actions = this.buildActions(entityDef, helpers.singleInterface);
15747
16350
  return {
15748
16351
  id: entityDef?.name ?? '',
15749
- title: `${context.rootTitle}`,
16352
+ title: context.rootTitle ?? '',
15750
16353
  label: relatedEntity.title ?? '@general:terms.common.overview',
15751
16354
  icon: relatedEntity.icon || entityDef.icon,
15752
16355
  isReadonly: isPageReadonly,
@@ -15755,7 +16358,7 @@ class AXPPageDetailsConverter extends AXPBaseRelatedEntityConverter {
15755
16358
  execute: this.createExecuteFunction(entityDef, actions, evaluateExpressions, context),
15756
16359
  actions: await this.buildEvaluatedActions(actions, evaluateExpressions),
15757
16360
  // tabs: [...tabDetailTabs, ...tabListTabs],
15758
- content: [await this.createGridLayoutStructure(helpers.singleInterface, helpers, evaluateExpressions, relatedEntity.properties)],
16361
+ content: [this.createGridLayoutStructure(helpers.singleInterface, helpers, relatedEntity.properties)],
15759
16362
  };
15760
16363
  }
15761
16364
  //#region ---- Utility Methods ----
@@ -15988,7 +16591,7 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
15988
16591
  }) ?? []);
15989
16592
  return {
15990
16593
  id: entityDef?.name ?? '',
15991
- title: `${context.rootTitle}`,
16594
+ title: context.rootTitle ?? '',
15992
16595
  label: relatedEntity.title,
15993
16596
  icon: relatedEntity.icon || entityDef.icon,
15994
16597
  actions: this.mergeActions(entityDef, actions)
@@ -16147,6 +16750,7 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
16147
16750
  includeColumns,
16148
16751
  relatedTableColumns,
16149
16752
  customFilterDefinitions: relatedEntity.customFilterDefinitions,
16753
+ excludeProperties: relatedEntity.excludeProperties,
16150
16754
  },
16151
16755
  },
16152
16756
  ],
@@ -16205,7 +16809,7 @@ class AXPTabDetailsConverter extends AXPBaseRelatedEntityConverter {
16205
16809
  title: relatedEntity.title ?? entityDef?.title ?? '',
16206
16810
  icon: relatedEntity.icon || entityDef.icon,
16207
16811
  content: [
16208
- await this.createGridLayoutStructure(helpers.singleInterface, helpers, undefined, relatedEntity.properties),
16812
+ this.createGridLayoutStructure(helpers.singleInterface, helpers, relatedEntity.properties),
16209
16813
  ],
16210
16814
  };
16211
16815
  }
@@ -16265,6 +16869,7 @@ class AXPTabListConverter extends AXPBaseRelatedEntityConverter {
16265
16869
  includeColumns,
16266
16870
  relatedTableColumns,
16267
16871
  customFilterDefinitions: relatedEntity.customFilterDefinitions,
16872
+ excludeProperties: relatedEntity.excludeProperties,
16268
16873
  },
16269
16874
  },
16270
16875
  ],
@@ -16755,12 +17360,27 @@ class AXPMainEntityContentBuilder {
16755
17360
  },
16756
17361
  children: await Promise.all((await Promise.all(combinedSections.map(async (s) => {
16757
17362
  const properties = await getVisiblePropertyByGroupId(s.id);
16758
- const visibleProperties = properties.filter((p) => {
17363
+ const inView = properties.filter((p) => {
16759
17364
  const isFromRelated = p.__dataPath != null;
16760
17365
  const visibleInMain = visiblePropertyNames.has(p.name);
16761
17366
  const visibleInRelated = isFromRelated ? !!p.__layout : false;
16762
17367
  return visibleInMain || visibleInRelated;
16763
17368
  });
17369
+ // String `schema.visible` is not evaluated here (no `dependencies.expressionEvaluator` call).
17370
+ // The template is placed on `form-field.options.visible` below; at render time
17371
+ // `AXPWidgetRendererDirective` injects `AXPExpressionEvaluatorService` and evaluates it in
17372
+ // `updateVisibility()` (and on context changes via `hasVisibilityDependency`). Evaluating once
17373
+ // at build time would freeze visibility and break detail/edit when data changes.
17374
+ const visibilityEvaluated = inView.map((p) => {
17375
+ const v = p.schema?.visible;
17376
+ if (typeof v === 'string') {
17377
+ return { property: p, resolvedVisible: true };
17378
+ }
17379
+ return { property: p, resolvedVisible: v !== false };
17380
+ });
17381
+ const visibleProperties = visibilityEvaluated
17382
+ .filter((x) => x.resolvedVisible)
17383
+ .map((x) => x.property);
16764
17384
  return { section: s, hasProperties: visibleProperties.length > 0, visibleProperties };
16765
17385
  })))
16766
17386
  .filter((item) => item.hasProperties)
@@ -16781,6 +17401,7 @@ class AXPMainEntityContentBuilder {
16781
17401
  collapsible: true,
16782
17402
  isOpen: !s.collapsed,
16783
17403
  look: 'card',
17404
+ showTitle: s.layout?.label?.visible !== false,
16784
17405
  },
16785
17406
  children: [
16786
17407
  {
@@ -16803,6 +17424,15 @@ class AXPMainEntityContentBuilder {
16803
17424
  : editablePropertyNames.has(p.name);
16804
17425
  // Check if property has its own disabled option
16805
17426
  const hasOwnDisabled = p.schema.interface?.options?.disabled !== undefined;
17427
+ let formFieldVisible;
17428
+ const sv = p.schema?.visible;
17429
+ // Template strings are evaluated by `AXPExpressionEvaluatorService` in the widget renderer, not here.
17430
+ if (typeof sv === 'string') {
17431
+ formFieldVisible = sv;
17432
+ }
17433
+ else if (sv === false) {
17434
+ formFieldVisible = false;
17435
+ }
16806
17436
  return {
16807
17437
  type: 'form-field',
16808
17438
  options: {
@@ -16814,7 +17444,8 @@ class AXPMainEntityContentBuilder {
16814
17444
  rowSpan: layout?.positions?.lg?.rowSpan,
16815
17445
  rowStart: layout?.positions?.lg?.rowStart,
16816
17446
  rowEnd: layout?.positions?.lg?.rowEnd,
16817
- visible: p.schema.visible,
17447
+ ...(formFieldVisible !== undefined ? { visible: formFieldVisible } : {}),
17448
+ ...(hintFormFieldOptionsFromDescription(p.description) ?? {}),
16818
17449
  },
16819
17450
  children: [
16820
17451
  {
@@ -17159,8 +17790,18 @@ class AXPLayoutAdapterFactory {
17159
17790
  }
17160
17791
  async getRootTitle(entity, rootContext, dependencies) {
17161
17792
  const titleTemplate = entity.interfaces?.master?.single?.title;
17162
- if (!titleTemplate || typeof titleTemplate !== 'string') {
17163
- return entity?.formats?.individual ?? '';
17793
+ const fallback = entity?.formats?.individual ?? '';
17794
+ if (titleTemplate == null || titleTemplate === '') {
17795
+ return fallback;
17796
+ }
17797
+ if (typeof titleTemplate === 'object' && !Array.isArray(titleTemplate)) {
17798
+ return titleTemplate;
17799
+ }
17800
+ if (typeof titleTemplate !== 'string') {
17801
+ return fallback;
17802
+ }
17803
+ if (!dependencies?.expressionEvaluator) {
17804
+ return titleTemplate;
17164
17805
  }
17165
17806
  const scope = {
17166
17807
  ...rootContext,
@@ -17169,7 +17810,7 @@ class AXPLayoutAdapterFactory {
17169
17810
  },
17170
17811
  };
17171
17812
  const title = await dependencies.expressionEvaluator.evaluate(titleTemplate, scope);
17172
- return typeof title === 'string' ? title : (entity?.formats?.individual ?? '');
17813
+ return title;
17173
17814
  }
17174
17815
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutAdapterFactory, deps: [{ token: AXPRelatedEntityConverterFactory }, { token: AXPMainEntityContentBuilder }, { token: AXPLayoutAdapterBuilder }, { token: i4$4.AXPFilterOperatorMiddlewareService }], target: i0.ɵɵFactoryTarget.Injectable }); }
17175
17816
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutAdapterFactory, providedIn: 'root' }); }
@@ -17193,7 +17834,8 @@ const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver =
17193
17834
  workflowService,
17194
17835
  commandService,
17195
17836
  };
17196
- return await layoutAdapterFactory.createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies);
17837
+ const adapter = await layoutAdapterFactory.createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies);
17838
+ return adapter;
17197
17839
  };
17198
17840
 
17199
17841
  class AXPEntityPreloadFilterGuard {
@@ -17455,8 +18097,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
17455
18097
  }], ctorParameters: () => [] });
17456
18098
 
17457
18099
  /**
17458
- * Default order for common sections
18100
+ * Default shipped rules: narrow identifier + wider title on `md` / `lg`.
17459
18101
  */
18102
+ const DEFAULT_PAIR_SPAN_RULES = [
18103
+ {
18104
+ first: 'code',
18105
+ second: 'title',
18106
+ firstSpan: 4,
18107
+ secondSpan: 8,
18108
+ breakpoints: ['md', 'lg'],
18109
+ },
18110
+ {
18111
+ first: 'name',
18112
+ second: 'title',
18113
+ firstSpan: 4,
18114
+ secondSpan: 8,
18115
+ breakpoints: ['md', 'lg'],
18116
+ },
18117
+ ];
17460
18118
  const DEFAULT_SECTION_ORDER = {
17461
18119
  'basic-info': -100,
17462
18120
  classification: 20,
@@ -17465,32 +18123,23 @@ const DEFAULT_SECTION_ORDER = {
17465
18123
  metadata: 120,
17466
18124
  settings: 200,
17467
18125
  };
17468
- /**
17469
- * Default order for common properties
17470
- * Format: 'sectionId.propertyName' for section-specific or 'propertyName' for any section
17471
- */
17472
18126
  const DEFAULT_PROPERTY_ORDER = {
17473
- // Basic Info section
17474
18127
  'basic-info.code': -10,
17475
18128
  'basic-info.title': -9,
17476
18129
  'basic-info.name': -8,
17477
18130
  'basic-info.description': -7,
17478
18131
  'basic-info.note': -6,
17479
18132
  'basic-info.notes': -5,
17480
- // Classification section
17481
18133
  'classification.categoryIds': 1,
17482
18134
  'classification.tags': 2,
17483
18135
  'classification.type': 3,
17484
- // Appearance section
17485
18136
  'appearance.icon': 1,
17486
18137
  'appearance.color': 2,
17487
18138
  'appearance.avatar': 3,
17488
- // Settings section
17489
18139
  'settings.isDefault': 90,
17490
18140
  'settings.isPrimary': 91,
17491
18141
  'settings.isDisabled': 95,
17492
18142
  'settings.isArchived': 96,
17493
- // Generic fallbacks (apply to any section if not specified above)
17494
18143
  code: 1,
17495
18144
  title: 2,
17496
18145
  name: 3,
@@ -17505,23 +18154,111 @@ const DEFAULT_PROPERTY_ORDER = {
17505
18154
  isDisabled: 95,
17506
18155
  isArchived: 96,
17507
18156
  };
17508
- /**
17509
- * Get the property order for a given section and property name
17510
- */
18157
+ const DEFAULT_PAIR_BREAKPOINTS = ['md', 'lg'];
18158
+ function applyPairSpanRules(layout, rules, getGroupId) {
18159
+ if (!layout.properties?.length || rules.length === 0) {
18160
+ return;
18161
+ }
18162
+ const namesByGroup = new Map();
18163
+ for (const prop of layout.properties) {
18164
+ if (!prop.name)
18165
+ continue;
18166
+ const gid = getGroupId(prop.name);
18167
+ if (!gid)
18168
+ continue;
18169
+ if (!namesByGroup.has(gid)) {
18170
+ namesByGroup.set(gid, new Set());
18171
+ }
18172
+ namesByGroup.get(gid).add(prop.name);
18173
+ }
18174
+ const findPropView = (name) => layout.properties.find((p) => p.name === name);
18175
+ const spanIfUnset = (pv, breakpoint, span) => {
18176
+ if (!pv.layout)
18177
+ pv.layout = {};
18178
+ let positions = pv.layout['positions'] ?? undefined;
18179
+ if (!positions) {
18180
+ positions = {};
18181
+ pv.layout['positions'] = positions;
18182
+ }
18183
+ const cell = positions[breakpoint] ?? {};
18184
+ positions[breakpoint] = cell;
18185
+ if (cell.colSpan === undefined)
18186
+ cell.colSpan = span;
18187
+ };
18188
+ for (const namesInGroup of namesByGroup.values()) {
18189
+ for (const rule of rules) {
18190
+ if (!namesInGroup.has(rule.first) || !namesInGroup.has(rule.second))
18191
+ continue;
18192
+ if (rule.first === 'name' && rule.second === 'title' && namesInGroup.has('code')) {
18193
+ continue;
18194
+ }
18195
+ const a = findPropView(rule.first);
18196
+ const b = findPropView(rule.second);
18197
+ if (!a || !b)
18198
+ continue;
18199
+ const breakpoints = rule.breakpoints?.length ? rule.breakpoints : DEFAULT_PAIR_BREAKPOINTS;
18200
+ for (const bp of breakpoints)
18201
+ spanIfUnset(a, bp, rule.firstSpan);
18202
+ for (const bp of breakpoints)
18203
+ spanIfUnset(b, bp, rule.secondSpan);
18204
+ break;
18205
+ }
18206
+ }
18207
+ }
17511
18208
  const getPropertyOrder = (sectionId, propertyName, orderConfig) => {
17512
- // Try section-specific order first
17513
18209
  if (sectionId) {
17514
18210
  const sectionSpecific = orderConfig[`${sectionId}.${propertyName}`];
17515
- if (sectionSpecific !== undefined) {
18211
+ if (sectionSpecific !== undefined)
17516
18212
  return sectionSpecific;
17517
- }
17518
18213
  }
17519
- // Fall back to generic property order
17520
18214
  return orderConfig[propertyName];
17521
18215
  };
17522
18216
  /**
17523
- * Factory to create a layout ordering middleware
18217
+ * True when the entity already defined sort order for this property view.
18218
+ * Middleware default order applies only when this is false (entity layout takes priority).
17524
18219
  */
18220
+ function hasExplicitLayoutOrder(prop) {
18221
+ const layout = prop.layout;
18222
+ if (!layout || typeof layout !== 'object') {
18223
+ return false;
18224
+ }
18225
+ if (layout['order'] !== undefined && layout['order'] !== null) {
18226
+ return true;
18227
+ }
18228
+ const positions = layout['positions'];
18229
+ if (!positions || typeof positions !== 'object') {
18230
+ return false;
18231
+ }
18232
+ for (const key of Object.keys(positions)) {
18233
+ const cell = positions[key];
18234
+ if (cell && typeof cell === 'object' && cell['order'] !== undefined && cell['order'] !== null) {
18235
+ return true;
18236
+ }
18237
+ }
18238
+ return false;
18239
+ }
18240
+ function resolveViewPropertySortOrder(prop) {
18241
+ const toNum = (v) => {
18242
+ if (v === undefined || v === null)
18243
+ return null;
18244
+ const n = Number(v);
18245
+ return Number.isFinite(n) ? n : null;
18246
+ };
18247
+ const layout = prop.layout;
18248
+ if (!layout)
18249
+ return 999;
18250
+ const primary = toNum(layout['order']);
18251
+ if (primary !== null)
18252
+ return primary;
18253
+ const positions = layout['positions'];
18254
+ const lg = toNum(positions?.['lg']?.order);
18255
+ if (lg !== null)
18256
+ return lg;
18257
+ const md = toNum(positions?.['md']?.order);
18258
+ if (md !== null)
18259
+ return md;
18260
+ return 999;
18261
+ }
17525
18262
  const layoutOrderingMiddlewareFactory = (config) => {
17526
18263
  return (context) => {
17527
18264
  const configService = inject(AXPLayoutOrderingConfigService);
@@ -17529,64 +18266,51 @@ const layoutOrderingMiddlewareFactory = (config) => {
17529
18266
  return;
17530
18267
  }
17531
18268
  const { sections: sectionOrder, properties: propertyOrder } = config;
17532
- //#region ---- Order Sections ----
18269
+ const pairRules = config.pairSpanRules === false
18270
+ ? []
18271
+ : config.pairSpanRules?.length
18272
+ ? config.pairSpanRules
18273
+ : [...DEFAULT_PAIR_SPAN_RULES];
17533
18274
  const orderSections = (layout) => {
17534
- if (!layout || !layout.sections) {
18275
+ if (!layout?.sections)
17535
18276
  return;
17536
- }
17537
18277
  layout.sections.forEach((section) => {
17538
18278
  const defaultOrder = sectionOrder[section.id];
17539
- if (defaultOrder !== undefined) {
17540
- // Always apply the default order if configured (force override)
18279
+ if (defaultOrder !== undefined && section.order === undefined) {
17541
18280
  section.order = defaultOrder;
17542
18281
  }
17543
- else {
17544
- // console.log(`[Layout Ordering Middleware] No default order for section "${section.id}"`);
17545
- }
17546
18282
  });
17547
- // Sort sections by order
17548
18283
  layout.sections.sort((a, b) => {
17549
18284
  const orderA = a.order ?? 999;
17550
18285
  const orderB = b.order ?? 999;
17551
18286
  return orderA - orderB;
17552
18287
  });
17553
18288
  };
17554
- //#endregion
17555
- //#region ---- Order Properties Within Sections ----
17556
18289
  const orderProperties = (layout) => {
17557
- if (!layout || !layout.properties) {
18290
+ if (!layout?.properties)
17558
18291
  return;
17559
- }
17560
18292
  layout.properties.forEach((prop) => {
17561
18293
  const groupId = context.properties.find(prop.name).get()?.groupId;
17562
18294
  const defaultOrder = getPropertyOrder(groupId, prop.name, propertyOrder);
17563
- if (defaultOrder !== undefined) {
17564
- // Ensure layout.positions exists
17565
- if (!prop.layout) {
18295
+ if (defaultOrder !== undefined && !hasExplicitLayoutOrder(prop)) {
18296
+ if (!prop.layout)
17566
18297
  prop.layout = {};
17567
- }
17568
- if (!prop.layout.positions) {
18298
+ if (prop.layout.order === undefined)
18299
+ prop.layout.order = defaultOrder;
18300
+ if (!prop.layout.positions)
17569
18301
  prop.layout.positions = {};
17570
- }
17571
- if (!prop.layout.positions.lg) {
18302
+ if (!prop.layout.positions.lg)
17572
18303
  prop.layout.positions.lg = {};
17573
- }
17574
- // Set order if not already defined
17575
18304
  if (prop.layout.positions.lg.order === undefined) {
17576
18305
  prop.layout.positions.lg.order = defaultOrder;
17577
18306
  }
17578
18307
  }
17579
18308
  });
17580
- // Sort properties by order
17581
- layout.properties.sort((a, b) => {
17582
- const orderA = a.layout?.positions?.lg?.order ?? 999;
17583
- const orderB = b.layout?.positions?.lg?.order ?? 999;
17584
- return orderA - orderB;
17585
- });
18309
+ layout.properties.sort((a, b) => resolveViewPropertySortOrder(a) - resolveViewPropertySortOrder(b));
18310
+ if (pairRules.length > 0) {
18311
+ applyPairSpanRules(layout, pairRules, (propertyName) => context.properties.find(propertyName).get()?.groupId);
18312
+ }
17586
18313
  };
17587
- //#endregion
17588
- //#region ---- Apply to All Layouts ----
17589
- // Apply to create layout
17590
18314
  context.interfaces.master.create.update((create) => {
17591
18315
  if (create) {
17592
18316
  orderSections(create);
@@ -17594,7 +18318,6 @@ const layoutOrderingMiddlewareFactory = (config) => {
17594
18318
  }
17595
18319
  return create ?? { sections: [], properties: [] };
17596
18320
  });
17597
- // Apply to modify layout
17598
18321
  context.interfaces.master.modify.update((modify) => {
17599
18322
  if (modify) {
17600
18323
  orderSections(modify);
@@ -17602,7 +18325,6 @@ const layoutOrderingMiddlewareFactory = (config) => {
17602
18325
  }
17603
18326
  return modify ?? { sections: [], properties: [] };
17604
18327
  });
17605
- // Apply to single layout
17606
18328
  context.interfaces.master.single.update((single) => {
17607
18329
  if (single) {
17608
18330
  orderSections(single);
@@ -17610,27 +18332,20 @@ const layoutOrderingMiddlewareFactory = (config) => {
17610
18332
  }
17611
18333
  return single ?? { title: context.entity.title, sections: [], properties: [] };
17612
18334
  });
17613
- //#endregion
17614
- };
17615
- };
17616
- //#endregion
17617
- //#region ---- Provider Registration ----
17618
- /**
17619
- * Helper to create a provider for the layout ordering middleware
17620
- * By default it applies to all entities using the '*' pattern
17621
- */
17622
- const createLayoutOrderingMiddlewareProvider = (config = {}, entityName = '*') => {
17623
- return {
17624
- entityName,
17625
- modifier: layoutOrderingMiddlewareFactory({
17626
- sections: { ...DEFAULT_SECTION_ORDER, ...config.sections },
17627
- properties: { ...DEFAULT_PROPERTY_ORDER, ...config.properties },
17628
- }),
17629
18335
  };
17630
18336
  };
17631
- /**
17632
- * Default provider registered with the default configuration
17633
- */
18337
+ const createLayoutOrderingMiddlewareProvider = (config = {}, entityName = '*') => ({
18338
+ entityName,
18339
+ modifier: layoutOrderingMiddlewareFactory({
18340
+ sections: { ...DEFAULT_SECTION_ORDER, ...config.sections },
18341
+ properties: { ...DEFAULT_PROPERTY_ORDER, ...config.properties },
18342
+ pairSpanRules: config.pairSpanRules === false
18343
+ ? false
18344
+ : config.pairSpanRules !== undefined
18345
+ ? config.pairSpanRules
18346
+ : undefined,
18347
+ }),
18348
+ });
17634
18349
  const layoutOrderingMiddlewareProvider = createLayoutOrderingMiddlewareProvider();
17635
18350
  //#endregion
17636
18351
 
@@ -18281,8 +18996,7 @@ class AXPShowFileUploaderPopupAction extends AXPWorkflowAction {
18281
18996
  const fileEditable = context.getVariable('options.fileEditable');
18282
18997
  const enableTitleDescription = context.getVariable('options.enableTitleDescription');
18283
18998
  const showEditDialogAfterSelect = context.getVariable('options.showEditDialogAfterSelect');
18284
- //check is correct file
18285
- const correctFiles = files.filter((item) => item != undefined);
18999
+ const correctFiles = (files ?? []).filter((item) => item != null && typeof item === 'object' && typeof item.name === 'string');
18286
19000
  // *********** show file list ***********
18287
19001
  const res = await this.fileUploaderWidgetService.showFileList({
18288
19002
  files: correctFiles,
@@ -19171,5 +19885,5 @@ function detectEntityChanges(oldObj, newObj) {
19171
19885
  * Generated bundle index. Do not edit.
19172
19886
  */
19173
19887
 
19174
- export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCategoryTreeService, AXPCreateEntityCommand, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntitiesListDataSourceDefinition, AXPEntityApplyUpdatesAction, AXPEntityCategoryTreeSelectorComponent, AXPEntityCategoryWidget, AXPEntityCategoryWidgetColumnComponent, AXPEntityCategoryWidgetEditComponent, AXPEntityCategoryWidgetViewComponent, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDataSelectorService, AXPEntityDefinitionProviderWidget, AXPEntityDefinitionProviderWidgetEditComponent, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailPopoverComponent, AXPEntityDetailPopoverService, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityEventsKeys, AXPEntityFormBuilderService, AXPEntityListTableService, AXPEntityListToolbarService, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityListWidget, AXPEntityListWidgetViewComponent, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityPreloadFiltersContainerComponent, AXPEntityPreloadFiltersViewModel, AXPEntityPreloadFiltersViewModelResolver, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPEntityUpdateViewSectionViewModel, 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_PROPERTY_ORDER, DEFAULT_SECTION_ORDER, EntityBuilder, EntityDataAccessor, actionExists, axpCreateEntityAiToolInputDefaults, axpCreateEntityCommandDefinition, cloneLayoutArrays, columnOrderingMiddleware, columnOrderingMiddlewareProvider, columnWidthMiddleware, columnWidthMiddlewareProvider, createColumnOrderingMiddlewareProvider, createLayoutOrderingMiddlewareProvider, createModifierContext, defaultMultiLanguageMiddleware, defaultMultiLanguageMiddlewareProvider, detectEntityChanges, ensureLayoutPropertyView, ensureLayoutSection, ensureListActions, entityDetailsCreateActions, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsNewEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterEditAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware, isAXPMiddlewareAbortError, layoutOrderingMiddlewareFactory, layoutOrderingMiddlewareProvider, provideEntity, resolveEntityPluginDetailPageOrder, searchResultDescriptionMiddleware, searchResultDescriptionMiddlewareProvider };
19888
+ export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCategoryTreeService, AXPCreateEntityCommand, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntitiesListDataSourceDefinition, AXPEntityApplyUpdatesAction, AXPEntityCategoryTreeSelectorComponent, AXPEntityCategoryWidget, AXPEntityCategoryWidgetColumnComponent, AXPEntityCategoryWidgetEditComponent, AXPEntityCategoryWidgetViewComponent, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDataSelectorService, AXPEntityDefinitionProviderWidget, AXPEntityDefinitionProviderWidgetEditComponent, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailPopoverComponent, AXPEntityDetailPopoverService, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityEventsKeys, AXPEntityFormBuilderService, AXPEntityListTableService, AXPEntityListToolbarService, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityListWidget, AXPEntityListWidgetViewComponent, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityPreloadFiltersContainerComponent, AXPEntityPreloadFiltersViewModel, AXPEntityPreloadFiltersViewModelResolver, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPEntityUpdateViewSectionViewModel, 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, EntityBuilder, EntityDataAccessor, actionExists, axpCreateEntityAiToolInputDefaults, axpCreateEntityCommandDefinition, cloneLayoutArrays, columnOrderingMiddleware, columnOrderingMiddlewareProvider, columnWidthMiddleware, columnWidthMiddlewareProvider, createColumnOrderingMiddlewareProvider, createLayoutOrderingMiddlewareProvider, createModifierContext, defaultMultiLanguageMiddleware, defaultMultiLanguageMiddlewareProvider, detectEntityChanges, ensureLayoutPropertyView, ensureLayoutSection, ensureListActions, entityDetailsCreateActions, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsNewEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterEditAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware, getMasterInterfacePropertySortKey, isAXPMiddlewareAbortError, layoutOrderingMiddlewareFactory, layoutOrderingMiddlewareProvider, provideEntity, resolveEntityPluginDetailPageOrder, searchResultDescriptionMiddleware, searchResultDescriptionMiddlewareProvider };
19175
19889
  //# sourceMappingURL=acorex-platform-layout-entity.mjs.map