@acorex/platform 21.0.0-next.71 → 21.0.0-next.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/acorex-platform-auth.mjs +10 -2
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/{acorex-platform-common-common-settings.provider-Bi1RYif5.mjs → acorex-platform-common-common-settings.provider-Ytey9uhY.mjs} +15 -1
- package/fesm2022/acorex-platform-common-common-settings.provider-Ytey9uhY.mjs.map +1 -0
- package/fesm2022/acorex-platform-common.mjs +3792 -1679
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +1112 -103
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +53 -170
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +70 -46
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +199 -126
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-entity-attachments-page.component-D8iQnT-R.mjs → acorex-platform-layout-entity-attachments-page.component-B0EkdqvH.mjs} +6 -1
- package/fesm2022/acorex-platform-layout-entity-attachments-page.component-B0EkdqvH.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-entity.mjs +341 -418
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +675 -301
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +115 -74
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-BcpRkpJp.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs} +2 -2
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-BcpRkpJp.mjs.map → acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs.map} +1 -1
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-DQtK4lxl.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs} +2 -2
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-DQtK4lxl.mjs.map → acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs.map} +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs +184 -655
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-default-error-401.component-B1nsdpTY.mjs +48 -0
- package/fesm2022/acorex-platform-themes-default-error-401.component-B1nsdpTY.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-error-404.component-D4UvRe8u.mjs +42 -0
- package/fesm2022/acorex-platform-themes-default-error-404.component-D4UvRe8u.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +76 -32
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/package.json +1 -1
- package/types/acorex-platform-auth.d.ts +2 -0
- package/types/acorex-platform-common.d.ts +891 -259
- package/types/acorex-platform-core.d.ts +284 -40
- package/types/acorex-platform-layout-builder.d.ts +10 -22
- package/types/acorex-platform-layout-components.d.ts +9 -7
- package/types/acorex-platform-layout-entity.d.ts +37 -41
- package/types/acorex-platform-layout-views.d.ts +125 -67
- package/types/acorex-platform-layout-widget-core.d.ts +53 -61
- package/types/acorex-platform-layout-widgets.d.ts +33 -20
- package/types/acorex-platform-themes-default.d.ts +14 -4
- package/fesm2022/acorex-platform-common-common-settings.provider-Bi1RYif5.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-entity-attachments-page.component-D8iQnT-R.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs +0 -31
- package/fesm2022/acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs +0 -25
- package/fesm2022/acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs.map +0 -1
|
@@ -2,7 +2,7 @@ import { AXToastService } from '@acorex/components/toast';
|
|
|
2
2
|
import * as i6 from '@acorex/core/translation';
|
|
3
3
|
import { AXTranslationService, AXTranslationModule, resolveMultiLanguageString, translateSync } from '@acorex/core/translation';
|
|
4
4
|
import * as i4$3 from '@acorex/platform/common';
|
|
5
|
-
import { AXPEntityCommandScope, AXPSettingsService, AXPCommonSettings, AXPFilterOperatorMiddlewareService, isCardFieldBadgeDisplay, resolveCardFieldBadgeColor, getEntityInfo, resolveEnabledMasterListLayouts, resolveDefaultMasterListLayout, AXPRefreshEvent, AXPReloadEvent, AXPCleanNestedFilters, AXPFileTypeProviderService, AXPFileStorageService, AXPFileActionsService, AXPDefaultMultiLanguageConfigService, withDefaultMultiLanguageOnWidgetNodeTree, AXPEntityQueryType, AXPWorkflowNavigateAction, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER, AXPMenuItemsDataSourceDefinition } from '@acorex/platform/common';
|
|
5
|
+
import { AXPNotFoundError, AXPEntityCommandScope, axpNavigateAppPath, AXPSettingsService, AXPCommonSettings, normalizeEntityDisplayTemplate, isUnresolvedEntityDisplayTemplate, AXPFilterOperatorMiddlewareService, isCardFieldBadgeDisplay, resolveCardFieldBadgeColor, getEntityInfo, resolveEnabledMasterListLayouts, resolveDefaultMasterListLayout, AXPRefreshEvent, AXPReloadEvent, axpRedirectToNotFound, AXPCleanNestedFilters, AXPFileTypeProviderService, AXPFileStorageService, buildEntitySearchTitleContext, resolveEntityRowTitleTemplate, AXPFileActionsService, axpIsEntityRecordNotFound, AXPDefaultMultiLanguageConfigService, withDefaultMultiLanguageOnWidgetNodeTree, AXPEntityQueryType, AXPWorkflowNavigateAction, AXP_NOT_FOUND_ROUTE, AXP_PROTECTED_ROUTE_GUARDS, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER, AXPMenuItemsDataSourceDefinition } from '@acorex/platform/common';
|
|
6
6
|
import * as i0 from '@angular/core';
|
|
7
7
|
import { InjectionToken, inject, Injector, runInInjectionContext, Injectable, input, viewChild, signal, computed, ElementRef, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent, NgModule, ChangeDetectorRef, effect, Input, afterNextRender, untracked, ViewEncapsulation, viewChildren, linkedSignal, HostBinding, output, makeEnvironmentProviders } from '@angular/core';
|
|
8
8
|
import { Subject, takeUntil } from 'rxjs';
|
|
@@ -12,7 +12,7 @@ import { AXPWidgetsCatalog, AXPWidgetCoreModule, AXPPageStatus, AXPWidgetRegistr
|
|
|
12
12
|
import { AXPSystemActionType, AXPDeviceService, AXPExpressionEvaluatorService, AXPBroadcastEventService, applyFilterArray, applySortArray, resolveActionLook, AXPDistributedEventListenerService, AXPPlatformScope, AXHighlightService, extractValue, setSmart, getChangedPaths, objectKeyValueTransforms, AXPHookService, AXPDataGenerator, AXPComponentSlotModule, AXPContextStore, AXPColumnWidthService, AXPModuleManifestRegistry, defaultColumnWidthProvider, AXP_COLUMN_WIDTH_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXPModuleManifestsDataSourceDefinition } from '@acorex/platform/core';
|
|
13
13
|
import { cloneDeep, merge, get, castArray, set, orderBy, omit, isNil, isEmpty, isEqual as isEqual$1, isArray, isString } from 'lodash-es';
|
|
14
14
|
import { transform, isEqual } from 'lodash';
|
|
15
|
-
import { AXPSessionService,
|
|
15
|
+
import { AXPSessionService, AXPPermissionDefinitionsDataSourceDefinition } from '@acorex/platform/auth';
|
|
16
16
|
import { Router, ActivatedRoute, RouterModule, ROUTES } from '@angular/router';
|
|
17
17
|
import { defineCommand, AXP_COMMAND_DEFINITION_CATEGORY_ENTITY, AXPCommandService, AXPQueryService, AXPQueryExecutor, AXPCommandExecutor, provideCommandSetups, provideQuerySetups, AXPCommandRegistry, AXPQueryRegistry } from '@acorex/platform/runtime';
|
|
18
18
|
import * as i1 from '@acorex/components/button';
|
|
@@ -25,7 +25,7 @@ import { AXFormatService } from '@acorex/core/format';
|
|
|
25
25
|
import * as i5 from '@angular/common';
|
|
26
26
|
import { CommonModule, AsyncPipe, NgClass } from '@angular/common';
|
|
27
27
|
import { AXPThemeLayoutBlockComponent, AXPPreloadFiltersComponent, AXP_PAGE_COMPONENT_PROVIDER, AXPStateMessageComponent, AXPColumnItemListComponent, AXPDataSelectorService, AXPPageComponentRegistryService } from '@acorex/platform/layout/components';
|
|
28
|
-
import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageComponentRendererDirective, AXPPageComponentInstanceRegistryService } from '@acorex/platform/layout/views';
|
|
28
|
+
import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageComponentRendererDirective, AXPPageComponentInstanceRegistryService, axpDetailsViewCanDeactivateGuard } from '@acorex/platform/layout/views';
|
|
29
29
|
import { AXDataSource } from '@acorex/cdk/common';
|
|
30
30
|
import { AXP_ENTITY_CRUD_SETUP } from '@acorex/platform/domain';
|
|
31
31
|
export { AXP_ENTITY_DEFINITION_CRUD_SERVICE } from '@acorex/platform/domain';
|
|
@@ -823,7 +823,7 @@ class AXPEntityDefinitionRegistryService {
|
|
|
823
823
|
throw error; // Rethrow to allow error handling by caller
|
|
824
824
|
}
|
|
825
825
|
if (!config) {
|
|
826
|
-
throw new
|
|
826
|
+
throw new AXPNotFoundError(`Invalid entity name: ${key}`);
|
|
827
827
|
}
|
|
828
828
|
}
|
|
829
829
|
return config;
|
|
@@ -902,6 +902,7 @@ function entityMasterDeleteAction() {
|
|
|
902
902
|
type: AXPSystemActionType.Delete,
|
|
903
903
|
scope: AXPEntityCommandScope.Individual,
|
|
904
904
|
order: 100,
|
|
905
|
+
shortcuts: ['ctrl+shift+delete'],
|
|
905
906
|
};
|
|
906
907
|
}
|
|
907
908
|
function entityMasterCrudActions(options) {
|
|
@@ -2498,8 +2499,7 @@ class AXPOpenEntityDetailsCommand {
|
|
|
2498
2499
|
};
|
|
2499
2500
|
}
|
|
2500
2501
|
const url = `/${this.sessionService.application?.name}/m/${module}/e/${entityName}/${data.id}/view`;
|
|
2501
|
-
|
|
2502
|
-
this.router.navigate([url]);
|
|
2502
|
+
await axpNavigateAppPath(this.router, url);
|
|
2503
2503
|
return {
|
|
2504
2504
|
success: true,
|
|
2505
2505
|
};
|
|
@@ -2972,17 +2972,6 @@ var viewEntityDetails_command = /*#__PURE__*/Object.freeze({
|
|
|
2972
2972
|
});
|
|
2973
2973
|
|
|
2974
2974
|
//#region ---- Template resolution ----
|
|
2975
|
-
/**
|
|
2976
|
-
* Normalizes lookup/search display templates for row-based formatting.
|
|
2977
|
-
* Converts `context.eval('path')` expressions to `{{ path }}` and single braces to mustache form.
|
|
2978
|
-
*/
|
|
2979
|
-
function normalizeLookupDisplayTemplate(template) {
|
|
2980
|
-
const withContextEval = template.replace(/\{\{\s*context\.eval\(['"]([^'"]+)['"]\)\s*\}\}/g, '{{ $1 }}');
|
|
2981
|
-
if (withContextEval.includes('{{')) {
|
|
2982
|
-
return withContextEval;
|
|
2983
|
-
}
|
|
2984
|
-
return withContextEval.replace(/\{/g, '{{').replace(/\}/g, '}}');
|
|
2985
|
-
}
|
|
2986
2975
|
/**
|
|
2987
2976
|
* Resolves the display template for a lookup item.
|
|
2988
2977
|
* Priority: explicit `displayFormat` → entity `formats.lookup` (template) → entity `formats.searchResult.title`.
|
|
@@ -2991,18 +2980,18 @@ function normalizeLookupDisplayTemplate(template) {
|
|
|
2991
2980
|
function resolveLookupDisplayTemplate(entity, options) {
|
|
2992
2981
|
const explicit = options.displayFormat?.trim();
|
|
2993
2982
|
if (explicit) {
|
|
2994
|
-
return
|
|
2983
|
+
return normalizeEntityDisplayTemplate(explicit);
|
|
2995
2984
|
}
|
|
2996
2985
|
if (options.textField?.trim()) {
|
|
2997
2986
|
return undefined;
|
|
2998
2987
|
}
|
|
2999
2988
|
const lookupFormat = entity?.formats?.lookup?.trim();
|
|
3000
2989
|
if (lookupFormat && (lookupFormat.includes('{{') || lookupFormat.includes('{'))) {
|
|
3001
|
-
return
|
|
2990
|
+
return normalizeEntityDisplayTemplate(lookupFormat);
|
|
3002
2991
|
}
|
|
3003
2992
|
const searchTitle = entity?.formats?.searchResult?.title?.trim();
|
|
3004
2993
|
if (searchTitle) {
|
|
3005
|
-
return
|
|
2994
|
+
return normalizeEntityDisplayTemplate(searchTitle);
|
|
3006
2995
|
}
|
|
3007
2996
|
return undefined;
|
|
3008
2997
|
}
|
|
@@ -3043,7 +3032,7 @@ function formatLookupItemDisplay(item, entity, options, formatService, resolveMu
|
|
|
3043
3032
|
const formatted = formatService.format(template, 'string', item);
|
|
3044
3033
|
if (formatted) {
|
|
3045
3034
|
const text = String(formatted);
|
|
3046
|
-
if (!
|
|
3035
|
+
if (!isUnresolvedEntityDisplayTemplate(text)) {
|
|
3047
3036
|
return text;
|
|
3048
3037
|
}
|
|
3049
3038
|
}
|
|
@@ -3064,10 +3053,6 @@ function formatLookupItemDisplay(item, entity, options, formatService, resolveMu
|
|
|
3064
3053
|
}
|
|
3065
3054
|
return String(raw);
|
|
3066
3055
|
}
|
|
3067
|
-
/** True when a formatted label still contains unresolved template markers. */
|
|
3068
|
-
function isUnresolvedLookupDisplayTemplate(value) {
|
|
3069
|
-
return /\{\{/.test(value) || /context\.eval\s*\(/.test(value);
|
|
3070
|
-
}
|
|
3071
3056
|
//#endregion
|
|
3072
3057
|
|
|
3073
3058
|
class AXPEntityDetailPopoverComponent {
|
|
@@ -3107,7 +3092,7 @@ class AXPEntityDetailPopoverComponent {
|
|
|
3107
3092
|
}
|
|
3108
3093
|
}
|
|
3109
3094
|
const preset = this.displayTitle()?.trim();
|
|
3110
|
-
if (preset && !
|
|
3095
|
+
if (preset && !isUnresolvedEntityDisplayTemplate(preset)) {
|
|
3111
3096
|
return preset;
|
|
3112
3097
|
}
|
|
3113
3098
|
const fallbackItem = this.item();
|
|
@@ -3206,7 +3191,7 @@ class AXPEntityDetailPopoverComponent {
|
|
|
3206
3191
|
resolveLookupDisplayLabel(item, entityDefinition) {
|
|
3207
3192
|
const label = formatLookupItemDisplay(item, entityDefinition, { textField: this.textField() }, this.formatService, (value) => this.translation.resolve(value));
|
|
3208
3193
|
const resolved = typeof label === 'string' ? label : this.translation.resolve(label);
|
|
3209
|
-
return resolved && !
|
|
3194
|
+
return resolved && !isUnresolvedEntityDisplayTemplate(resolved) ? resolved : '';
|
|
3210
3195
|
}
|
|
3211
3196
|
/**
|
|
3212
3197
|
* Returns true if a value is meaningful for display (non-empty/non-null).
|
|
@@ -4356,6 +4341,7 @@ class AXPEntityCommandTriggerViewModel {
|
|
|
4356
4341
|
this.hidden = action.hidden ?? false;
|
|
4357
4342
|
this.disabled = action.disabled ?? false;
|
|
4358
4343
|
this.default = action.default ?? false;
|
|
4344
|
+
this.shortcuts = action.shortcuts;
|
|
4359
4345
|
this.scope = action.scope;
|
|
4360
4346
|
this.order = action.order ?? 0;
|
|
4361
4347
|
this.isChild = isChild;
|
|
@@ -6642,20 +6628,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
6642
6628
|
type: Injectable,
|
|
6643
6629
|
args: [{ providedIn: 'root' }]
|
|
6644
6630
|
}] });
|
|
6645
|
-
const AXPEntityListViewModelResolver = async (route, state, service = inject(AXPEntityListViewModelFactory)) => {
|
|
6631
|
+
const AXPEntityListViewModelResolver = async (route, state, service = inject(AXPEntityListViewModelFactory), router = inject(Router)) => {
|
|
6646
6632
|
const moduleName = route.parent?.paramMap.get('module');
|
|
6647
6633
|
const entityName = route.paramMap.get('entity');
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6634
|
+
try {
|
|
6635
|
+
const vm = await service.create(moduleName, entityName);
|
|
6636
|
+
// Check if filters are provided in query params
|
|
6637
|
+
const filtersParam = route.queryParamMap.get('filters');
|
|
6638
|
+
if (filtersParam) {
|
|
6639
|
+
const applied = vm.applyFiltersFromQueryParams(filtersParam);
|
|
6640
|
+
if (applied) {
|
|
6641
|
+
// Trigger filter and sort application
|
|
6642
|
+
await vm.applyFilterAndSort();
|
|
6643
|
+
}
|
|
6644
|
+
}
|
|
6645
|
+
return vm;
|
|
6646
|
+
}
|
|
6647
|
+
catch (error) {
|
|
6648
|
+
if (error instanceof AXPNotFoundError) {
|
|
6649
|
+
return axpRedirectToNotFound(router);
|
|
6656
6650
|
}
|
|
6651
|
+
throw error;
|
|
6657
6652
|
}
|
|
6658
|
-
return vm;
|
|
6659
6653
|
};
|
|
6660
6654
|
|
|
6661
6655
|
const AXPEntityDeletedEvent = createWorkFlowEvent('[Entity] Deleted');
|
|
@@ -6706,7 +6700,7 @@ class AXPEntityPerformDeleteAction extends AXPWorkflowAction {
|
|
|
6706
6700
|
dialog = this.loadingDialog.show({
|
|
6707
6701
|
title: await this.translationService.translateAsync('@general:workflow.deleting'),
|
|
6708
6702
|
mode: 'determinate',
|
|
6709
|
-
status: '
|
|
6703
|
+
status: await this.translationService.translateAsync('@general:workflow.deleting'),
|
|
6710
6704
|
progressValue: 0,
|
|
6711
6705
|
text: `0/${idLength}`,
|
|
6712
6706
|
buttons: [
|
|
@@ -7467,10 +7461,19 @@ class AXPEntityPreloadFiltersViewModel {
|
|
|
7467
7461
|
const AXPEntityPreloadFiltersViewModelResolver = async (route, state) => {
|
|
7468
7462
|
const injector = inject(Injector);
|
|
7469
7463
|
const entityRegistry = inject(AXPEntityDefinitionRegistryService);
|
|
7464
|
+
const router = inject(Router);
|
|
7470
7465
|
const moduleName = route.parent?.paramMap.get('module');
|
|
7471
7466
|
const entityName = route.paramMap.get('entity');
|
|
7472
|
-
|
|
7473
|
-
|
|
7467
|
+
try {
|
|
7468
|
+
const entity = await entityRegistry.resolve(moduleName, entityName);
|
|
7469
|
+
return new AXPEntityPreloadFiltersViewModel(injector, entity);
|
|
7470
|
+
}
|
|
7471
|
+
catch (error) {
|
|
7472
|
+
if (error instanceof AXPNotFoundError) {
|
|
7473
|
+
return axpRedirectToNotFound(router);
|
|
7474
|
+
}
|
|
7475
|
+
throw error;
|
|
7476
|
+
}
|
|
7474
7477
|
};
|
|
7475
7478
|
//#endregion
|
|
7476
7479
|
|
|
@@ -8035,7 +8038,7 @@ class AXMAttachmentsPageComponentProvider {
|
|
|
8035
8038
|
return [
|
|
8036
8039
|
{
|
|
8037
8040
|
key: ATTACHMENTS_PAGE_COMPONENT_KEY,
|
|
8038
|
-
loader: () => import('./acorex-platform-layout-entity-attachments-page.component-
|
|
8041
|
+
loader: () => import('./acorex-platform-layout-entity-attachments-page.component-B0EkdqvH.mjs').then((m) => m.AXMAttachmentsPageComponent),
|
|
8039
8042
|
},
|
|
8040
8043
|
];
|
|
8041
8044
|
}
|
|
@@ -8354,7 +8357,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8354
8357
|
this.noRecordsTitle = signal('', ...(ngDevMode ? [{ debugName: "noRecordsTitle" }] : /* istanbul ignore next */ []));
|
|
8355
8358
|
this.currentSearchTerm = null;
|
|
8356
8359
|
this.isRefreshing = false;
|
|
8357
|
-
this.isUpdatingSelection = false; // Flag to prevent recursive updates during batch operations
|
|
8360
|
+
this.isUpdatingSelection = false; // Flag to prevent recursive updates during batch operations (multiple mode)
|
|
8358
8361
|
/**
|
|
8359
8362
|
* Computed property to check if we should show the "no search results" empty state.
|
|
8360
8363
|
* Returns true when search is active, not searching, and no results found.
|
|
@@ -8421,9 +8424,8 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8421
8424
|
}
|
|
8422
8425
|
});
|
|
8423
8426
|
}
|
|
8424
|
-
// Mark pre-selected nodes
|
|
8425
|
-
|
|
8426
|
-
if (!this.isUpdatingSelection) {
|
|
8427
|
+
// Mark pre-selected leaf nodes on loaded children (multiple mode only; single uses controlledSelection)
|
|
8428
|
+
if (!this.isUpdatingSelection && this.allowMultiple()) {
|
|
8427
8429
|
const selectedIds = this.selectedNodeIds();
|
|
8428
8430
|
childNodes.forEach((node) => {
|
|
8429
8431
|
const nodeId = String(node['id'] ?? '');
|
|
@@ -8431,38 +8433,6 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8431
8433
|
node['selected'] = true;
|
|
8432
8434
|
}
|
|
8433
8435
|
});
|
|
8434
|
-
// After children load, programmatically select pre-selected nodes in tree component
|
|
8435
|
-
// This ensures the tree's internal state matches our selectedNodeIds
|
|
8436
|
-
// Skip this if we're in the middle of a selection update (user is selecting/deselecting)
|
|
8437
|
-
const treeComponent = this.tree();
|
|
8438
|
-
if (treeComponent && selectedIds.length > 0) {
|
|
8439
|
-
// Use setTimeout to ensure nodes are in tree structure before selecting
|
|
8440
|
-
setTimeout(() => {
|
|
8441
|
-
// Double-check we're not in a selection update when timeout fires
|
|
8442
|
-
if (this.isUpdatingSelection) {
|
|
8443
|
-
return;
|
|
8444
|
-
}
|
|
8445
|
-
this.isUpdatingSelection = true;
|
|
8446
|
-
try {
|
|
8447
|
-
// Re-check selectedNodeIds at this point (might have changed)
|
|
8448
|
-
const currentSelectedIds = this.selectedNodeIds();
|
|
8449
|
-
childNodes.forEach((node) => {
|
|
8450
|
-
const nodeId = String(node['id'] ?? '');
|
|
8451
|
-
if (nodeId && currentSelectedIds.includes(nodeId) && nodeId !== 'all') {
|
|
8452
|
-
try {
|
|
8453
|
-
treeComponent.selectNode(nodeId);
|
|
8454
|
-
}
|
|
8455
|
-
catch {
|
|
8456
|
-
// Node might not be in tree yet
|
|
8457
|
-
}
|
|
8458
|
-
}
|
|
8459
|
-
});
|
|
8460
|
-
}
|
|
8461
|
-
finally {
|
|
8462
|
-
this.isUpdatingSelection = false;
|
|
8463
|
-
}
|
|
8464
|
-
}, 10);
|
|
8465
|
-
}
|
|
8466
8436
|
}
|
|
8467
8437
|
return childNodes;
|
|
8468
8438
|
};
|
|
@@ -8488,6 +8458,60 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8488
8458
|
}
|
|
8489
8459
|
//#endregion
|
|
8490
8460
|
//#region ---- Private Methods ----
|
|
8461
|
+
/** Keeps at most one id when {@link allowMultiple} is false. */
|
|
8462
|
+
normalizeSelectedIds(ids) {
|
|
8463
|
+
const filtered = ids.filter((id) => id && id !== 'all');
|
|
8464
|
+
if (this.allowMultiple()) {
|
|
8465
|
+
return [...filtered];
|
|
8466
|
+
}
|
|
8467
|
+
return filtered.length > 0 ? [filtered[filtered.length - 1]] : [];
|
|
8468
|
+
}
|
|
8469
|
+
setSelectedNodeIds(ids) {
|
|
8470
|
+
this.selectedNodeIds.set(this.normalizeSelectedIds(ids));
|
|
8471
|
+
}
|
|
8472
|
+
/** Keeps widget selectedNodeIds in sync when the tree uses controlled single selection. */
|
|
8473
|
+
onControlledSelectedIdsChange(ids) {
|
|
8474
|
+
if (this.allowMultiple()) {
|
|
8475
|
+
return;
|
|
8476
|
+
}
|
|
8477
|
+
this.setSelectedNodeIds(ids);
|
|
8478
|
+
}
|
|
8479
|
+
async waitForTreeComponent(maxWaitMs = 3500) {
|
|
8480
|
+
const deadline = Date.now() + maxWaitMs;
|
|
8481
|
+
while (Date.now() < deadline) {
|
|
8482
|
+
const treeComponent = this.tree();
|
|
8483
|
+
if (treeComponent) {
|
|
8484
|
+
return treeComponent;
|
|
8485
|
+
}
|
|
8486
|
+
await new Promise((resolve) => setTimeout(resolve, 80));
|
|
8487
|
+
}
|
|
8488
|
+
return undefined;
|
|
8489
|
+
}
|
|
8490
|
+
/** Expands ancestor paths and reveals the initial selection via the tree API. */
|
|
8491
|
+
async revealInitialSelection(ids) {
|
|
8492
|
+
const normalizedIds = this.normalizeSelectedIds(ids);
|
|
8493
|
+
if (normalizedIds.length === 0) {
|
|
8494
|
+
return;
|
|
8495
|
+
}
|
|
8496
|
+
const treeComponent = await this.waitForTreeComponent();
|
|
8497
|
+
if (!treeComponent) {
|
|
8498
|
+
return;
|
|
8499
|
+
}
|
|
8500
|
+
try {
|
|
8501
|
+
if (this.allowMultiple()) {
|
|
8502
|
+
await this.restoreMultipleSelectionAfterReload(normalizedIds);
|
|
8503
|
+
}
|
|
8504
|
+
else {
|
|
8505
|
+
const chains = await this.buildAncestorChains(normalizedIds);
|
|
8506
|
+
const ancestorPaths = normalizedIds.map((id) => chains.get(id) ?? []);
|
|
8507
|
+
await treeComponent.selectAndReveal(normalizedIds, { ancestorPaths });
|
|
8508
|
+
}
|
|
8509
|
+
}
|
|
8510
|
+
catch (error) {
|
|
8511
|
+
console.error('Error revealing initial category selection:', error);
|
|
8512
|
+
}
|
|
8513
|
+
this.changeDetectorRef.markForCheck();
|
|
8514
|
+
}
|
|
8491
8515
|
async initializeTree() {
|
|
8492
8516
|
if (!this.entityKey()) {
|
|
8493
8517
|
this.loading.set(false);
|
|
@@ -8512,12 +8536,12 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8512
8536
|
// Resolve initial selected IDs from data (popup) or input binding
|
|
8513
8537
|
const fromData = this.selectedValues().filter((id) => id && id !== 'all');
|
|
8514
8538
|
const fromInput = (this.selectedValuesInput() ?? []).filter((id) => id && id !== 'all');
|
|
8515
|
-
const initialSelectedIds = fromData.length > 0 ? fromData : fromInput;
|
|
8539
|
+
const initialSelectedIds = this.normalizeSelectedIds(fromData.length > 0 ? fromData : fromInput);
|
|
8516
8540
|
if (initialSelectedIds.length > 0) {
|
|
8517
8541
|
await this.loadMissingNodeData(initialSelectedIds);
|
|
8518
8542
|
// Re-fetch any node that has no parent info (batch query may return minimal fields)
|
|
8519
8543
|
await this.ensureParentDataInCache(initialSelectedIds);
|
|
8520
|
-
this.
|
|
8544
|
+
this.setSelectedNodeIds(initialSelectedIds);
|
|
8521
8545
|
}
|
|
8522
8546
|
}
|
|
8523
8547
|
catch (error) {
|
|
@@ -8531,52 +8555,20 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8531
8555
|
const selectedIds = this.selectedNodeIds();
|
|
8532
8556
|
if (selectedIds.length > 0) {
|
|
8533
8557
|
this.initialExpandSyncDone = true;
|
|
8534
|
-
this.
|
|
8558
|
+
void this.revealInitialSelection(selectedIds);
|
|
8535
8559
|
}
|
|
8536
8560
|
}
|
|
8537
8561
|
/**
|
|
8538
8562
|
* Called when popup data arrives after ngOnInit: load data, set selection, expand and sync.
|
|
8539
8563
|
*/
|
|
8540
8564
|
runInitialExpandAndSync(ids) {
|
|
8541
|
-
this.
|
|
8565
|
+
this.setSelectedNodeIds(ids);
|
|
8542
8566
|
Promise.resolve()
|
|
8543
8567
|
.then(() => this.loadMissingNodeData(ids))
|
|
8544
8568
|
.then(() => this.ensureParentDataInCache(ids))
|
|
8545
|
-
.then(() =>
|
|
8546
|
-
this.runExpandAndSyncWhenTreeReady(ids);
|
|
8547
|
-
})
|
|
8569
|
+
.then(() => this.revealInitialSelection(ids))
|
|
8548
8570
|
.catch((err) => console.error('Error in runInitialExpandAndSync:', err));
|
|
8549
8571
|
}
|
|
8550
|
-
/**
|
|
8551
|
-
* Runs expand path + sync selection once the tree viewChild is available.
|
|
8552
|
-
* Uses retry loop so we don't run before the view has rendered the tree.
|
|
8553
|
-
*/
|
|
8554
|
-
runExpandAndSyncWhenTreeReady(selectedIds) {
|
|
8555
|
-
const maxWaitMs = 3500;
|
|
8556
|
-
const pollMs = 80;
|
|
8557
|
-
const start = Date.now();
|
|
8558
|
-
const run = async () => {
|
|
8559
|
-
while (Date.now() - start < maxWaitMs) {
|
|
8560
|
-
const treeComponent = this.tree();
|
|
8561
|
-
if (treeComponent) {
|
|
8562
|
-
try {
|
|
8563
|
-
await new Promise((resolve) => setTimeout(resolve, 320));
|
|
8564
|
-
const ancestorChains = await this.buildAncestorChains(selectedIds);
|
|
8565
|
-
await this.expandAncestorNodesInOrder(ancestorChains);
|
|
8566
|
-
await new Promise((resolve) => setTimeout(resolve, 120));
|
|
8567
|
-
await this.syncSelectionWithTree(selectedIds);
|
|
8568
|
-
}
|
|
8569
|
-
catch (error) {
|
|
8570
|
-
console.error('Error syncing selection after tree render:', error);
|
|
8571
|
-
}
|
|
8572
|
-
this.changeDetectorRef.markForCheck();
|
|
8573
|
-
return;
|
|
8574
|
-
}
|
|
8575
|
-
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
8576
|
-
}
|
|
8577
|
-
};
|
|
8578
|
-
run();
|
|
8579
|
-
}
|
|
8580
8572
|
//#endregion
|
|
8581
8573
|
//#region ---- Public Methods ----
|
|
8582
8574
|
/**
|
|
@@ -8981,8 +8973,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8981
8973
|
this.nodesExpandedDuringSearch = [];
|
|
8982
8974
|
return;
|
|
8983
8975
|
}
|
|
8984
|
-
|
|
8985
|
-
const selectedIds = this.selectedNodeIds();
|
|
8976
|
+
const expandTargetIds = [...this.selectedNodeIds()];
|
|
8986
8977
|
// Reload tree to show all nodes (no filtering)
|
|
8987
8978
|
await treeComponent.reloadData();
|
|
8988
8979
|
// Collapse nodes that were expanded during search (in reverse order - leaves first)
|
|
@@ -9002,39 +8993,38 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9002
8993
|
// Clear the stored expanded nodes
|
|
9003
8994
|
this.expandedNodesBeforeSearch = [];
|
|
9004
8995
|
// Restore selection state after tree reload
|
|
9005
|
-
if (
|
|
9006
|
-
|
|
9007
|
-
|
|
9008
|
-
|
|
9009
|
-
|
|
8996
|
+
if (expandTargetIds.length > 0) {
|
|
8997
|
+
if (!this.allowMultiple()) {
|
|
8998
|
+
await this.revealInitialSelection(expandTargetIds);
|
|
8999
|
+
}
|
|
9000
|
+
else {
|
|
9001
|
+
await this.restoreMultipleSelectionAfterReload(expandTargetIds);
|
|
9002
|
+
}
|
|
9010
9003
|
}
|
|
9011
9004
|
}
|
|
9012
9005
|
/**
|
|
9013
|
-
* Restores selection
|
|
9014
|
-
* Expands ancestor nodes and selects the previously selected leaf nodes.
|
|
9006
|
+
* Restores multiple-mode leaf selection after search reset.
|
|
9015
9007
|
*/
|
|
9016
|
-
async
|
|
9008
|
+
async restoreMultipleSelectionAfterReload(selectedLeafIds) {
|
|
9017
9009
|
const treeComponent = this.tree();
|
|
9018
|
-
|
|
9010
|
+
const normalizedIds = this.normalizeSelectedIds(selectedLeafIds);
|
|
9011
|
+
if (!treeComponent || normalizedIds.length === 0) {
|
|
9019
9012
|
return;
|
|
9020
9013
|
}
|
|
9021
9014
|
this.isUpdatingSelection = true;
|
|
9022
9015
|
try {
|
|
9023
|
-
|
|
9024
|
-
const ancestorChains = await this.buildAncestorChains(selectedIds);
|
|
9025
|
-
// Expand ancestor nodes to make selected nodes visible
|
|
9016
|
+
const ancestorChains = await this.buildAncestorChains(normalizedIds);
|
|
9026
9017
|
await this.expandAncestorNodesInOrder(ancestorChains);
|
|
9027
|
-
|
|
9028
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
9029
|
-
// Select the nodes visually in the tree
|
|
9030
|
-
for (const id of selectedIds) {
|
|
9018
|
+
for (const id of normalizedIds) {
|
|
9031
9019
|
try {
|
|
9032
9020
|
treeComponent.selectNode(id);
|
|
9033
9021
|
}
|
|
9034
9022
|
catch {
|
|
9035
|
-
// Node might not be
|
|
9023
|
+
// Node might not be loaded yet
|
|
9036
9024
|
}
|
|
9037
9025
|
}
|
|
9026
|
+
await this.updateParentStatesAfterSelection(normalizedIds);
|
|
9027
|
+
treeComponent.refresh();
|
|
9038
9028
|
}
|
|
9039
9029
|
finally {
|
|
9040
9030
|
this.isUpdatingSelection = false;
|
|
@@ -9051,10 +9041,6 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9051
9041
|
if (!event.isUserInteraction) {
|
|
9052
9042
|
return;
|
|
9053
9043
|
}
|
|
9054
|
-
// Don't process if we're already updating selection
|
|
9055
|
-
if (this.isUpdatingSelection) {
|
|
9056
|
-
return;
|
|
9057
|
-
}
|
|
9058
9044
|
// Cache node data for getSelectedItems (except for 'all' node)
|
|
9059
9045
|
if (nodeId !== 'all') {
|
|
9060
9046
|
const nodeData = node['data'];
|
|
@@ -9062,72 +9048,64 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9062
9048
|
this.nodeDataCache.set(nodeId, nodeData);
|
|
9063
9049
|
}
|
|
9064
9050
|
}
|
|
9065
|
-
//
|
|
9051
|
+
// Single selection is handled by the tree controlledSelection + selectedIds binding.
|
|
9052
|
+
if (!this.allowMultiple()) {
|
|
9053
|
+
return;
|
|
9054
|
+
}
|
|
9066
9055
|
const isSelected = node['selected'] === true;
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
|
|
9078
|
-
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
|
|
9084
|
-
|
|
9085
|
-
|
|
9056
|
+
const children = node['children'];
|
|
9057
|
+
const childrenCount = node['childrenCount'];
|
|
9058
|
+
// Determine if this node has children (is a parent node)
|
|
9059
|
+
// A node has children if: childrenCount > 0, or has non-empty children array
|
|
9060
|
+
// Note: childrenCount === undefined means "unknown" - we need to check via datasource
|
|
9061
|
+
const hasLoadedChildren = children && children.length > 0;
|
|
9062
|
+
const hasChildrenCount = childrenCount !== undefined && childrenCount > 0;
|
|
9063
|
+
const isDefinitelyLeaf = childrenCount === 0 && (!children || children.length === 0);
|
|
9064
|
+
if (isSelected) {
|
|
9065
|
+
// SELECTION: Only add LEAF nodes to selectedNodeIds
|
|
9066
|
+
this.isUpdatingSelection = true;
|
|
9067
|
+
try {
|
|
9068
|
+
if (nodeId === 'all') {
|
|
9069
|
+
// "All Items" selected - recursively select all leaf descendants
|
|
9070
|
+
await this.selectAllLeafDescendants(nodeId);
|
|
9071
|
+
}
|
|
9072
|
+
else if (isDefinitelyLeaf) {
|
|
9073
|
+
// This is definitely a leaf node - add it directly
|
|
9074
|
+
const currentSelected = new Set(this.selectedNodeIds());
|
|
9075
|
+
currentSelected.add(nodeId);
|
|
9076
|
+
this.setSelectedNodeIds(Array.from(currentSelected));
|
|
9077
|
+
}
|
|
9078
|
+
else if (hasLoadedChildren || hasChildrenCount) {
|
|
9079
|
+
// This node has children - only add its leaf descendants
|
|
9080
|
+
await this.selectAllLeafDescendants(nodeId);
|
|
9081
|
+
}
|
|
9082
|
+
else {
|
|
9083
|
+
// childrenCount is undefined - fetch once and reuse to avoid double datasource call
|
|
9084
|
+
const childNodes = await this.datasource(nodeId);
|
|
9085
|
+
if (!childNodes || childNodes.length === 0) {
|
|
9086
|
+
// No children - this is a leaf node, add it
|
|
9086
9087
|
const currentSelected = new Set(this.selectedNodeIds());
|
|
9087
9088
|
currentSelected.add(nodeId);
|
|
9088
|
-
this.
|
|
9089
|
-
}
|
|
9090
|
-
else if (hasLoadedChildren || hasChildrenCount) {
|
|
9091
|
-
// This node has children - only add its leaf descendants
|
|
9092
|
-
await this.selectAllLeafDescendants(nodeId);
|
|
9089
|
+
this.setSelectedNodeIds(Array.from(currentSelected));
|
|
9093
9090
|
}
|
|
9094
9091
|
else {
|
|
9095
|
-
//
|
|
9096
|
-
|
|
9097
|
-
if (!childNodes || childNodes.length === 0) {
|
|
9098
|
-
// No children - this is a leaf node, add it
|
|
9099
|
-
const currentSelected = new Set(this.selectedNodeIds());
|
|
9100
|
-
currentSelected.add(nodeId);
|
|
9101
|
-
this.selectedNodeIds.set(Array.from(currentSelected));
|
|
9102
|
-
}
|
|
9103
|
-
else {
|
|
9104
|
-
// Has children - pass prefetched childNodes to avoid datasource(nodeId) again
|
|
9105
|
-
await this.selectAllLeafDescendants(nodeId, childNodes);
|
|
9106
|
-
}
|
|
9092
|
+
// Has children - pass prefetched childNodes to avoid datasource(nodeId) again
|
|
9093
|
+
await this.selectAllLeafDescendants(nodeId, childNodes);
|
|
9107
9094
|
}
|
|
9108
9095
|
}
|
|
9109
|
-
finally {
|
|
9110
|
-
this.isUpdatingSelection = false;
|
|
9111
|
-
}
|
|
9112
9096
|
}
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
this.isUpdatingSelection = true;
|
|
9116
|
-
try {
|
|
9117
|
-
await this.deselectAllLeafDescendants(nodeId);
|
|
9118
|
-
}
|
|
9119
|
-
finally {
|
|
9120
|
-
this.isUpdatingSelection = false;
|
|
9121
|
-
}
|
|
9097
|
+
finally {
|
|
9098
|
+
this.isUpdatingSelection = false;
|
|
9122
9099
|
}
|
|
9123
9100
|
}
|
|
9124
9101
|
else {
|
|
9125
|
-
//
|
|
9126
|
-
|
|
9127
|
-
|
|
9102
|
+
// DESELECTION: Remove node (if leaf) and all leaf descendants from selectedNodeIds
|
|
9103
|
+
this.isUpdatingSelection = true;
|
|
9104
|
+
try {
|
|
9105
|
+
await this.deselectAllLeafDescendants(nodeId);
|
|
9128
9106
|
}
|
|
9129
|
-
|
|
9130
|
-
this.
|
|
9107
|
+
finally {
|
|
9108
|
+
this.isUpdatingSelection = false;
|
|
9131
9109
|
}
|
|
9132
9110
|
}
|
|
9133
9111
|
}
|
|
@@ -9143,7 +9121,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9143
9121
|
* Clears all selected items
|
|
9144
9122
|
*/
|
|
9145
9123
|
onClearAll() {
|
|
9146
|
-
this.
|
|
9124
|
+
this.setSelectedNodeIds([]);
|
|
9147
9125
|
const treeComponent = this.tree();
|
|
9148
9126
|
if (treeComponent) {
|
|
9149
9127
|
treeComponent.deselectAll();
|
|
@@ -9194,7 +9172,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9194
9172
|
for (const leafId of leafIds) {
|
|
9195
9173
|
currentSelected.add(leafId);
|
|
9196
9174
|
}
|
|
9197
|
-
this.
|
|
9175
|
+
this.setSelectedNodeIds(Array.from(currentSelected));
|
|
9198
9176
|
// Select all leaf nodes visually in the tree
|
|
9199
9177
|
if (treeComponent) {
|
|
9200
9178
|
for (const leafId of leafIds) {
|
|
@@ -9223,7 +9201,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9223
9201
|
try {
|
|
9224
9202
|
// Special case: deselecting 'all' clears everything
|
|
9225
9203
|
if (parentId === 'all') {
|
|
9226
|
-
this.
|
|
9204
|
+
this.setSelectedNodeIds([]);
|
|
9227
9205
|
// Use tree's deselectAll() to clear all visual selections
|
|
9228
9206
|
const treeComponent = this.tree();
|
|
9229
9207
|
if (treeComponent) {
|
|
@@ -9244,7 +9222,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9244
9222
|
// Only update our internal state - tree handles visual state
|
|
9245
9223
|
const currentSelected = this.selectedNodeIds();
|
|
9246
9224
|
const newSelected = currentSelected.filter((id) => !leafIds.has(id));
|
|
9247
|
-
this.
|
|
9225
|
+
this.setSelectedNodeIds(newSelected);
|
|
9248
9226
|
}
|
|
9249
9227
|
catch (error) {
|
|
9250
9228
|
console.error(`Error deselecting leaf descendants for node ${parentId}:`, error);
|
|
@@ -9494,60 +9472,6 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9494
9472
|
await new Promise((r) => setTimeout(r, pollMs));
|
|
9495
9473
|
}
|
|
9496
9474
|
}
|
|
9497
|
-
/**
|
|
9498
|
-
* Syncs selection state with the tree component.
|
|
9499
|
-
* Selects leaf nodes and manually updates parent states (indeterminate/selected).
|
|
9500
|
-
*/
|
|
9501
|
-
async syncSelectionWithTree(selectedIds) {
|
|
9502
|
-
const treeComponent = this.tree();
|
|
9503
|
-
if (!treeComponent || selectedIds.length === 0) {
|
|
9504
|
-
return;
|
|
9505
|
-
}
|
|
9506
|
-
// Wait for tree to be fully initialized after ancestor expansion
|
|
9507
|
-
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
9508
|
-
// Keep track of successfully synced nodes
|
|
9509
|
-
const syncedNodes = new Set();
|
|
9510
|
-
// Try multiple times to sync selection (nodes might load progressively)
|
|
9511
|
-
for (let attempt = 0; attempt < 5; attempt++) {
|
|
9512
|
-
for (const id of selectedIds) {
|
|
9513
|
-
if (id && id !== 'all' && !syncedNodes.has(id)) {
|
|
9514
|
-
try {
|
|
9515
|
-
const node = treeComponent.findNode(id);
|
|
9516
|
-
if (node) {
|
|
9517
|
-
// Node exists in tree - mark it as selected using both methods
|
|
9518
|
-
// 1. Direct property assignment for immediate visual feedback
|
|
9519
|
-
node['selected'] = true;
|
|
9520
|
-
node['indeterminate'] = false;
|
|
9521
|
-
// 2. Use selectNode API for tree's internal state tracking
|
|
9522
|
-
try {
|
|
9523
|
-
treeComponent.selectNode(id);
|
|
9524
|
-
}
|
|
9525
|
-
catch {
|
|
9526
|
-
// selectNode might fail but direct assignment should work
|
|
9527
|
-
}
|
|
9528
|
-
syncedNodes.add(id);
|
|
9529
|
-
}
|
|
9530
|
-
}
|
|
9531
|
-
catch {
|
|
9532
|
-
// Node not in tree yet
|
|
9533
|
-
}
|
|
9534
|
-
}
|
|
9535
|
-
}
|
|
9536
|
-
// If all nodes are synced, we're done
|
|
9537
|
-
if (syncedNodes.size === selectedIds.length) {
|
|
9538
|
-
break;
|
|
9539
|
-
}
|
|
9540
|
-
// Wait before next attempt
|
|
9541
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
9542
|
-
}
|
|
9543
|
-
// Now update parent states (indeterminate/selected) based on children
|
|
9544
|
-
// This uses bottom-up traversal with datasource fallback for loading children
|
|
9545
|
-
await this.updateParentStatesAfterSelection(selectedIds);
|
|
9546
|
-
// Refresh tree to apply changes
|
|
9547
|
-
treeComponent.refresh();
|
|
9548
|
-
// Trigger change detection to update UI
|
|
9549
|
-
this.changeDetectorRef.markForCheck();
|
|
9550
|
-
}
|
|
9551
9475
|
/**
|
|
9552
9476
|
* Updates parent node states (selected/indeterminate) based on children selection.
|
|
9553
9477
|
* Called after leaf nodes are selected to properly show parent states.
|
|
@@ -9741,35 +9665,6 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9741
9665
|
const id = String(parentIdValue);
|
|
9742
9666
|
return id && id !== 'all' ? id : null;
|
|
9743
9667
|
}
|
|
9744
|
-
/**
|
|
9745
|
-
* Marks nodes as selected in the tree structure based on selectedNodeIds.
|
|
9746
|
-
* This ensures pre-selected nodes appear selected when the tree is rendered.
|
|
9747
|
-
*/
|
|
9748
|
-
markNodesAsSelected(node) {
|
|
9749
|
-
const selectedIds = this.selectedNodeIds();
|
|
9750
|
-
if (selectedIds.length === 0) {
|
|
9751
|
-
return;
|
|
9752
|
-
}
|
|
9753
|
-
// Mark the node itself if it's selected
|
|
9754
|
-
this.markNodeAsSelectedIfNeeded(node);
|
|
9755
|
-
// Recursively mark children
|
|
9756
|
-
const nodeChildren = node['children'];
|
|
9757
|
-
if (nodeChildren) {
|
|
9758
|
-
nodeChildren.forEach((child) => {
|
|
9759
|
-
this.markNodesAsSelected(child);
|
|
9760
|
-
});
|
|
9761
|
-
}
|
|
9762
|
-
}
|
|
9763
|
-
/**
|
|
9764
|
-
* Marks a single node as selected if it's in the selectedNodeIds list.
|
|
9765
|
-
*/
|
|
9766
|
-
markNodeAsSelectedIfNeeded(node) {
|
|
9767
|
-
const selectedIds = this.selectedNodeIds();
|
|
9768
|
-
const nodeId = String(node['id'] ?? '');
|
|
9769
|
-
if (nodeId && selectedIds.includes(nodeId)) {
|
|
9770
|
-
node['selected'] = true;
|
|
9771
|
-
}
|
|
9772
|
-
}
|
|
9773
9668
|
/**
|
|
9774
9669
|
* Marks a node and its children as disabled if the node ID matches the excluded ID.
|
|
9775
9670
|
*/
|
|
@@ -9778,7 +9673,6 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9778
9673
|
if (nodeId === excludedId) {
|
|
9779
9674
|
node['disabled'] = true;
|
|
9780
9675
|
}
|
|
9781
|
-
// Recursively mark children
|
|
9782
9676
|
const nodeChildren = node['children'];
|
|
9783
9677
|
if (nodeChildren) {
|
|
9784
9678
|
nodeChildren.forEach((child) => {
|
|
@@ -9787,41 +9681,16 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9787
9681
|
}
|
|
9788
9682
|
}
|
|
9789
9683
|
/**
|
|
9790
|
-
* Processes root node: marks excluded as disabled
|
|
9684
|
+
* Processes root node: marks excluded nodes as disabled.
|
|
9791
9685
|
*/
|
|
9792
9686
|
processRootNode(rootNode) {
|
|
9793
9687
|
const excludedId = this.excludedNodeId();
|
|
9794
9688
|
if (excludedId) {
|
|
9795
9689
|
this.markNodeAsDisabled(rootNode, excludedId);
|
|
9796
9690
|
}
|
|
9797
|
-
this.markNodesAsSelected(rootNode);
|
|
9798
|
-
// Sync selection with tree component after a short delay to ensure tree is rendered
|
|
9799
|
-
const treeComponent = this.tree();
|
|
9800
|
-
if (treeComponent) {
|
|
9801
|
-
setTimeout(() => {
|
|
9802
|
-
this.isUpdatingSelection = true;
|
|
9803
|
-
try {
|
|
9804
|
-
const selectedIds = this.selectedNodeIds();
|
|
9805
|
-
selectedIds.forEach((id) => {
|
|
9806
|
-
if (id && id !== 'all') {
|
|
9807
|
-
try {
|
|
9808
|
-
treeComponent.selectNode(id);
|
|
9809
|
-
}
|
|
9810
|
-
catch {
|
|
9811
|
-
// Node might not be in tree yet
|
|
9812
|
-
}
|
|
9813
|
-
}
|
|
9814
|
-
});
|
|
9815
|
-
}
|
|
9816
|
-
finally {
|
|
9817
|
-
this.isUpdatingSelection = false;
|
|
9818
|
-
}
|
|
9819
|
-
}, 0);
|
|
9820
|
-
}
|
|
9821
9691
|
}
|
|
9822
9692
|
/**
|
|
9823
9693
|
* Processes child nodes: marks excluded as disabled
|
|
9824
|
-
* Selection marking is handled in datasource callback ONLY during initial load
|
|
9825
9694
|
*/
|
|
9826
9695
|
processChildNodes(childNodes) {
|
|
9827
9696
|
const excludedId = this.excludedNodeId();
|
|
@@ -9967,8 +9836,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9967
9836
|
return this.translationService.resolve(raw);
|
|
9968
9837
|
}
|
|
9969
9838
|
async getSelectedItems() {
|
|
9970
|
-
|
|
9971
|
-
const selectedIds = this.selectedNodeIds();
|
|
9839
|
+
const selectedIds = this.normalizeSelectedIds(this.selectedNodeIds());
|
|
9972
9840
|
if (selectedIds.length === 0) {
|
|
9973
9841
|
return [];
|
|
9974
9842
|
}
|
|
@@ -10061,6 +9929,9 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
10061
9929
|
[dragBehavior]="'none'"
|
|
10062
9930
|
[selectMode]="allowMultiple() ? 'multiple' : 'single'"
|
|
10063
9931
|
[selectionBehavior]="allowMultiple() ? 'intermediate-nested' : 'all'"
|
|
9932
|
+
[controlledSelection]="!allowMultiple()"
|
|
9933
|
+
[selectedIds]="selectedNodeIds()"
|
|
9934
|
+
(selectedIdsChange)="onControlledSelectedIdsChange($event)"
|
|
10064
9935
|
[showIcons]="true"
|
|
10065
9936
|
[titleField]="textField()"
|
|
10066
9937
|
[idField]="valueField()"
|
|
@@ -10147,7 +10018,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
10147
10018
|
></ax-button>
|
|
10148
10019
|
</ax-suffix>
|
|
10149
10020
|
</ax-footer>
|
|
10150
|
-
`, 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: i4.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", "look"] }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10021
|
+
`, 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: i4.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "component", type: AXTreeViewComponent, selector: "ax-tree-view", inputs: ["datasource", "selectMode", "selectionBehavior", "dragArea", "dragBehavior", "showIcons", "showChildrenBadge", "expandedIcon", "collapsedIcon", "indentSize", "look", "nodeTemplate", "idField", "titleField", "tooltipField", "iconField", "expandedField", "selectedField", "indeterminateField", "disabledField", "hiddenField", "childrenField", "childrenCountField", "dataField", "inheritDisabled", "expandOnDoubleClick", "doubleClickDuration", "tooltipDelay", "controlledSelection", "selectedIds"], outputs: ["datasourceChange", "selectedIdsChange", "onBeforeDrop", "onNodeToggle", "onNodeSelect", "onNodeDoubleClick", "onNodeClick", "onSelectionChange", "onOrderChange", "onMoveChange", "onItemsChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "look"] }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10151
10022
|
}
|
|
10152
10023
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityCategoryTreeSelectorComponent, decorators: [{
|
|
10153
10024
|
type: Component,
|
|
@@ -10198,6 +10069,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
10198
10069
|
[dragBehavior]="'none'"
|
|
10199
10070
|
[selectMode]="allowMultiple() ? 'multiple' : 'single'"
|
|
10200
10071
|
[selectionBehavior]="allowMultiple() ? 'intermediate-nested' : 'all'"
|
|
10072
|
+
[controlledSelection]="!allowMultiple()"
|
|
10073
|
+
[selectedIds]="selectedNodeIds()"
|
|
10074
|
+
(selectedIdsChange)="onControlledSelectedIdsChange($event)"
|
|
10201
10075
|
[showIcons]="true"
|
|
10202
10076
|
[titleField]="textField()"
|
|
10203
10077
|
[idField]="valueField()"
|
|
@@ -11307,9 +11181,7 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
11307
11181
|
this.isOpen.set(true);
|
|
11308
11182
|
const currentValue = this.getValue();
|
|
11309
11183
|
const selectedIds = currentValue
|
|
11310
|
-
?
|
|
11311
|
-
.map((v) => String(extractValue(v, this.valueField())))
|
|
11312
|
-
.filter((id) => id && id !== 'all')
|
|
11184
|
+
? this.normalizePopupSelectedIds(currentValue)
|
|
11313
11185
|
: [];
|
|
11314
11186
|
// Get current entity ID from context (if editing an entity)
|
|
11315
11187
|
const currentEntityId = this.contextService.getValue('id');
|
|
@@ -11330,9 +11202,7 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
11330
11202
|
},
|
|
11331
11203
|
});
|
|
11332
11204
|
if (result?.data?.selected && Array.isArray(result.data.selected)) {
|
|
11333
|
-
|
|
11334
|
-
// This ensures that deselected items are properly removed
|
|
11335
|
-
const newItems = result.data.selected;
|
|
11205
|
+
const newItems = this.multiple() ? result.data.selected : result.data.selected.slice(0, 1);
|
|
11336
11206
|
if (newItems.length === 0) {
|
|
11337
11207
|
// All items were deselected
|
|
11338
11208
|
this.clear();
|
|
@@ -11482,10 +11352,10 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
11482
11352
|
}
|
|
11483
11353
|
});
|
|
11484
11354
|
this.contextService.applyObjectPaths(itemToExpose, { origin: 'user' });
|
|
11485
|
-
this.
|
|
11355
|
+
this.setValue(this.singleOrMultiple(keys));
|
|
11486
11356
|
}
|
|
11487
11357
|
else {
|
|
11488
|
-
this.
|
|
11358
|
+
this.setValue(this.singleOrMultiple(keys));
|
|
11489
11359
|
}
|
|
11490
11360
|
// Trigger change detection
|
|
11491
11361
|
this.cdr.markForCheck();
|
|
@@ -11500,6 +11370,12 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
11500
11370
|
singleOrMultiple(values) {
|
|
11501
11371
|
return this.multiple() ? values : values[0];
|
|
11502
11372
|
}
|
|
11373
|
+
normalizePopupSelectedIds(currentValue) {
|
|
11374
|
+
const ids = (this.multiple() ? castArray(currentValue) : castArray(currentValue).slice(0, 1))
|
|
11375
|
+
.map((v) => String(extractValue(v, this.valueField())))
|
|
11376
|
+
.filter((id) => id && id !== 'all');
|
|
11377
|
+
return this.multiple() ? ids : ids.slice(0, 1);
|
|
11378
|
+
}
|
|
11503
11379
|
getItemLabel(item) {
|
|
11504
11380
|
if (!item) {
|
|
11505
11381
|
return '';
|
|
@@ -12777,11 +12653,10 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
12777
12653
|
}
|
|
12778
12654
|
untracked(() => void this.applyRelatedFiltersFromContextAndDatasource(specs));
|
|
12779
12655
|
}, ...(ngDevMode ? [{ debugName: "#relatedFilterSyncEffect" }] : /* istanbul ignore next */ []));
|
|
12780
|
-
/** Patches data-list `refresh` so
|
|
12656
|
+
/** Patches data-list `refresh` so reload keeps parent-scoped toolbar filters on the data source. */
|
|
12781
12657
|
this.#patchDataListRefreshEffect = effect(() => {
|
|
12782
12658
|
const inst = this.listWidget()?.instance;
|
|
12783
|
-
|
|
12784
|
-
if (!inst?.refresh || inst.__axpEntityListRefreshPatched || !opts['syncRelatedListFiltersFromDialogContext']) {
|
|
12659
|
+
if (!inst?.refresh || inst.__axpEntityListRefreshPatched) {
|
|
12785
12660
|
return;
|
|
12786
12661
|
}
|
|
12787
12662
|
inst.__axpEntityListRefreshPatched = true;
|
|
@@ -12793,6 +12668,9 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
12793
12668
|
if (o['syncRelatedListFiltersFromDialogContext'] && specs?.length) {
|
|
12794
12669
|
await this.applyRelatedFiltersFromContextAndDatasource(specs);
|
|
12795
12670
|
}
|
|
12671
|
+
else {
|
|
12672
|
+
await this.reapplyScopedFiltersToDataSource();
|
|
12673
|
+
}
|
|
12796
12674
|
originalRefresh();
|
|
12797
12675
|
})();
|
|
12798
12676
|
};
|
|
@@ -13013,6 +12891,10 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13013
12891
|
* Applies merged route + parent-scope filters to the widget value and data source.
|
|
13014
12892
|
*/
|
|
13015
12893
|
applyMergedRouteFiltersToList() {
|
|
12894
|
+
void this.reapplyScopedFiltersToDataSource();
|
|
12895
|
+
}
|
|
12896
|
+
/** Syncs toolbar filters to context and AXDataSource (retries until data-list is mounted). */
|
|
12897
|
+
async reapplyScopedFiltersToDataSource() {
|
|
13016
12898
|
const merged = this.getMergedToolbarFilters();
|
|
13017
12899
|
const current = this.getValue();
|
|
13018
12900
|
if (!isEqual$1(current?.toolbar?.filters, merged)) {
|
|
@@ -13021,7 +12903,26 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13021
12903
|
toolbar: { ...(current?.toolbar ?? {}), filters: merged },
|
|
13022
12904
|
});
|
|
13023
12905
|
}
|
|
12906
|
+
const pushed = await this.ensureToolbarFiltersOnDataSource();
|
|
12907
|
+
if (pushed) {
|
|
12908
|
+
this.triggerInitialLoadIfNeeded();
|
|
12909
|
+
}
|
|
12910
|
+
}
|
|
12911
|
+
/**
|
|
12912
|
+
* Entity lists use `fetchDataMode: 'manual'`; after scoped filters reach the data source,
|
|
12913
|
+
* the grid must be refreshed once (initial #effect may run before the data-list is ready).
|
|
12914
|
+
*/
|
|
12915
|
+
triggerInitialLoadIfNeeded() {
|
|
12916
|
+
if (this.isMounted()) {
|
|
12917
|
+
return;
|
|
12918
|
+
}
|
|
12919
|
+
const listInstance = this.listWidget()?.instance;
|
|
12920
|
+
if (!listInstance?.call) {
|
|
12921
|
+
return;
|
|
12922
|
+
}
|
|
13024
12923
|
this.pushToolbarFiltersToDataSource();
|
|
12924
|
+
listInstance.call('refresh');
|
|
12925
|
+
this.isMounted.set(true);
|
|
13025
12926
|
}
|
|
13026
12927
|
/**
|
|
13027
12928
|
* Re-evaluates related-entity list filters from the live dialog form context (e.g. after create saves the main row id).
|
|
@@ -13068,26 +12969,29 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13068
12969
|
return true;
|
|
13069
12970
|
}
|
|
13070
12971
|
/**
|
|
13071
|
-
*
|
|
12972
|
+
* Pushes toolbar filters once the embedded data-list exposes its data source
|
|
12973
|
+
* (listNode is created via deferred setTimeout in ngOnInit).
|
|
13072
12974
|
*/
|
|
13073
|
-
async
|
|
13074
|
-
await this.applyRelatedFiltersFromContext(specs);
|
|
12975
|
+
async ensureToolbarFiltersOnDataSource() {
|
|
13075
12976
|
if (this.pushToolbarFiltersToDataSource()) {
|
|
13076
|
-
return;
|
|
13077
|
-
}
|
|
13078
|
-
const opts = this.options();
|
|
13079
|
-
if (!opts['syncRelatedListFiltersFromDialogContext']) {
|
|
13080
|
-
return;
|
|
12977
|
+
return true;
|
|
13081
12978
|
}
|
|
13082
|
-
/** Data-list is created in ngOnInit via deferred listNode.set; retry briefly until instance exposes dataSource. */
|
|
13083
12979
|
const maxAttempts = 40;
|
|
13084
12980
|
const delayMs = 50;
|
|
13085
12981
|
for (let i = 0; i < maxAttempts; i++) {
|
|
13086
12982
|
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
13087
12983
|
if (this.pushToolbarFiltersToDataSource()) {
|
|
13088
|
-
return;
|
|
12984
|
+
return true;
|
|
13089
12985
|
}
|
|
13090
12986
|
}
|
|
12987
|
+
return false;
|
|
12988
|
+
}
|
|
12989
|
+
/**
|
|
12990
|
+
* Writes toolbar filters from specs and pushes them onto the data source so refresh/reload keeps the parent scope.
|
|
12991
|
+
*/
|
|
12992
|
+
async applyRelatedFiltersFromContextAndDatasource(specs) {
|
|
12993
|
+
await this.applyRelatedFiltersFromContext(specs);
|
|
12994
|
+
await this.ensureToolbarFiltersOnDataSource();
|
|
13091
12995
|
}
|
|
13092
12996
|
/**
|
|
13093
12997
|
* Refreshes the embedded data list (toolbar / workflow). In wizard mode, `refresh` is patched to re-apply scoped filters first.
|
|
@@ -13095,7 +12999,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13095
12999
|
refreshGridWithParentScopedFilters() {
|
|
13096
13000
|
this.listWidget()?.instance?.call('refresh');
|
|
13097
13001
|
}
|
|
13098
|
-
/** Patches data-list `refresh` so
|
|
13002
|
+
/** Patches data-list `refresh` so reload keeps parent-scoped toolbar filters on the data source. */
|
|
13099
13003
|
#patchDataListRefreshEffect;
|
|
13100
13004
|
#effect;
|
|
13101
13005
|
/**
|
|
@@ -13110,7 +13014,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13110
13014
|
handleQueryChanges(queries, dataSource, listInstance, isMounted) {
|
|
13111
13015
|
const changeTracker = this.analyzeChanges(queries);
|
|
13112
13016
|
this.previousQueries = queries;
|
|
13113
|
-
this.applyDataSourceChanges(dataSource, queries, changeTracker);
|
|
13017
|
+
this.applyDataSourceChanges(dataSource, queries, changeTracker, isMounted);
|
|
13114
13018
|
this.handleListRefresh(listInstance, changeTracker, isMounted);
|
|
13115
13019
|
this.handleColumnChanges(changeTracker);
|
|
13116
13020
|
}
|
|
@@ -13137,8 +13041,9 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13137
13041
|
/**
|
|
13138
13042
|
* Applies filter and sort changes to the data source
|
|
13139
13043
|
*/
|
|
13140
|
-
applyDataSourceChanges(dataSource, queries, changeTracker) {
|
|
13141
|
-
|
|
13044
|
+
applyDataSourceChanges(dataSource, queries, changeTracker, isMounted) {
|
|
13045
|
+
const shouldApplyFilters = changeTracker.isFilterChanged || (!isMounted && (queries?.filters?.length ?? 0) > 0);
|
|
13046
|
+
if (shouldApplyFilters) {
|
|
13142
13047
|
dataSource.filter({
|
|
13143
13048
|
filters: queries?.filters,
|
|
13144
13049
|
});
|
|
@@ -13149,16 +13054,16 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13149
13054
|
}
|
|
13150
13055
|
}
|
|
13151
13056
|
/**
|
|
13152
|
-
* Handles list refresh logic based on changes and mount status
|
|
13057
|
+
* Handles list refresh logic based on changes and mount status.
|
|
13058
|
+
* Initial fetch is owned by {@link triggerInitialLoadIfNeeded} (manual fetchDataMode).
|
|
13153
13059
|
*/
|
|
13154
13060
|
handleListRefresh(listInstance, changeTracker, isMounted) {
|
|
13155
|
-
|
|
13156
|
-
|
|
13061
|
+
if (!isMounted) {
|
|
13062
|
+
return;
|
|
13063
|
+
}
|
|
13064
|
+
if (changeTracker.isFilterChanged || changeTracker.isSortChanged) {
|
|
13065
|
+
this.pushToolbarFiltersToDataSource();
|
|
13157
13066
|
listInstance.call('refresh');
|
|
13158
|
-
// Set mounted flag only on initial load (not when filters/sorts change)
|
|
13159
|
-
if (!changeTracker.isFilterChanged && !changeTracker.isSortChanged) {
|
|
13160
|
-
this.isMounted.set(true);
|
|
13161
|
-
}
|
|
13162
13067
|
}
|
|
13163
13068
|
}
|
|
13164
13069
|
/**
|
|
@@ -15597,8 +15502,8 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15597
15502
|
this.setLoading = (loading) => {
|
|
15598
15503
|
this.isLoading.set(loading);
|
|
15599
15504
|
};
|
|
15600
|
-
|
|
15601
|
-
|
|
15505
|
+
/** @param syncContext When false, only updates UI (hydration/revert); skips context writes. */
|
|
15506
|
+
this.setItems = (items, syncContext = true) => {
|
|
15602
15507
|
// Ensure items is always an array
|
|
15603
15508
|
items = castArray(items);
|
|
15604
15509
|
// Filter out null/undefined items
|
|
@@ -15614,13 +15519,13 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15614
15519
|
return item;
|
|
15615
15520
|
});
|
|
15616
15521
|
this.selectedItems.set(items);
|
|
15617
|
-
|
|
15522
|
+
if (!syncContext) {
|
|
15523
|
+
return;
|
|
15524
|
+
}
|
|
15618
15525
|
const keys = items.map((item) => get(item, this.valueField()));
|
|
15619
15526
|
const text = items.map((item) => this.mlsResolver.resolve(get(item, displayField)));
|
|
15620
|
-
//
|
|
15621
|
-
// extract data from valueField and set context by expose path
|
|
15622
15527
|
if (this.expose()) {
|
|
15623
|
-
this.expoesItems(
|
|
15528
|
+
this.expoesItems();
|
|
15624
15529
|
}
|
|
15625
15530
|
const newValue = this.singleOrMultiple(keys);
|
|
15626
15531
|
if (this.filterMode()) {
|
|
@@ -15630,10 +15535,10 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15630
15535
|
operation: {
|
|
15631
15536
|
type: this.multiple() ? 'in' : 'equal',
|
|
15632
15537
|
},
|
|
15633
|
-
}
|
|
15538
|
+
});
|
|
15634
15539
|
}
|
|
15635
15540
|
else {
|
|
15636
|
-
this.setValue(newValue
|
|
15541
|
+
this.setValue(newValue);
|
|
15637
15542
|
}
|
|
15638
15543
|
};
|
|
15639
15544
|
}
|
|
@@ -15647,7 +15552,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15647
15552
|
? castArray(this.filterMode() ? rawValue.value : rawValue)
|
|
15648
15553
|
: [rawValue].filter((v) => v != null);
|
|
15649
15554
|
if (!values.length) {
|
|
15650
|
-
this.setItems([]);
|
|
15555
|
+
this.setItems([], false);
|
|
15651
15556
|
this.isLoading.set(false);
|
|
15652
15557
|
return;
|
|
15653
15558
|
}
|
|
@@ -15662,22 +15567,22 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15662
15567
|
.map((id) => entityDataAccessor.byKey(id)));
|
|
15663
15568
|
// Filter out null/undefined results
|
|
15664
15569
|
const validItems = items.filter((item) => item != null);
|
|
15665
|
-
this.setItems(validItems);
|
|
15570
|
+
this.setItems(validItems, false);
|
|
15666
15571
|
}
|
|
15667
15572
|
else {
|
|
15668
15573
|
const id = extractValue(this.filterMode() ? values[0].value : values[0], this.valueField());
|
|
15669
15574
|
if (id != null) {
|
|
15670
15575
|
const item = await entityDataAccessor.byKey(id);
|
|
15671
|
-
this.setItems(item != null ? [item] : []);
|
|
15576
|
+
this.setItems(item != null ? [item] : [], false);
|
|
15672
15577
|
}
|
|
15673
15578
|
else {
|
|
15674
|
-
this.setItems([]);
|
|
15579
|
+
this.setItems([], false);
|
|
15675
15580
|
}
|
|
15676
15581
|
}
|
|
15677
15582
|
}
|
|
15678
15583
|
catch (error) {
|
|
15679
15584
|
console.error('[LookupWidget] findByValue() error:', error);
|
|
15680
|
-
this.setItems([]);
|
|
15585
|
+
this.setItems([], false);
|
|
15681
15586
|
}
|
|
15682
15587
|
finally {
|
|
15683
15588
|
this.isLoading.set(false);
|
|
@@ -15685,7 +15590,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15685
15590
|
}
|
|
15686
15591
|
//#region ---- Event Handlers from Dumb Components ----
|
|
15687
15592
|
handleComponentValueChanged(items) {
|
|
15688
|
-
this.setItems(items ?? []
|
|
15593
|
+
this.setItems(items ?? []);
|
|
15689
15594
|
}
|
|
15690
15595
|
async handleCreateClick(_e) {
|
|
15691
15596
|
const entity = this.entityDef();
|
|
@@ -15710,10 +15615,10 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15710
15615
|
if (this.multiple()) {
|
|
15711
15616
|
const exists = currentItems.some((item) => get(item, valueField) === newId);
|
|
15712
15617
|
const newItems = exists ? currentItems : [...currentItems, createdItem];
|
|
15713
|
-
this.setItems(newItems
|
|
15618
|
+
this.setItems(newItems);
|
|
15714
15619
|
}
|
|
15715
15620
|
else {
|
|
15716
|
-
this.setItems([createdItem]
|
|
15621
|
+
this.setItems([createdItem]);
|
|
15717
15622
|
}
|
|
15718
15623
|
}
|
|
15719
15624
|
}
|
|
@@ -15730,7 +15635,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15730
15635
|
* so e.g. `{ person: { educationLevel: { id, title } } }` would replace the entire `person`
|
|
15731
15636
|
* object and drop sibling fields like `person.educationLevelId`, causing a value/effect loop.
|
|
15732
15637
|
*/
|
|
15733
|
-
expoesItems(
|
|
15638
|
+
expoesItems() {
|
|
15734
15639
|
const exposeValue = castArray(this.expose());
|
|
15735
15640
|
const items = this.selectedItems();
|
|
15736
15641
|
const isEmpty = !items || items.length === 0;
|
|
@@ -15743,7 +15648,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15743
15648
|
parentPaths.add(pathParts.slice(0, -1).join('.'));
|
|
15744
15649
|
}
|
|
15745
15650
|
else {
|
|
15746
|
-
this.contextService.update(i, null
|
|
15651
|
+
this.contextService.update(i, null);
|
|
15747
15652
|
}
|
|
15748
15653
|
}
|
|
15749
15654
|
else {
|
|
@@ -15752,25 +15657,25 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15752
15657
|
parentPaths.add(pathParts.slice(0, -1).join('.'));
|
|
15753
15658
|
}
|
|
15754
15659
|
else {
|
|
15755
|
-
this.contextService.update(i.target, null
|
|
15660
|
+
this.contextService.update(i.target, null);
|
|
15756
15661
|
}
|
|
15757
15662
|
}
|
|
15758
15663
|
});
|
|
15759
15664
|
parentPaths.forEach((parentPath) => {
|
|
15760
|
-
this.contextService.update(parentPath, null
|
|
15665
|
+
this.contextService.update(parentPath, null);
|
|
15761
15666
|
});
|
|
15762
15667
|
return;
|
|
15763
15668
|
}
|
|
15764
15669
|
exposeValue.forEach((i) => {
|
|
15765
15670
|
if (typeof i === 'string') {
|
|
15766
15671
|
const values = items.map((item) => set({}, i, get(item, i)));
|
|
15767
|
-
this.contextService.update(i, this.singleOrMultiple(values)
|
|
15672
|
+
this.contextService.update(i, this.singleOrMultiple(values));
|
|
15768
15673
|
}
|
|
15769
15674
|
else {
|
|
15770
15675
|
const values = this.multiple()
|
|
15771
15676
|
? items.map((item) => set({}, i.source, get(item, i.source)))
|
|
15772
15677
|
: items.map((item) => get(item, i.source));
|
|
15773
|
-
this.contextService.update(i.target, this.singleOrMultiple(values)
|
|
15678
|
+
this.contextService.update(i.target, this.singleOrMultiple(values));
|
|
15774
15679
|
}
|
|
15775
15680
|
});
|
|
15776
15681
|
}
|
|
@@ -16185,7 +16090,7 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
16185
16090
|
if (!resolvedTitle) {
|
|
16186
16091
|
const displayTitle = formatLookupItemDisplay(headerItem, this.entityDef(), this.lookupDisplayOptions(), this.formatService, (value) => this.translation.resolve(value));
|
|
16187
16092
|
resolvedTitle = typeof displayTitle === 'string' ? displayTitle : this.translation.resolve(displayTitle);
|
|
16188
|
-
if (
|
|
16093
|
+
if (isUnresolvedEntityDisplayTemplate(resolvedTitle)) {
|
|
16189
16094
|
resolvedTitle = '';
|
|
16190
16095
|
}
|
|
16191
16096
|
}
|
|
@@ -19105,32 +19010,10 @@ function hasFileUploaderTitleOrDescriptionFields(editDialog) {
|
|
|
19105
19010
|
}
|
|
19106
19011
|
//#endregion
|
|
19107
19012
|
|
|
19108
|
-
//#region ----
|
|
19013
|
+
//#region ---- Imports ----
|
|
19109
19014
|
//#endregion
|
|
19110
|
-
//#region ----
|
|
19015
|
+
//#region ---- Title template resolution ----
|
|
19111
19016
|
const INVALID_DISPLAY_TEXT = '[object Object]';
|
|
19112
|
-
/**
|
|
19113
|
-
* Row title template for entity-scoped popovers (e.g. attachment file list).
|
|
19114
|
-
* Priority: `interfaces.master.single.title` → `formats.searchResult.title` → `formats.individual`.
|
|
19115
|
-
*/
|
|
19116
|
-
function resolveEntityRowTitleTemplate(entity) {
|
|
19117
|
-
if (!entity) {
|
|
19118
|
-
return undefined;
|
|
19119
|
-
}
|
|
19120
|
-
const singleTitle = entity.interfaces?.master?.single?.title?.trim();
|
|
19121
|
-
if (singleTitle) {
|
|
19122
|
-
return normalizeLookupDisplayTemplate(singleTitle);
|
|
19123
|
-
}
|
|
19124
|
-
const searchTitle = entity.formats?.searchResult?.title?.trim();
|
|
19125
|
-
if (searchTitle) {
|
|
19126
|
-
return normalizeLookupDisplayTemplate(searchTitle);
|
|
19127
|
-
}
|
|
19128
|
-
const individual = entity.formats?.individual?.trim();
|
|
19129
|
-
if (individual) {
|
|
19130
|
-
return normalizeLookupDisplayTemplate(individual);
|
|
19131
|
-
}
|
|
19132
|
-
return undefined;
|
|
19133
|
-
}
|
|
19134
19017
|
/** Resolves a row field or format result to a plain display string for the active locale. */
|
|
19135
19018
|
function resolveEntityRowDisplayText(value, activeLang) {
|
|
19136
19019
|
if (value == null || value === '') {
|
|
@@ -19138,7 +19021,7 @@ function resolveEntityRowDisplayText(value, activeLang) {
|
|
|
19138
19021
|
}
|
|
19139
19022
|
if (typeof value === 'string') {
|
|
19140
19023
|
const text = value.trim();
|
|
19141
|
-
if (!text || text === INVALID_DISPLAY_TEXT ||
|
|
19024
|
+
if (!text || text === INVALID_DISPLAY_TEXT || isUnresolvedEntityDisplayTemplate(text)) {
|
|
19142
19025
|
return '';
|
|
19143
19026
|
}
|
|
19144
19027
|
return text;
|
|
@@ -19156,21 +19039,25 @@ function resolveEntityRowDisplayText(value, activeLang) {
|
|
|
19156
19039
|
return '';
|
|
19157
19040
|
}
|
|
19158
19041
|
/**
|
|
19159
|
-
* Formats the entity row title for display using
|
|
19042
|
+
* Formats the entity row title for display using entity-driven templates and property paths.
|
|
19160
19043
|
*/
|
|
19161
19044
|
function formatEntityRowDisplayTitle(entity, rowData, formatService, activeLang) {
|
|
19162
19045
|
if (!rowData) {
|
|
19163
19046
|
return '';
|
|
19164
19047
|
}
|
|
19165
|
-
|
|
19166
|
-
|
|
19048
|
+
const titleContext = buildEntitySearchTitleContext(entity ?? {});
|
|
19049
|
+
for (const path of titleContext.fallbackFields) {
|
|
19050
|
+
const fromField = resolveEntityRowDisplayText(get(rowData, path), activeLang);
|
|
19167
19051
|
if (fromField) {
|
|
19168
19052
|
return fromField;
|
|
19169
19053
|
}
|
|
19170
19054
|
}
|
|
19171
|
-
const
|
|
19172
|
-
|
|
19173
|
-
|
|
19055
|
+
const templates = [
|
|
19056
|
+
resolveEntityRowTitleTemplate(entity),
|
|
19057
|
+
...titleContext.fallbackTemplates,
|
|
19058
|
+
].filter((template) => !!template?.trim());
|
|
19059
|
+
for (const template of templates) {
|
|
19060
|
+
const formatted = formatService.format(normalizeEntityDisplayTemplate(template), 'string', rowData);
|
|
19174
19061
|
const fromTemplate = resolveEntityRowDisplayText(formatted, activeLang);
|
|
19175
19062
|
if (fromTemplate) {
|
|
19176
19063
|
return fromTemplate;
|
|
@@ -21522,7 +21409,7 @@ class AXPLayoutAdapterBuilder {
|
|
|
21522
21409
|
load: this.createLoadFunction(),
|
|
21523
21410
|
pages: this.adapter.pages || [],
|
|
21524
21411
|
exitUrl: this.adapter.exitUrl,
|
|
21525
|
-
|
|
21412
|
+
getPageBadge: (context, isDirty) => this.badgeStatusService.getPageBadge(name, context, isDirty),
|
|
21526
21413
|
getPageStatus: (context, currentPage) => this.badgeStatusService.getPageStatus(name, context, currentPage),
|
|
21527
21414
|
};
|
|
21528
21415
|
}
|
|
@@ -22210,6 +22097,8 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
|
|
|
22210
22097
|
title: context.rootTitle ?? '',
|
|
22211
22098
|
label: relatedEntity.title,
|
|
22212
22099
|
icon: relatedEntity.icon || entityDef.icon,
|
|
22100
|
+
/** List-only page: scoped filters are system state, not user edits. */
|
|
22101
|
+
isReadonly: true,
|
|
22213
22102
|
actions: this.mergeActions(entityDef, actions)
|
|
22214
22103
|
?.filter((a) => a.priority === 'primary' && !a.isChild)
|
|
22215
22104
|
?.map((a) => {
|
|
@@ -22892,6 +22781,7 @@ class AXPMainEntityContentBuilder {
|
|
|
22892
22781
|
icon: 'fa-light fa-rotate-left',
|
|
22893
22782
|
color: 'default',
|
|
22894
22783
|
visible: '{{context.isDirty()}}',
|
|
22784
|
+
shortcuts: ['escape'],
|
|
22895
22785
|
command: {
|
|
22896
22786
|
name: 'discard',
|
|
22897
22787
|
},
|
|
@@ -22901,6 +22791,7 @@ class AXPMainEntityContentBuilder {
|
|
|
22901
22791
|
icon: 'fa-light fa-floppy-disk',
|
|
22902
22792
|
color: 'primary',
|
|
22903
22793
|
visible: '{{context.isDirty()}}',
|
|
22794
|
+
shortcuts: ['ctrl+s'],
|
|
22904
22795
|
command: {
|
|
22905
22796
|
name: 'update-entity',
|
|
22906
22797
|
},
|
|
@@ -23194,6 +23085,7 @@ class AXPMainEntityContentBuilder {
|
|
|
23194
23085
|
icon: action.icon,
|
|
23195
23086
|
color: action.color,
|
|
23196
23087
|
disabled: disabled || false,
|
|
23088
|
+
shortcuts: action.shortcuts,
|
|
23197
23089
|
zone: 'header',
|
|
23198
23090
|
priority: action.priority,
|
|
23199
23091
|
scope: action.scope === AXPEntityCommandScope.Individual ? AXPEntityCommandScope.TypeLevel : action.scope,
|
|
@@ -23256,17 +23148,25 @@ class AXPLayoutAdapterFactory {
|
|
|
23256
23148
|
async createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies) {
|
|
23257
23149
|
const entity = await entityResolver.resolve(moduleName, entityName);
|
|
23258
23150
|
if (!entity) {
|
|
23259
|
-
throw new
|
|
23151
|
+
throw new AXPNotFoundError(`Entity ${moduleName}.${entityName} not found`);
|
|
23260
23152
|
}
|
|
23261
23153
|
const rootContext = await this.loadRootContext(entity, id);
|
|
23262
|
-
|
|
23263
|
-
|
|
23264
|
-
|
|
23265
|
-
|
|
23266
|
-
const
|
|
23267
|
-
const
|
|
23154
|
+
if (axpIsEntityRecordNotFound(rootContext)) {
|
|
23155
|
+
throw new AXPNotFoundError(`Entity record ${moduleName}.${entityName}#${id} not found`);
|
|
23156
|
+
}
|
|
23157
|
+
// Evaluate hidden expressions for related entities and component pages once, reuse across building and composing
|
|
23158
|
+
const evaluatedRelatedEntities = await this.evaluateHiddenFlags(entity?.relatedEntities ?? [], rootContext, dependencies);
|
|
23159
|
+
const evaluatedPages = await this.evaluateHiddenFlags(entity?.pages ?? [], rootContext, dependencies);
|
|
23160
|
+
// Build main and related pages using evaluated related entities and pages
|
|
23161
|
+
const entityWithEvaluatedLayout = {
|
|
23162
|
+
...entity,
|
|
23163
|
+
relatedEntities: evaluatedRelatedEntities,
|
|
23164
|
+
pages: evaluatedPages,
|
|
23165
|
+
};
|
|
23166
|
+
const mainPage = await this.buildMainPage(entityWithEvaluatedLayout, rootContext, id, dependencies);
|
|
23167
|
+
const relatedPages = await this.buildRelatedPages(entityWithEvaluatedLayout, rootContext, dependencies);
|
|
23268
23168
|
// Compose ordered pages around the primary page
|
|
23269
|
-
const orderedPages = this.composePagesWithPositions(mainPage, relatedPages,
|
|
23169
|
+
const orderedPages = this.composePagesWithPositions(mainPage, relatedPages, entityWithEvaluatedLayout);
|
|
23270
23170
|
const applicationName = dependencies.session.application?.name ?? 'default';
|
|
23271
23171
|
const rootTitle = await this.getRootTitle(entity, rootContext, dependencies);
|
|
23272
23172
|
return this.layoutAdapterBuilder
|
|
@@ -23285,15 +23185,15 @@ class AXPLayoutAdapterFactory {
|
|
|
23285
23185
|
return this.mainEntityContentBuilder.build(entity, rootContext, { ...dependencies, reloadRootContext: () => this.loadRootContext(entity, id) }, await this.getRootTitle(entity, rootContext, dependencies));
|
|
23286
23186
|
}
|
|
23287
23187
|
/**
|
|
23288
|
-
* Evaluates the 'hidden' expression for
|
|
23289
|
-
* Returns a new array
|
|
23188
|
+
* Evaluates the 'hidden' expression for layout items using the expression evaluator.
|
|
23189
|
+
* Returns a new array with evaluated hidden values.
|
|
23290
23190
|
*/
|
|
23291
|
-
async
|
|
23292
|
-
if (!
|
|
23293
|
-
return
|
|
23191
|
+
async evaluateHiddenFlags(items, rootContext, dependencies) {
|
|
23192
|
+
if (!items?.length || !dependencies?.expressionEvaluator) {
|
|
23193
|
+
return items ?? [];
|
|
23294
23194
|
}
|
|
23295
|
-
return Promise.all(
|
|
23296
|
-
let hidden =
|
|
23195
|
+
return Promise.all(items.map(async (item) => {
|
|
23196
|
+
let hidden = item.hidden;
|
|
23297
23197
|
if (hidden && typeof hidden === 'string') {
|
|
23298
23198
|
try {
|
|
23299
23199
|
const scope = {
|
|
@@ -23308,9 +23208,12 @@ class AXPLayoutAdapterFactory {
|
|
|
23308
23208
|
// Keep original hidden value if evaluation fails
|
|
23309
23209
|
}
|
|
23310
23210
|
}
|
|
23311
|
-
return { ...
|
|
23211
|
+
return { ...item, hidden };
|
|
23312
23212
|
}));
|
|
23313
23213
|
}
|
|
23214
|
+
async evaluateRelatedEntitiesHidden(relatedEntities, rootContext, dependencies) {
|
|
23215
|
+
return this.evaluateHiddenFlags(relatedEntities, rootContext, dependencies);
|
|
23216
|
+
}
|
|
23314
23217
|
async buildRelatedPages(entity, rootContext, dependencies) {
|
|
23315
23218
|
const pages = [];
|
|
23316
23219
|
const rootTitle = await this.getRootTitle(entity, rootContext, dependencies);
|
|
@@ -23475,7 +23378,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
23475
23378
|
}]
|
|
23476
23379
|
}], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }, { type: AXPMainEntityContentBuilder }, { type: AXPLayoutAdapterBuilder }, { type: i4$3.AXPFilterOperatorMiddlewareService }] });
|
|
23477
23380
|
|
|
23478
|
-
const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver = inject(AXPEntityDefinitionRegistryService), expressionEvaluator = inject(AXPExpressionEvaluatorService), session = inject(AXPSessionService), formatService = inject(AXFormatService), workflowService = inject(AXPWorkflowService), commandService = inject(AXPCommandService), layoutAdapterFactory = inject(AXPLayoutAdapterFactory)) => {
|
|
23381
|
+
const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver = inject(AXPEntityDefinitionRegistryService), expressionEvaluator = inject(AXPExpressionEvaluatorService), session = inject(AXPSessionService), formatService = inject(AXFormatService), workflowService = inject(AXPWorkflowService), commandService = inject(AXPCommandService), layoutAdapterFactory = inject(AXPLayoutAdapterFactory), router = inject(Router)) => {
|
|
23479
23382
|
const moduleName = route.parent?.paramMap.get('module');
|
|
23480
23383
|
const entityName = route.paramMap.get('entity');
|
|
23481
23384
|
const id = route.paramMap.get('id');
|
|
@@ -23487,8 +23390,15 @@ const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver =
|
|
|
23487
23390
|
workflowService,
|
|
23488
23391
|
commandService,
|
|
23489
23392
|
};
|
|
23490
|
-
|
|
23491
|
-
|
|
23393
|
+
try {
|
|
23394
|
+
return await layoutAdapterFactory.createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies);
|
|
23395
|
+
}
|
|
23396
|
+
catch (error) {
|
|
23397
|
+
if (error instanceof AXPNotFoundError) {
|
|
23398
|
+
return axpRedirectToNotFound(router);
|
|
23399
|
+
}
|
|
23400
|
+
throw error;
|
|
23401
|
+
}
|
|
23492
23402
|
};
|
|
23493
23403
|
|
|
23494
23404
|
class AXPEntityPreloadFilterGuard {
|
|
@@ -24262,7 +24172,7 @@ const AXPCrudModifier = {
|
|
|
24262
24172
|
queries.list = {
|
|
24263
24173
|
execute: async (e) => {
|
|
24264
24174
|
const res = await dataService.query(e);
|
|
24265
|
-
console.log('query', res, ctx.module.get() + '.' + ctx.name.get(), e);
|
|
24175
|
+
// console.log('query', res, ctx.module.get() + '.' + ctx.name.get(), e);
|
|
24266
24176
|
return res;
|
|
24267
24177
|
},
|
|
24268
24178
|
type: AXPEntityQueryType.List,
|
|
@@ -24305,6 +24215,8 @@ class AXPEntitySearchDefinitionProvider {
|
|
|
24305
24215
|
this.entityRegister.getAll().forEach((entity) => {
|
|
24306
24216
|
const manifest = this.manifestRegistry.get(entity.module);
|
|
24307
24217
|
const i18nScope = manifest?.i18n ?? moduleNameToI18nScope(entity.module);
|
|
24218
|
+
const searchTitleTemplate = entity.formats.searchResult?.title;
|
|
24219
|
+
const titleContext = buildEntitySearchTitleContext(entity, searchTitleTemplate);
|
|
24308
24220
|
context.addDefinition(`Module.${entity.module}.${entity.name}`, `@${i18nScope}:module.title`, `Module.${entity.module}`, entity.icon ?? 'fa-solid fa-objects-column', 4, {
|
|
24309
24221
|
actions: [
|
|
24310
24222
|
{
|
|
@@ -24314,9 +24226,11 @@ class AXPEntitySearchDefinitionProvider {
|
|
|
24314
24226
|
},
|
|
24315
24227
|
],
|
|
24316
24228
|
format: {
|
|
24317
|
-
title:
|
|
24229
|
+
title: searchTitleTemplate,
|
|
24318
24230
|
description: (entity.formats.searchResult?.description) ?? `${entity.module} / ${entity.title}`,
|
|
24319
24231
|
id: '{{data.id}}',
|
|
24232
|
+
titleFallbackTemplates: titleContext.fallbackTemplates,
|
|
24233
|
+
titleFallbackFields: titleContext.fallbackFields,
|
|
24320
24234
|
},
|
|
24321
24235
|
});
|
|
24322
24236
|
});
|
|
@@ -25000,7 +24914,7 @@ function routesFacory() {
|
|
|
25000
24914
|
loadComponent: () => {
|
|
25001
24915
|
return config.viewers.root();
|
|
25002
24916
|
},
|
|
25003
|
-
canActivate: [
|
|
24917
|
+
canActivate: [...AXP_PROTECTED_ROUTE_GUARDS],
|
|
25004
24918
|
children: [
|
|
25005
24919
|
{
|
|
25006
24920
|
path: ':module',
|
|
@@ -25038,6 +24952,7 @@ function routesFacory() {
|
|
|
25038
24952
|
loadComponent: () => {
|
|
25039
24953
|
return config.viewers.master.details();
|
|
25040
24954
|
},
|
|
24955
|
+
canDeactivate: [axpDetailsViewCanDeactivateGuard],
|
|
25041
24956
|
runGuardsAndResolvers: (from, to) => {
|
|
25042
24957
|
const entityChanged = from.params['module'] !== to.params['module'] || from.params['entity'] !== to.params['entity'];
|
|
25043
24958
|
const idChanged = from.params['id'] !== to.params['id'];
|
|
@@ -25056,8 +24971,16 @@ function routesFacory() {
|
|
|
25056
24971
|
redirectTo: ':entity/list',
|
|
25057
24972
|
pathMatch: 'full',
|
|
25058
24973
|
},
|
|
24974
|
+
{
|
|
24975
|
+
path: '**',
|
|
24976
|
+
redirectTo: AXP_NOT_FOUND_ROUTE,
|
|
24977
|
+
},
|
|
25059
24978
|
],
|
|
25060
24979
|
},
|
|
24980
|
+
{
|
|
24981
|
+
path: '**',
|
|
24982
|
+
redirectTo: AXP_NOT_FOUND_ROUTE,
|
|
24983
|
+
},
|
|
25061
24984
|
],
|
|
25062
24985
|
},
|
|
25063
24986
|
];
|
|
@@ -25611,5 +25534,5 @@ var getEntityDetails_query = /*#__PURE__*/Object.freeze({
|
|
|
25611
25534
|
* Generated bundle index. Do not edit.
|
|
25612
25535
|
*/
|
|
25613
25536
|
|
|
25614
|
-
export { ATTACHMENTS_PAGE_COMPONENT_KEY, AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCategoryTreeService, AXPCreateEntityCommand, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEditFileUploaderCommand, AXPEntitiesListDataSourceDefinition, AXPEntityApplyUpdatesAction, AXPEntityCategoryTreeSelectorComponent, AXPEntityCategoryWidget, AXPEntityCategoryWidgetColumnComponent, AXPEntityCategoryWidgetEditComponent, AXPEntityCategoryWidgetViewComponent, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDataSelectorRowActionsService, AXPEntityDataSelectorService, AXPEntityDefinitionProviderWidget, AXPEntityDefinitionProviderWidgetEditComponent, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailPopoverComponent, AXPEntityDetailPopoverService, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityEventsKeys, AXPEntityFormBuilderService, AXPEntityListPersistenceModeDefault, AXPEntityListTableService, AXPEntityListToolbarService, AXPEntityListViewCardFieldViewModel, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityListWidget, AXPEntityListWidgetViewComponent, AXPEntityMasterCreateViewModel, AXPEntityMasterListCardSelectActionName, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityPreloadFiltersContainerComponent, AXPEntityPreloadFiltersViewModel, AXPEntityPreloadFiltersViewModelResolver, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPEntityUpdateViewSectionViewModel, AXPFileListComponent, AXPFileUploaderLoadFilesQuery, AXPFileUploaderSaveFilesCommand, AXPFileUploaderWidget, AXPFileUploaderWidgetColumnComponent, AXPFileUploaderWidgetEditComponent, AXPFileUploaderWidgetService, AXPFileUploaderWidgetViewComponent, AXPGetEntityDetailsQuery, AXPLayoutOrderingConfigService, AXPLookupWidget, AXPLookupWidgetColumnComponent, AXPLookupWidgetEditComponent, AXPLookupWidgetViewComponent, AXPMiddlewareAbortError, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPMultiSourceDefinitionProviderContext, AXPMultiSourceDefinitionProviderService, AXPMultiSourceFederatedSearchService, AXPMultiSourceSelectorComponent, AXPMultiSourceSelectorService, AXPMultiSourceSelectorWidget, AXPMultiSourceSelectorWidgetColumnComponent, AXPMultiSourceSelectorWidgetEditComponent, AXPMultiSourceSelectorWidgetViewComponent, AXPMultiSourceType, AXPOpenEntityDetailsCommand, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPRelatedColumnEnrichmentService, AXPRelatedColumnMetadataResolver, AXPSelectorStructureWidget, AXPSelectorStructureWidgetColumnComponent, AXPSelectorStructureWidgetEditComponent, AXPSelectorStructureWidgetViewComponent, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXPTruncatedBreadcrumbComponent, AXPUpdateEntityCommand, AXPViewEntityDetailsCommand, AXP_CATEGORY_TREE_ROOT_TITLE_I18N_KEY, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, AXP_MULTI_SOURCE_DEFINITION_PROVIDER, AXP_RECORD_WORKFLOW_INFO_CORRELATION_ID_FIELD, AXP_RECORD_WORKFLOW_INFO_DEFINITION_ID_FIELD, AXP_RECORD_WORKFLOW_INFO_INSTANCE_ID_FIELD, DEFAULT_COLUMN_ORDER, DEFAULT_PAIR_SPAN_RULES, DEFAULT_PROPERTY_ORDER, DEFAULT_SECTION_ORDER, ENTITY_LIST_ROUTE_CONTEXT_SESSION_KEY, EntityBuilder, EntityDataAccessor, actionExists, applyDataSourcePagingWithoutLoad, attachmentFieldCount, attachmentsPlugin, attachmentsSemanticallyEqual, axpCreateEntityAiToolInputDefaults, axpCreateEntityCommandDefinition, buildAXPRecordWorkflowInfo, canPersistEntityListState, cloneLayoutArrays, collectEntityQuickSearchFieldPaths, collectNestedCreateHiddenProperties, collectNestedFieldPathsFromEntityColumns, collectQuickSearchPathsFromSingleEntityDefinition, columnOrderingMiddleware, columnOrderingMiddlewareProvider, columnWidthMiddleware, columnWidthMiddlewareProvider, commandMessageTextForError, committedAttachments, computeEntityAggregates, createColumnOrderingMiddlewareProvider, createLayoutOrderingMiddlewareProvider, createModifierContext, defaultCardLayoutMiddleware, defaultCardLayoutMiddlewareProvider, defaultMultiLanguageMiddleware, defaultMultiLanguageMiddlewareProvider, detectEntityChanges, ensureLayoutPropertyView, ensureLayoutSection, ensureListActions, entityDetailsCreateActions, entityDetailsCreateActionsDeferredParent, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsNewEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterEditAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware, filterSortEntityRows, findEntityListRowDataInTree, fingerprintAttachmentItem, fingerprintAttachments, formatLookupItemDisplay, getDataSourcePageIndex, getEntityListRowId, getMasterInterfacePropertySortKey, getRecordWorkflowCorrelationId, getRecordWorkflowInstanceId, hasFileUploaderTitleOrDescriptionFields, isAXPMiddlewareAbortError, isAttachmentListEntry, isCategoryEntity, isCategoryFilter, isFileListItem, isFileUploaderEditDialogAuto, isLegacyEntityDataSelectorOptions,
|
|
25537
|
+
export { ATTACHMENTS_PAGE_COMPONENT_KEY, AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCategoryTreeService, AXPCreateEntityCommand, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEditFileUploaderCommand, AXPEntitiesListDataSourceDefinition, AXPEntityApplyUpdatesAction, AXPEntityCategoryTreeSelectorComponent, AXPEntityCategoryWidget, AXPEntityCategoryWidgetColumnComponent, AXPEntityCategoryWidgetEditComponent, AXPEntityCategoryWidgetViewComponent, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDataSelectorRowActionsService, AXPEntityDataSelectorService, AXPEntityDefinitionProviderWidget, AXPEntityDefinitionProviderWidgetEditComponent, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailPopoverComponent, AXPEntityDetailPopoverService, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityEventsKeys, AXPEntityFormBuilderService, AXPEntityListPersistenceModeDefault, AXPEntityListTableService, AXPEntityListToolbarService, AXPEntityListViewCardFieldViewModel, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityListWidget, AXPEntityListWidgetViewComponent, AXPEntityMasterCreateViewModel, AXPEntityMasterListCardSelectActionName, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityPreloadFiltersContainerComponent, AXPEntityPreloadFiltersViewModel, AXPEntityPreloadFiltersViewModelResolver, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPEntityUpdateViewSectionViewModel, AXPFileListComponent, AXPFileUploaderLoadFilesQuery, AXPFileUploaderSaveFilesCommand, AXPFileUploaderWidget, AXPFileUploaderWidgetColumnComponent, AXPFileUploaderWidgetEditComponent, AXPFileUploaderWidgetService, AXPFileUploaderWidgetViewComponent, AXPGetEntityDetailsQuery, AXPLayoutOrderingConfigService, AXPLookupWidget, AXPLookupWidgetColumnComponent, AXPLookupWidgetEditComponent, AXPLookupWidgetViewComponent, AXPMiddlewareAbortError, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPMultiSourceDefinitionProviderContext, AXPMultiSourceDefinitionProviderService, AXPMultiSourceFederatedSearchService, AXPMultiSourceSelectorComponent, AXPMultiSourceSelectorService, AXPMultiSourceSelectorWidget, AXPMultiSourceSelectorWidgetColumnComponent, AXPMultiSourceSelectorWidgetEditComponent, AXPMultiSourceSelectorWidgetViewComponent, AXPMultiSourceType, AXPOpenEntityDetailsCommand, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPRelatedColumnEnrichmentService, AXPRelatedColumnMetadataResolver, AXPSelectorStructureWidget, AXPSelectorStructureWidgetColumnComponent, AXPSelectorStructureWidgetEditComponent, AXPSelectorStructureWidgetViewComponent, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXPTruncatedBreadcrumbComponent, AXPUpdateEntityCommand, AXPViewEntityDetailsCommand, AXP_CATEGORY_TREE_ROOT_TITLE_I18N_KEY, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, AXP_MULTI_SOURCE_DEFINITION_PROVIDER, AXP_RECORD_WORKFLOW_INFO_CORRELATION_ID_FIELD, AXP_RECORD_WORKFLOW_INFO_DEFINITION_ID_FIELD, AXP_RECORD_WORKFLOW_INFO_INSTANCE_ID_FIELD, DEFAULT_COLUMN_ORDER, DEFAULT_PAIR_SPAN_RULES, DEFAULT_PROPERTY_ORDER, DEFAULT_SECTION_ORDER, ENTITY_LIST_ROUTE_CONTEXT_SESSION_KEY, EntityBuilder, EntityDataAccessor, actionExists, applyDataSourcePagingWithoutLoad, attachmentFieldCount, attachmentsPlugin, attachmentsSemanticallyEqual, axpCreateEntityAiToolInputDefaults, axpCreateEntityCommandDefinition, buildAXPRecordWorkflowInfo, canPersistEntityListState, cloneLayoutArrays, collectEntityQuickSearchFieldPaths, collectNestedCreateHiddenProperties, collectNestedFieldPathsFromEntityColumns, collectQuickSearchPathsFromSingleEntityDefinition, columnOrderingMiddleware, columnOrderingMiddlewareProvider, columnWidthMiddleware, columnWidthMiddlewareProvider, commandMessageTextForError, committedAttachments, computeEntityAggregates, createColumnOrderingMiddlewareProvider, createLayoutOrderingMiddlewareProvider, createModifierContext, defaultCardLayoutMiddleware, defaultCardLayoutMiddlewareProvider, defaultMultiLanguageMiddleware, defaultMultiLanguageMiddlewareProvider, detectEntityChanges, ensureLayoutPropertyView, ensureLayoutSection, ensureListActions, entityDetailsCreateActions, entityDetailsCreateActionsDeferredParent, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsNewEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterEditAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware, filterSortEntityRows, findEntityListRowDataInTree, fingerprintAttachmentItem, fingerprintAttachments, formatLookupItemDisplay, getDataSourcePageIndex, getEntityListRowId, getMasterInterfacePropertySortKey, getRecordWorkflowCorrelationId, getRecordWorkflowInstanceId, hasFileUploaderTitleOrDescriptionFields, isAXPMiddlewareAbortError, isAttachmentListEntry, isCategoryEntity, isCategoryFilter, isFileListItem, isFileUploaderEditDialogAuto, isLegacyEntityDataSelectorOptions, layoutOrderingMiddlewareFactory, layoutOrderingMiddlewareProvider, mapEntityStorageErrorToCommandResult, mapLegacyEntityDataSelectorOptions, mergeForeignKeyFieldIntoCreateActions, normalizeEntityDataSelectorOptions, normalizeEntityFieldToFileList, normalizeEntityListPersistenceMode, normalizeListPaging, persistedAttachments, provideEntity, resolveEntityPluginDetailPageOrder, resolveFileUploaderEditDialog, resolveFileUploaderEntityScope, resolveLookupDisplayField, resolveLookupDisplayTemplate, restoreEntityListExpandedRows, runEntityQuery, searchResultDescriptionMiddleware, searchResultDescriptionMiddlewareProvider, shouldLoadEntityListStateFromStorage, shouldResetEntityListStateOnRouteEntry };
|
|
25615
25538
|
//# sourceMappingURL=acorex-platform-layout-entity.mjs.map
|