@acorex/platform 21.0.0-next.71 → 21.0.0-next.73
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/contracts/README.md +3 -0
- package/fesm2022/acorex-platform-auth.mjs +82 -60
- 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 +3796 -1677
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-contracts.mjs +10 -0
- package/fesm2022/acorex-platform-contracts.mjs.map +1 -0
- package/fesm2022/acorex-platform-core.mjs +1126 -114
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +56 -170
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +254 -53
- 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 +403 -460
- 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 +126 -75
- 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 +450 -750
- 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 +79 -35
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-shared.mjs +3 -0
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/fesm2022/acorex-platform-workflow.mjs +57 -54
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/package.json +5 -1
- package/types/acorex-platform-auth.d.ts +31 -22
- package/types/acorex-platform-common.d.ts +892 -259
- package/types/acorex-platform-contracts.d.ts +39 -0
- package/types/acorex-platform-core.d.ts +291 -47
- package/types/acorex-platform-layout-builder.d.ts +10 -22
- package/types/acorex-platform-layout-components.d.ts +86 -14
- package/types/acorex-platform-layout-entity.d.ts +218 -212
- package/types/acorex-platform-layout-views.d.ts +125 -67
- package/types/acorex-platform-layout-widget-core.d.ts +56 -62
- package/types/acorex-platform-layout-widgets.d.ts +78 -65
- 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
|
};
|
|
@@ -2971,18 +2971,56 @@ var viewEntityDetails_command = /*#__PURE__*/Object.freeze({
|
|
|
2971
2971
|
AXPViewEntityDetailsCommand: AXPViewEntityDetailsCommand
|
|
2972
2972
|
});
|
|
2973
2973
|
|
|
2974
|
-
//#region ----
|
|
2975
|
-
/**
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2974
|
+
//#region ---- Datasource keys ----
|
|
2975
|
+
/** Platform entity layout datasource registry names. */
|
|
2976
|
+
const AXPEntityDataSourceKeys = {
|
|
2977
|
+
Entities: 'entities',
|
|
2978
|
+
};
|
|
2979
|
+
//#endregion
|
|
2980
|
+
|
|
2981
|
+
const AXPEntityEventsKeys = {
|
|
2982
|
+
REFRESH_LAYOUT: 'entity:refresh-layout',
|
|
2983
|
+
REFRESH_DATA: 'entity:refresh-data',
|
|
2984
|
+
};
|
|
2985
|
+
|
|
2986
|
+
//#endregion
|
|
2987
|
+
|
|
2988
|
+
/** Entity query filter field for {@link AXPRecordWorkflowInfo.instanceId}. */
|
|
2989
|
+
const AXP_RECORD_WORKFLOW_INFO_INSTANCE_ID_FIELD = 'workflowInfo.instanceId';
|
|
2990
|
+
/** Entity query filter field for {@link AXPRecordWorkflowInfo.correlationId}. */
|
|
2991
|
+
const AXP_RECORD_WORKFLOW_INFO_CORRELATION_ID_FIELD = 'workflowInfo.correlationId';
|
|
2992
|
+
/** Entity query filter field for {@link AXPRecordWorkflowInfo.definitionId}. */
|
|
2993
|
+
const AXP_RECORD_WORKFLOW_INFO_DEFINITION_ID_FIELD = 'workflowInfo.definitionId';
|
|
2994
|
+
/** Returns a trimmed workflow instance id from a record, if present. */
|
|
2995
|
+
function getRecordWorkflowInstanceId(record) {
|
|
2996
|
+
const id = record?.workflowInfo?.instanceId?.trim();
|
|
2997
|
+
return id && id.length > 0 ? id : null;
|
|
2998
|
+
}
|
|
2999
|
+
/** Returns a trimmed workflow correlation id from a record, if present. */
|
|
3000
|
+
function getRecordWorkflowCorrelationId(record) {
|
|
3001
|
+
const id = record?.workflowInfo?.correlationId?.trim();
|
|
3002
|
+
return id && id.length > 0 ? id : null;
|
|
3003
|
+
}
|
|
3004
|
+
/** Builds canonical workflow metadata for a domain record (engine / middleware). */
|
|
3005
|
+
function buildAXPRecordWorkflowInfo(params) {
|
|
3006
|
+
const instanceId = params.instanceId?.trim();
|
|
3007
|
+
if (!instanceId) {
|
|
3008
|
+
return {};
|
|
2983
3009
|
}
|
|
2984
|
-
|
|
3010
|
+
const definitionId = params.definitionId?.trim();
|
|
3011
|
+
const correlationId = params.correlationId?.trim();
|
|
3012
|
+
return {
|
|
3013
|
+
instanceId,
|
|
3014
|
+
...(definitionId ? { definitionId } : { definitionId: null }),
|
|
3015
|
+
...(correlationId ? { correlationId } : { correlationId: null }),
|
|
3016
|
+
...(params.pinnedVersion != null ? { pinnedVersion: params.pinnedVersion } : {}),
|
|
3017
|
+
};
|
|
2985
3018
|
}
|
|
3019
|
+
|
|
3020
|
+
//#region ---- Contracts barrel ----
|
|
3021
|
+
//#endregion
|
|
3022
|
+
|
|
3023
|
+
//#region ---- Template resolution ----
|
|
2986
3024
|
/**
|
|
2987
3025
|
* Resolves the display template for a lookup item.
|
|
2988
3026
|
* Priority: explicit `displayFormat` → entity `formats.lookup` (template) → entity `formats.searchResult.title`.
|
|
@@ -2991,18 +3029,18 @@ function normalizeLookupDisplayTemplate(template) {
|
|
|
2991
3029
|
function resolveLookupDisplayTemplate(entity, options) {
|
|
2992
3030
|
const explicit = options.displayFormat?.trim();
|
|
2993
3031
|
if (explicit) {
|
|
2994
|
-
return
|
|
3032
|
+
return normalizeEntityDisplayTemplate(explicit);
|
|
2995
3033
|
}
|
|
2996
3034
|
if (options.textField?.trim()) {
|
|
2997
3035
|
return undefined;
|
|
2998
3036
|
}
|
|
2999
3037
|
const lookupFormat = entity?.formats?.lookup?.trim();
|
|
3000
3038
|
if (lookupFormat && (lookupFormat.includes('{{') || lookupFormat.includes('{'))) {
|
|
3001
|
-
return
|
|
3039
|
+
return normalizeEntityDisplayTemplate(lookupFormat);
|
|
3002
3040
|
}
|
|
3003
3041
|
const searchTitle = entity?.formats?.searchResult?.title?.trim();
|
|
3004
3042
|
if (searchTitle) {
|
|
3005
|
-
return
|
|
3043
|
+
return normalizeEntityDisplayTemplate(searchTitle);
|
|
3006
3044
|
}
|
|
3007
3045
|
return undefined;
|
|
3008
3046
|
}
|
|
@@ -3043,7 +3081,7 @@ function formatLookupItemDisplay(item, entity, options, formatService, resolveMu
|
|
|
3043
3081
|
const formatted = formatService.format(template, 'string', item);
|
|
3044
3082
|
if (formatted) {
|
|
3045
3083
|
const text = String(formatted);
|
|
3046
|
-
if (!
|
|
3084
|
+
if (!isUnresolvedEntityDisplayTemplate(text)) {
|
|
3047
3085
|
return text;
|
|
3048
3086
|
}
|
|
3049
3087
|
}
|
|
@@ -3064,10 +3102,6 @@ function formatLookupItemDisplay(item, entity, options, formatService, resolveMu
|
|
|
3064
3102
|
}
|
|
3065
3103
|
return String(raw);
|
|
3066
3104
|
}
|
|
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
3105
|
//#endregion
|
|
3072
3106
|
|
|
3073
3107
|
class AXPEntityDetailPopoverComponent {
|
|
@@ -3107,7 +3141,7 @@ class AXPEntityDetailPopoverComponent {
|
|
|
3107
3141
|
}
|
|
3108
3142
|
}
|
|
3109
3143
|
const preset = this.displayTitle()?.trim();
|
|
3110
|
-
if (preset && !
|
|
3144
|
+
if (preset && !isUnresolvedEntityDisplayTemplate(preset)) {
|
|
3111
3145
|
return preset;
|
|
3112
3146
|
}
|
|
3113
3147
|
const fallbackItem = this.item();
|
|
@@ -3206,7 +3240,7 @@ class AXPEntityDetailPopoverComponent {
|
|
|
3206
3240
|
resolveLookupDisplayLabel(item, entityDefinition) {
|
|
3207
3241
|
const label = formatLookupItemDisplay(item, entityDefinition, { textField: this.textField() }, this.formatService, (value) => this.translation.resolve(value));
|
|
3208
3242
|
const resolved = typeof label === 'string' ? label : this.translation.resolve(label);
|
|
3209
|
-
return resolved && !
|
|
3243
|
+
return resolved && !isUnresolvedEntityDisplayTemplate(resolved) ? resolved : '';
|
|
3210
3244
|
}
|
|
3211
3245
|
/**
|
|
3212
3246
|
* Returns true if a value is meaningful for display (non-empty/non-null).
|
|
@@ -3777,6 +3811,16 @@ class EntityDataAccessor {
|
|
|
3777
3811
|
}
|
|
3778
3812
|
return await this.crudService.query(queryRequest);
|
|
3779
3813
|
}
|
|
3814
|
+
/**
|
|
3815
|
+
* Queries category entities linked to this entity (`{module}.{entity}Category`).
|
|
3816
|
+
* Falls back to CRUD category storage (same as {@link AXMEntityCrudServiceImpl.getCategoriesList}).
|
|
3817
|
+
*/
|
|
3818
|
+
async getCategoriesList(request = { skip: 0, take: 1000 }) {
|
|
3819
|
+
if (!this.crudService) {
|
|
3820
|
+
this.crudService = new AXMEntityCrudServiceImpl(`${this.module}.${this.entity}`);
|
|
3821
|
+
}
|
|
3822
|
+
return await this.crudService.getCategoriesList(request);
|
|
3823
|
+
}
|
|
3780
3824
|
/**
|
|
3781
3825
|
* Creates a new entity.
|
|
3782
3826
|
* @param data - The entity data to create
|
|
@@ -4135,7 +4179,7 @@ class AXPEntitiesListDataSourceDefinition {
|
|
|
4135
4179
|
items() {
|
|
4136
4180
|
return Promise.resolve([
|
|
4137
4181
|
{
|
|
4138
|
-
name:
|
|
4182
|
+
name: AXPEntityDataSourceKeys.Entities,
|
|
4139
4183
|
title: 'Entities',
|
|
4140
4184
|
columns: [
|
|
4141
4185
|
{
|
|
@@ -4356,6 +4400,7 @@ class AXPEntityCommandTriggerViewModel {
|
|
|
4356
4400
|
this.hidden = action.hidden ?? false;
|
|
4357
4401
|
this.disabled = action.disabled ?? false;
|
|
4358
4402
|
this.default = action.default ?? false;
|
|
4403
|
+
this.shortcuts = action.shortcuts;
|
|
4359
4404
|
this.scope = action.scope;
|
|
4360
4405
|
this.order = action.order ?? 0;
|
|
4361
4406
|
this.isChild = isChild;
|
|
@@ -4739,11 +4784,6 @@ class AXPEntityDetailListViewModel {
|
|
|
4739
4784
|
}
|
|
4740
4785
|
}
|
|
4741
4786
|
|
|
4742
|
-
const AXPEntityEventsKeys = {
|
|
4743
|
-
REFRESH_LAYOUT: 'entity:refresh-layout',
|
|
4744
|
-
REFRESH_DATA: 'entity:refresh-data',
|
|
4745
|
-
};
|
|
4746
|
-
|
|
4747
4787
|
/**
|
|
4748
4788
|
* Entity Event Dispatcher - A wrapper for entity-specific events
|
|
4749
4789
|
* Handles pattern-based dispatching for entity operations with wildcard support
|
|
@@ -6642,20 +6682,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
6642
6682
|
type: Injectable,
|
|
6643
6683
|
args: [{ providedIn: 'root' }]
|
|
6644
6684
|
}] });
|
|
6645
|
-
const AXPEntityListViewModelResolver = async (route, state, service = inject(AXPEntityListViewModelFactory)) => {
|
|
6685
|
+
const AXPEntityListViewModelResolver = async (route, state, service = inject(AXPEntityListViewModelFactory), router = inject(Router)) => {
|
|
6646
6686
|
const moduleName = route.parent?.paramMap.get('module');
|
|
6647
6687
|
const entityName = route.paramMap.get('entity');
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6688
|
+
try {
|
|
6689
|
+
const vm = await service.create(moduleName, entityName);
|
|
6690
|
+
// Check if filters are provided in query params
|
|
6691
|
+
const filtersParam = route.queryParamMap.get('filters');
|
|
6692
|
+
if (filtersParam) {
|
|
6693
|
+
const applied = vm.applyFiltersFromQueryParams(filtersParam);
|
|
6694
|
+
if (applied) {
|
|
6695
|
+
// Trigger filter and sort application
|
|
6696
|
+
await vm.applyFilterAndSort();
|
|
6697
|
+
}
|
|
6656
6698
|
}
|
|
6699
|
+
return vm;
|
|
6700
|
+
}
|
|
6701
|
+
catch (error) {
|
|
6702
|
+
if (error instanceof AXPNotFoundError) {
|
|
6703
|
+
return axpRedirectToNotFound(router);
|
|
6704
|
+
}
|
|
6705
|
+
throw error;
|
|
6657
6706
|
}
|
|
6658
|
-
return vm;
|
|
6659
6707
|
};
|
|
6660
6708
|
|
|
6661
6709
|
const AXPEntityDeletedEvent = createWorkFlowEvent('[Entity] Deleted');
|
|
@@ -6706,7 +6754,7 @@ class AXPEntityPerformDeleteAction extends AXPWorkflowAction {
|
|
|
6706
6754
|
dialog = this.loadingDialog.show({
|
|
6707
6755
|
title: await this.translationService.translateAsync('@general:workflow.deleting'),
|
|
6708
6756
|
mode: 'determinate',
|
|
6709
|
-
status: '
|
|
6757
|
+
status: await this.translationService.translateAsync('@general:workflow.deleting'),
|
|
6710
6758
|
progressValue: 0,
|
|
6711
6759
|
text: `0/${idLength}`,
|
|
6712
6760
|
buttons: [
|
|
@@ -7467,10 +7515,19 @@ class AXPEntityPreloadFiltersViewModel {
|
|
|
7467
7515
|
const AXPEntityPreloadFiltersViewModelResolver = async (route, state) => {
|
|
7468
7516
|
const injector = inject(Injector);
|
|
7469
7517
|
const entityRegistry = inject(AXPEntityDefinitionRegistryService);
|
|
7518
|
+
const router = inject(Router);
|
|
7470
7519
|
const moduleName = route.parent?.paramMap.get('module');
|
|
7471
7520
|
const entityName = route.paramMap.get('entity');
|
|
7472
|
-
|
|
7473
|
-
|
|
7521
|
+
try {
|
|
7522
|
+
const entity = await entityRegistry.resolve(moduleName, entityName);
|
|
7523
|
+
return new AXPEntityPreloadFiltersViewModel(injector, entity);
|
|
7524
|
+
}
|
|
7525
|
+
catch (error) {
|
|
7526
|
+
if (error instanceof AXPNotFoundError) {
|
|
7527
|
+
return axpRedirectToNotFound(router);
|
|
7528
|
+
}
|
|
7529
|
+
throw error;
|
|
7530
|
+
}
|
|
7474
7531
|
};
|
|
7475
7532
|
//#endregion
|
|
7476
7533
|
|
|
@@ -7835,8 +7892,6 @@ async function runEntityQuery(entityName, request, adapters) {
|
|
|
7835
7892
|
}
|
|
7836
7893
|
//#endregion
|
|
7837
7894
|
|
|
7838
|
-
//#endregion
|
|
7839
|
-
|
|
7840
7895
|
/** Component key used when display is 'page'. Register a page component with this key via AXP_PAGE_COMPONENT_PROVIDER. */
|
|
7841
7896
|
const ATTACHMENTS_PAGE_COMPONENT_KEY = 'entity-attachments-page';
|
|
7842
7897
|
/** Default section order for attachments when display is 'section' (after meta-data-form). */
|
|
@@ -8035,7 +8090,7 @@ class AXMAttachmentsPageComponentProvider {
|
|
|
8035
8090
|
return [
|
|
8036
8091
|
{
|
|
8037
8092
|
key: ATTACHMENTS_PAGE_COMPONENT_KEY,
|
|
8038
|
-
loader: () => import('./acorex-platform-layout-entity-attachments-page.component-
|
|
8093
|
+
loader: () => import('./acorex-platform-layout-entity-attachments-page.component-B0EkdqvH.mjs').then((m) => m.AXMAttachmentsPageComponent),
|
|
8039
8094
|
},
|
|
8040
8095
|
];
|
|
8041
8096
|
}
|
|
@@ -8354,7 +8409,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8354
8409
|
this.noRecordsTitle = signal('', ...(ngDevMode ? [{ debugName: "noRecordsTitle" }] : /* istanbul ignore next */ []));
|
|
8355
8410
|
this.currentSearchTerm = null;
|
|
8356
8411
|
this.isRefreshing = false;
|
|
8357
|
-
this.isUpdatingSelection = false; // Flag to prevent recursive updates during batch operations
|
|
8412
|
+
this.isUpdatingSelection = false; // Flag to prevent recursive updates during batch operations (multiple mode)
|
|
8358
8413
|
/**
|
|
8359
8414
|
* Computed property to check if we should show the "no search results" empty state.
|
|
8360
8415
|
* Returns true when search is active, not searching, and no results found.
|
|
@@ -8421,9 +8476,8 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8421
8476
|
}
|
|
8422
8477
|
});
|
|
8423
8478
|
}
|
|
8424
|
-
// Mark pre-selected nodes
|
|
8425
|
-
|
|
8426
|
-
if (!this.isUpdatingSelection) {
|
|
8479
|
+
// Mark pre-selected leaf nodes on loaded children (multiple mode only; single uses controlledSelection)
|
|
8480
|
+
if (!this.isUpdatingSelection && this.allowMultiple()) {
|
|
8427
8481
|
const selectedIds = this.selectedNodeIds();
|
|
8428
8482
|
childNodes.forEach((node) => {
|
|
8429
8483
|
const nodeId = String(node['id'] ?? '');
|
|
@@ -8431,38 +8485,6 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8431
8485
|
node['selected'] = true;
|
|
8432
8486
|
}
|
|
8433
8487
|
});
|
|
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
8488
|
}
|
|
8467
8489
|
return childNodes;
|
|
8468
8490
|
};
|
|
@@ -8488,6 +8510,60 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8488
8510
|
}
|
|
8489
8511
|
//#endregion
|
|
8490
8512
|
//#region ---- Private Methods ----
|
|
8513
|
+
/** Keeps at most one id when {@link allowMultiple} is false. */
|
|
8514
|
+
normalizeSelectedIds(ids) {
|
|
8515
|
+
const filtered = ids.filter((id) => id && id !== 'all');
|
|
8516
|
+
if (this.allowMultiple()) {
|
|
8517
|
+
return [...filtered];
|
|
8518
|
+
}
|
|
8519
|
+
return filtered.length > 0 ? [filtered[filtered.length - 1]] : [];
|
|
8520
|
+
}
|
|
8521
|
+
setSelectedNodeIds(ids) {
|
|
8522
|
+
this.selectedNodeIds.set(this.normalizeSelectedIds(ids));
|
|
8523
|
+
}
|
|
8524
|
+
/** Keeps widget selectedNodeIds in sync when the tree uses controlled single selection. */
|
|
8525
|
+
onControlledSelectedIdsChange(ids) {
|
|
8526
|
+
if (this.allowMultiple()) {
|
|
8527
|
+
return;
|
|
8528
|
+
}
|
|
8529
|
+
this.setSelectedNodeIds(ids);
|
|
8530
|
+
}
|
|
8531
|
+
async waitForTreeComponent(maxWaitMs = 3500) {
|
|
8532
|
+
const deadline = Date.now() + maxWaitMs;
|
|
8533
|
+
while (Date.now() < deadline) {
|
|
8534
|
+
const treeComponent = this.tree();
|
|
8535
|
+
if (treeComponent) {
|
|
8536
|
+
return treeComponent;
|
|
8537
|
+
}
|
|
8538
|
+
await new Promise((resolve) => setTimeout(resolve, 80));
|
|
8539
|
+
}
|
|
8540
|
+
return undefined;
|
|
8541
|
+
}
|
|
8542
|
+
/** Expands ancestor paths and reveals the initial selection via the tree API. */
|
|
8543
|
+
async revealInitialSelection(ids) {
|
|
8544
|
+
const normalizedIds = this.normalizeSelectedIds(ids);
|
|
8545
|
+
if (normalizedIds.length === 0) {
|
|
8546
|
+
return;
|
|
8547
|
+
}
|
|
8548
|
+
const treeComponent = await this.waitForTreeComponent();
|
|
8549
|
+
if (!treeComponent) {
|
|
8550
|
+
return;
|
|
8551
|
+
}
|
|
8552
|
+
try {
|
|
8553
|
+
if (this.allowMultiple()) {
|
|
8554
|
+
await this.restoreMultipleSelectionAfterReload(normalizedIds);
|
|
8555
|
+
}
|
|
8556
|
+
else {
|
|
8557
|
+
const chains = await this.buildAncestorChains(normalizedIds);
|
|
8558
|
+
const ancestorPaths = normalizedIds.map((id) => chains.get(id) ?? []);
|
|
8559
|
+
await treeComponent.selectAndReveal(normalizedIds, { ancestorPaths });
|
|
8560
|
+
}
|
|
8561
|
+
}
|
|
8562
|
+
catch (error) {
|
|
8563
|
+
console.error('Error revealing initial category selection:', error);
|
|
8564
|
+
}
|
|
8565
|
+
this.changeDetectorRef.markForCheck();
|
|
8566
|
+
}
|
|
8491
8567
|
async initializeTree() {
|
|
8492
8568
|
if (!this.entityKey()) {
|
|
8493
8569
|
this.loading.set(false);
|
|
@@ -8512,12 +8588,12 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8512
8588
|
// Resolve initial selected IDs from data (popup) or input binding
|
|
8513
8589
|
const fromData = this.selectedValues().filter((id) => id && id !== 'all');
|
|
8514
8590
|
const fromInput = (this.selectedValuesInput() ?? []).filter((id) => id && id !== 'all');
|
|
8515
|
-
const initialSelectedIds = fromData.length > 0 ? fromData : fromInput;
|
|
8591
|
+
const initialSelectedIds = this.normalizeSelectedIds(fromData.length > 0 ? fromData : fromInput);
|
|
8516
8592
|
if (initialSelectedIds.length > 0) {
|
|
8517
8593
|
await this.loadMissingNodeData(initialSelectedIds);
|
|
8518
8594
|
// Re-fetch any node that has no parent info (batch query may return minimal fields)
|
|
8519
8595
|
await this.ensureParentDataInCache(initialSelectedIds);
|
|
8520
|
-
this.
|
|
8596
|
+
this.setSelectedNodeIds(initialSelectedIds);
|
|
8521
8597
|
}
|
|
8522
8598
|
}
|
|
8523
8599
|
catch (error) {
|
|
@@ -8531,52 +8607,20 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8531
8607
|
const selectedIds = this.selectedNodeIds();
|
|
8532
8608
|
if (selectedIds.length > 0) {
|
|
8533
8609
|
this.initialExpandSyncDone = true;
|
|
8534
|
-
this.
|
|
8610
|
+
void this.revealInitialSelection(selectedIds);
|
|
8535
8611
|
}
|
|
8536
8612
|
}
|
|
8537
8613
|
/**
|
|
8538
8614
|
* Called when popup data arrives after ngOnInit: load data, set selection, expand and sync.
|
|
8539
8615
|
*/
|
|
8540
8616
|
runInitialExpandAndSync(ids) {
|
|
8541
|
-
this.
|
|
8617
|
+
this.setSelectedNodeIds(ids);
|
|
8542
8618
|
Promise.resolve()
|
|
8543
8619
|
.then(() => this.loadMissingNodeData(ids))
|
|
8544
8620
|
.then(() => this.ensureParentDataInCache(ids))
|
|
8545
|
-
.then(() =>
|
|
8546
|
-
this.runExpandAndSyncWhenTreeReady(ids);
|
|
8547
|
-
})
|
|
8621
|
+
.then(() => this.revealInitialSelection(ids))
|
|
8548
8622
|
.catch((err) => console.error('Error in runInitialExpandAndSync:', err));
|
|
8549
8623
|
}
|
|
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
8624
|
//#endregion
|
|
8581
8625
|
//#region ---- Public Methods ----
|
|
8582
8626
|
/**
|
|
@@ -8981,8 +9025,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
8981
9025
|
this.nodesExpandedDuringSearch = [];
|
|
8982
9026
|
return;
|
|
8983
9027
|
}
|
|
8984
|
-
|
|
8985
|
-
const selectedIds = this.selectedNodeIds();
|
|
9028
|
+
const expandTargetIds = [...this.selectedNodeIds()];
|
|
8986
9029
|
// Reload tree to show all nodes (no filtering)
|
|
8987
9030
|
await treeComponent.reloadData();
|
|
8988
9031
|
// Collapse nodes that were expanded during search (in reverse order - leaves first)
|
|
@@ -9002,39 +9045,38 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9002
9045
|
// Clear the stored expanded nodes
|
|
9003
9046
|
this.expandedNodesBeforeSearch = [];
|
|
9004
9047
|
// Restore selection state after tree reload
|
|
9005
|
-
if (
|
|
9006
|
-
|
|
9007
|
-
|
|
9008
|
-
|
|
9009
|
-
|
|
9048
|
+
if (expandTargetIds.length > 0) {
|
|
9049
|
+
if (!this.allowMultiple()) {
|
|
9050
|
+
await this.revealInitialSelection(expandTargetIds);
|
|
9051
|
+
}
|
|
9052
|
+
else {
|
|
9053
|
+
await this.restoreMultipleSelectionAfterReload(expandTargetIds);
|
|
9054
|
+
}
|
|
9010
9055
|
}
|
|
9011
9056
|
}
|
|
9012
9057
|
/**
|
|
9013
|
-
* Restores selection
|
|
9014
|
-
* Expands ancestor nodes and selects the previously selected leaf nodes.
|
|
9058
|
+
* Restores multiple-mode leaf selection after search reset.
|
|
9015
9059
|
*/
|
|
9016
|
-
async
|
|
9060
|
+
async restoreMultipleSelectionAfterReload(selectedLeafIds) {
|
|
9017
9061
|
const treeComponent = this.tree();
|
|
9018
|
-
|
|
9062
|
+
const normalizedIds = this.normalizeSelectedIds(selectedLeafIds);
|
|
9063
|
+
if (!treeComponent || normalizedIds.length === 0) {
|
|
9019
9064
|
return;
|
|
9020
9065
|
}
|
|
9021
9066
|
this.isUpdatingSelection = true;
|
|
9022
9067
|
try {
|
|
9023
|
-
|
|
9024
|
-
const ancestorChains = await this.buildAncestorChains(selectedIds);
|
|
9025
|
-
// Expand ancestor nodes to make selected nodes visible
|
|
9068
|
+
const ancestorChains = await this.buildAncestorChains(normalizedIds);
|
|
9026
9069
|
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) {
|
|
9070
|
+
for (const id of normalizedIds) {
|
|
9031
9071
|
try {
|
|
9032
9072
|
treeComponent.selectNode(id);
|
|
9033
9073
|
}
|
|
9034
9074
|
catch {
|
|
9035
|
-
// Node might not be
|
|
9075
|
+
// Node might not be loaded yet
|
|
9036
9076
|
}
|
|
9037
9077
|
}
|
|
9078
|
+
await this.updateParentStatesAfterSelection(normalizedIds);
|
|
9079
|
+
treeComponent.refresh();
|
|
9038
9080
|
}
|
|
9039
9081
|
finally {
|
|
9040
9082
|
this.isUpdatingSelection = false;
|
|
@@ -9051,10 +9093,6 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9051
9093
|
if (!event.isUserInteraction) {
|
|
9052
9094
|
return;
|
|
9053
9095
|
}
|
|
9054
|
-
// Don't process if we're already updating selection
|
|
9055
|
-
if (this.isUpdatingSelection) {
|
|
9056
|
-
return;
|
|
9057
|
-
}
|
|
9058
9096
|
// Cache node data for getSelectedItems (except for 'all' node)
|
|
9059
9097
|
if (nodeId !== 'all') {
|
|
9060
9098
|
const nodeData = node['data'];
|
|
@@ -9062,72 +9100,64 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9062
9100
|
this.nodeDataCache.set(nodeId, nodeData);
|
|
9063
9101
|
}
|
|
9064
9102
|
}
|
|
9065
|
-
//
|
|
9103
|
+
// Single selection is handled by the tree controlledSelection + selectedIds binding.
|
|
9104
|
+
if (!this.allowMultiple()) {
|
|
9105
|
+
return;
|
|
9106
|
+
}
|
|
9066
9107
|
const isSelected = node['selected'] === true;
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
|
|
9078
|
-
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
|
|
9084
|
-
|
|
9085
|
-
|
|
9108
|
+
const children = node['children'];
|
|
9109
|
+
const childrenCount = node['childrenCount'];
|
|
9110
|
+
// Determine if this node has children (is a parent node)
|
|
9111
|
+
// A node has children if: childrenCount > 0, or has non-empty children array
|
|
9112
|
+
// Note: childrenCount === undefined means "unknown" - we need to check via datasource
|
|
9113
|
+
const hasLoadedChildren = children && children.length > 0;
|
|
9114
|
+
const hasChildrenCount = childrenCount !== undefined && childrenCount > 0;
|
|
9115
|
+
const isDefinitelyLeaf = childrenCount === 0 && (!children || children.length === 0);
|
|
9116
|
+
if (isSelected) {
|
|
9117
|
+
// SELECTION: Only add LEAF nodes to selectedNodeIds
|
|
9118
|
+
this.isUpdatingSelection = true;
|
|
9119
|
+
try {
|
|
9120
|
+
if (nodeId === 'all') {
|
|
9121
|
+
// "All Items" selected - recursively select all leaf descendants
|
|
9122
|
+
await this.selectAllLeafDescendants(nodeId);
|
|
9123
|
+
}
|
|
9124
|
+
else if (isDefinitelyLeaf) {
|
|
9125
|
+
// This is definitely a leaf node - add it directly
|
|
9126
|
+
const currentSelected = new Set(this.selectedNodeIds());
|
|
9127
|
+
currentSelected.add(nodeId);
|
|
9128
|
+
this.setSelectedNodeIds(Array.from(currentSelected));
|
|
9129
|
+
}
|
|
9130
|
+
else if (hasLoadedChildren || hasChildrenCount) {
|
|
9131
|
+
// This node has children - only add its leaf descendants
|
|
9132
|
+
await this.selectAllLeafDescendants(nodeId);
|
|
9133
|
+
}
|
|
9134
|
+
else {
|
|
9135
|
+
// childrenCount is undefined - fetch once and reuse to avoid double datasource call
|
|
9136
|
+
const childNodes = await this.datasource(nodeId);
|
|
9137
|
+
if (!childNodes || childNodes.length === 0) {
|
|
9138
|
+
// No children - this is a leaf node, add it
|
|
9086
9139
|
const currentSelected = new Set(this.selectedNodeIds());
|
|
9087
9140
|
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);
|
|
9141
|
+
this.setSelectedNodeIds(Array.from(currentSelected));
|
|
9093
9142
|
}
|
|
9094
9143
|
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
|
-
}
|
|
9144
|
+
// Has children - pass prefetched childNodes to avoid datasource(nodeId) again
|
|
9145
|
+
await this.selectAllLeafDescendants(nodeId, childNodes);
|
|
9107
9146
|
}
|
|
9108
9147
|
}
|
|
9109
|
-
finally {
|
|
9110
|
-
this.isUpdatingSelection = false;
|
|
9111
|
-
}
|
|
9112
9148
|
}
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
this.isUpdatingSelection = true;
|
|
9116
|
-
try {
|
|
9117
|
-
await this.deselectAllLeafDescendants(nodeId);
|
|
9118
|
-
}
|
|
9119
|
-
finally {
|
|
9120
|
-
this.isUpdatingSelection = false;
|
|
9121
|
-
}
|
|
9149
|
+
finally {
|
|
9150
|
+
this.isUpdatingSelection = false;
|
|
9122
9151
|
}
|
|
9123
9152
|
}
|
|
9124
9153
|
else {
|
|
9125
|
-
//
|
|
9126
|
-
|
|
9127
|
-
|
|
9154
|
+
// DESELECTION: Remove node (if leaf) and all leaf descendants from selectedNodeIds
|
|
9155
|
+
this.isUpdatingSelection = true;
|
|
9156
|
+
try {
|
|
9157
|
+
await this.deselectAllLeafDescendants(nodeId);
|
|
9128
9158
|
}
|
|
9129
|
-
|
|
9130
|
-
this.
|
|
9159
|
+
finally {
|
|
9160
|
+
this.isUpdatingSelection = false;
|
|
9131
9161
|
}
|
|
9132
9162
|
}
|
|
9133
9163
|
}
|
|
@@ -9143,7 +9173,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9143
9173
|
* Clears all selected items
|
|
9144
9174
|
*/
|
|
9145
9175
|
onClearAll() {
|
|
9146
|
-
this.
|
|
9176
|
+
this.setSelectedNodeIds([]);
|
|
9147
9177
|
const treeComponent = this.tree();
|
|
9148
9178
|
if (treeComponent) {
|
|
9149
9179
|
treeComponent.deselectAll();
|
|
@@ -9194,7 +9224,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9194
9224
|
for (const leafId of leafIds) {
|
|
9195
9225
|
currentSelected.add(leafId);
|
|
9196
9226
|
}
|
|
9197
|
-
this.
|
|
9227
|
+
this.setSelectedNodeIds(Array.from(currentSelected));
|
|
9198
9228
|
// Select all leaf nodes visually in the tree
|
|
9199
9229
|
if (treeComponent) {
|
|
9200
9230
|
for (const leafId of leafIds) {
|
|
@@ -9223,7 +9253,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9223
9253
|
try {
|
|
9224
9254
|
// Special case: deselecting 'all' clears everything
|
|
9225
9255
|
if (parentId === 'all') {
|
|
9226
|
-
this.
|
|
9256
|
+
this.setSelectedNodeIds([]);
|
|
9227
9257
|
// Use tree's deselectAll() to clear all visual selections
|
|
9228
9258
|
const treeComponent = this.tree();
|
|
9229
9259
|
if (treeComponent) {
|
|
@@ -9244,7 +9274,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9244
9274
|
// Only update our internal state - tree handles visual state
|
|
9245
9275
|
const currentSelected = this.selectedNodeIds();
|
|
9246
9276
|
const newSelected = currentSelected.filter((id) => !leafIds.has(id));
|
|
9247
|
-
this.
|
|
9277
|
+
this.setSelectedNodeIds(newSelected);
|
|
9248
9278
|
}
|
|
9249
9279
|
catch (error) {
|
|
9250
9280
|
console.error(`Error deselecting leaf descendants for node ${parentId}:`, error);
|
|
@@ -9494,60 +9524,6 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9494
9524
|
await new Promise((r) => setTimeout(r, pollMs));
|
|
9495
9525
|
}
|
|
9496
9526
|
}
|
|
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
9527
|
/**
|
|
9552
9528
|
* Updates parent node states (selected/indeterminate) based on children selection.
|
|
9553
9529
|
* Called after leaf nodes are selected to properly show parent states.
|
|
@@ -9741,35 +9717,6 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9741
9717
|
const id = String(parentIdValue);
|
|
9742
9718
|
return id && id !== 'all' ? id : null;
|
|
9743
9719
|
}
|
|
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
9720
|
/**
|
|
9774
9721
|
* Marks a node and its children as disabled if the node ID matches the excluded ID.
|
|
9775
9722
|
*/
|
|
@@ -9778,7 +9725,6 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9778
9725
|
if (nodeId === excludedId) {
|
|
9779
9726
|
node['disabled'] = true;
|
|
9780
9727
|
}
|
|
9781
|
-
// Recursively mark children
|
|
9782
9728
|
const nodeChildren = node['children'];
|
|
9783
9729
|
if (nodeChildren) {
|
|
9784
9730
|
nodeChildren.forEach((child) => {
|
|
@@ -9787,41 +9733,16 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9787
9733
|
}
|
|
9788
9734
|
}
|
|
9789
9735
|
/**
|
|
9790
|
-
* Processes root node: marks excluded as disabled
|
|
9736
|
+
* Processes root node: marks excluded nodes as disabled.
|
|
9791
9737
|
*/
|
|
9792
9738
|
processRootNode(rootNode) {
|
|
9793
9739
|
const excludedId = this.excludedNodeId();
|
|
9794
9740
|
if (excludedId) {
|
|
9795
9741
|
this.markNodeAsDisabled(rootNode, excludedId);
|
|
9796
9742
|
}
|
|
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
9743
|
}
|
|
9822
9744
|
/**
|
|
9823
9745
|
* Processes child nodes: marks excluded as disabled
|
|
9824
|
-
* Selection marking is handled in datasource callback ONLY during initial load
|
|
9825
9746
|
*/
|
|
9826
9747
|
processChildNodes(childNodes) {
|
|
9827
9748
|
const excludedId = this.excludedNodeId();
|
|
@@ -9967,8 +9888,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
9967
9888
|
return this.translationService.resolve(raw);
|
|
9968
9889
|
}
|
|
9969
9890
|
async getSelectedItems() {
|
|
9970
|
-
|
|
9971
|
-
const selectedIds = this.selectedNodeIds();
|
|
9891
|
+
const selectedIds = this.normalizeSelectedIds(this.selectedNodeIds());
|
|
9972
9892
|
if (selectedIds.length === 0) {
|
|
9973
9893
|
return [];
|
|
9974
9894
|
}
|
|
@@ -10061,6 +9981,9 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
10061
9981
|
[dragBehavior]="'none'"
|
|
10062
9982
|
[selectMode]="allowMultiple() ? 'multiple' : 'single'"
|
|
10063
9983
|
[selectionBehavior]="allowMultiple() ? 'intermediate-nested' : 'all'"
|
|
9984
|
+
[controlledSelection]="!allowMultiple()"
|
|
9985
|
+
[selectedIds]="selectedNodeIds()"
|
|
9986
|
+
(selectedIdsChange)="onControlledSelectedIdsChange($event)"
|
|
10064
9987
|
[showIcons]="true"
|
|
10065
9988
|
[titleField]="textField()"
|
|
10066
9989
|
[idField]="valueField()"
|
|
@@ -10147,7 +10070,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
10147
10070
|
></ax-button>
|
|
10148
10071
|
</ax-suffix>
|
|
10149
10072
|
</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 }); }
|
|
10073
|
+
`, 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
10074
|
}
|
|
10152
10075
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityCategoryTreeSelectorComponent, decorators: [{
|
|
10153
10076
|
type: Component,
|
|
@@ -10198,6 +10121,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
10198
10121
|
[dragBehavior]="'none'"
|
|
10199
10122
|
[selectMode]="allowMultiple() ? 'multiple' : 'single'"
|
|
10200
10123
|
[selectionBehavior]="allowMultiple() ? 'intermediate-nested' : 'all'"
|
|
10124
|
+
[controlledSelection]="!allowMultiple()"
|
|
10125
|
+
[selectedIds]="selectedNodeIds()"
|
|
10126
|
+
(selectedIdsChange)="onControlledSelectedIdsChange($event)"
|
|
10201
10127
|
[showIcons]="true"
|
|
10202
10128
|
[titleField]="textField()"
|
|
10203
10129
|
[idField]="valueField()"
|
|
@@ -11307,9 +11233,7 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
11307
11233
|
this.isOpen.set(true);
|
|
11308
11234
|
const currentValue = this.getValue();
|
|
11309
11235
|
const selectedIds = currentValue
|
|
11310
|
-
?
|
|
11311
|
-
.map((v) => String(extractValue(v, this.valueField())))
|
|
11312
|
-
.filter((id) => id && id !== 'all')
|
|
11236
|
+
? this.normalizePopupSelectedIds(currentValue)
|
|
11313
11237
|
: [];
|
|
11314
11238
|
// Get current entity ID from context (if editing an entity)
|
|
11315
11239
|
const currentEntityId = this.contextService.getValue('id');
|
|
@@ -11330,9 +11254,7 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
11330
11254
|
},
|
|
11331
11255
|
});
|
|
11332
11256
|
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;
|
|
11257
|
+
const newItems = this.multiple() ? result.data.selected : result.data.selected.slice(0, 1);
|
|
11336
11258
|
if (newItems.length === 0) {
|
|
11337
11259
|
// All items were deselected
|
|
11338
11260
|
this.clear();
|
|
@@ -11482,10 +11404,10 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
11482
11404
|
}
|
|
11483
11405
|
});
|
|
11484
11406
|
this.contextService.applyObjectPaths(itemToExpose, { origin: 'user' });
|
|
11485
|
-
this.
|
|
11407
|
+
this.setValue(this.singleOrMultiple(keys));
|
|
11486
11408
|
}
|
|
11487
11409
|
else {
|
|
11488
|
-
this.
|
|
11410
|
+
this.setValue(this.singleOrMultiple(keys));
|
|
11489
11411
|
}
|
|
11490
11412
|
// Trigger change detection
|
|
11491
11413
|
this.cdr.markForCheck();
|
|
@@ -11500,6 +11422,12 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
11500
11422
|
singleOrMultiple(values) {
|
|
11501
11423
|
return this.multiple() ? values : values[0];
|
|
11502
11424
|
}
|
|
11425
|
+
normalizePopupSelectedIds(currentValue) {
|
|
11426
|
+
const ids = (this.multiple() ? castArray(currentValue) : castArray(currentValue).slice(0, 1))
|
|
11427
|
+
.map((v) => String(extractValue(v, this.valueField())))
|
|
11428
|
+
.filter((id) => id && id !== 'all');
|
|
11429
|
+
return this.multiple() ? ids : ids.slice(0, 1);
|
|
11430
|
+
}
|
|
11503
11431
|
getItemLabel(item) {
|
|
11504
11432
|
if (!item) {
|
|
11505
11433
|
return '';
|
|
@@ -12777,11 +12705,10 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
12777
12705
|
}
|
|
12778
12706
|
untracked(() => void this.applyRelatedFiltersFromContextAndDatasource(specs));
|
|
12779
12707
|
}, ...(ngDevMode ? [{ debugName: "#relatedFilterSyncEffect" }] : /* istanbul ignore next */ []));
|
|
12780
|
-
/** Patches data-list `refresh` so
|
|
12708
|
+
/** Patches data-list `refresh` so reload keeps parent-scoped toolbar filters on the data source. */
|
|
12781
12709
|
this.#patchDataListRefreshEffect = effect(() => {
|
|
12782
12710
|
const inst = this.listWidget()?.instance;
|
|
12783
|
-
|
|
12784
|
-
if (!inst?.refresh || inst.__axpEntityListRefreshPatched || !opts['syncRelatedListFiltersFromDialogContext']) {
|
|
12711
|
+
if (!inst?.refresh || inst.__axpEntityListRefreshPatched) {
|
|
12785
12712
|
return;
|
|
12786
12713
|
}
|
|
12787
12714
|
inst.__axpEntityListRefreshPatched = true;
|
|
@@ -12793,6 +12720,9 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
12793
12720
|
if (o['syncRelatedListFiltersFromDialogContext'] && specs?.length) {
|
|
12794
12721
|
await this.applyRelatedFiltersFromContextAndDatasource(specs);
|
|
12795
12722
|
}
|
|
12723
|
+
else {
|
|
12724
|
+
await this.reapplyScopedFiltersToDataSource();
|
|
12725
|
+
}
|
|
12796
12726
|
originalRefresh();
|
|
12797
12727
|
})();
|
|
12798
12728
|
};
|
|
@@ -13013,6 +12943,10 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13013
12943
|
* Applies merged route + parent-scope filters to the widget value and data source.
|
|
13014
12944
|
*/
|
|
13015
12945
|
applyMergedRouteFiltersToList() {
|
|
12946
|
+
void this.reapplyScopedFiltersToDataSource();
|
|
12947
|
+
}
|
|
12948
|
+
/** Syncs toolbar filters to context and AXDataSource (retries until data-list is mounted). */
|
|
12949
|
+
async reapplyScopedFiltersToDataSource() {
|
|
13016
12950
|
const merged = this.getMergedToolbarFilters();
|
|
13017
12951
|
const current = this.getValue();
|
|
13018
12952
|
if (!isEqual$1(current?.toolbar?.filters, merged)) {
|
|
@@ -13021,7 +12955,26 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13021
12955
|
toolbar: { ...(current?.toolbar ?? {}), filters: merged },
|
|
13022
12956
|
});
|
|
13023
12957
|
}
|
|
12958
|
+
const pushed = await this.ensureToolbarFiltersOnDataSource();
|
|
12959
|
+
if (pushed) {
|
|
12960
|
+
this.triggerInitialLoadIfNeeded();
|
|
12961
|
+
}
|
|
12962
|
+
}
|
|
12963
|
+
/**
|
|
12964
|
+
* Entity lists use `fetchDataMode: 'manual'`; after scoped filters reach the data source,
|
|
12965
|
+
* the grid must be refreshed once (initial #effect may run before the data-list is ready).
|
|
12966
|
+
*/
|
|
12967
|
+
triggerInitialLoadIfNeeded() {
|
|
12968
|
+
if (this.isMounted()) {
|
|
12969
|
+
return;
|
|
12970
|
+
}
|
|
12971
|
+
const listInstance = this.listWidget()?.instance;
|
|
12972
|
+
if (!listInstance?.call) {
|
|
12973
|
+
return;
|
|
12974
|
+
}
|
|
13024
12975
|
this.pushToolbarFiltersToDataSource();
|
|
12976
|
+
listInstance.call('refresh');
|
|
12977
|
+
this.isMounted.set(true);
|
|
13025
12978
|
}
|
|
13026
12979
|
/**
|
|
13027
12980
|
* Re-evaluates related-entity list filters from the live dialog form context (e.g. after create saves the main row id).
|
|
@@ -13068,26 +13021,29 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13068
13021
|
return true;
|
|
13069
13022
|
}
|
|
13070
13023
|
/**
|
|
13071
|
-
*
|
|
13024
|
+
* Pushes toolbar filters once the embedded data-list exposes its data source
|
|
13025
|
+
* (listNode is created via deferred setTimeout in ngOnInit).
|
|
13072
13026
|
*/
|
|
13073
|
-
async
|
|
13074
|
-
await this.applyRelatedFiltersFromContext(specs);
|
|
13027
|
+
async ensureToolbarFiltersOnDataSource() {
|
|
13075
13028
|
if (this.pushToolbarFiltersToDataSource()) {
|
|
13076
|
-
return;
|
|
13077
|
-
}
|
|
13078
|
-
const opts = this.options();
|
|
13079
|
-
if (!opts['syncRelatedListFiltersFromDialogContext']) {
|
|
13080
|
-
return;
|
|
13029
|
+
return true;
|
|
13081
13030
|
}
|
|
13082
|
-
/** Data-list is created in ngOnInit via deferred listNode.set; retry briefly until instance exposes dataSource. */
|
|
13083
13031
|
const maxAttempts = 40;
|
|
13084
13032
|
const delayMs = 50;
|
|
13085
13033
|
for (let i = 0; i < maxAttempts; i++) {
|
|
13086
13034
|
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
13087
13035
|
if (this.pushToolbarFiltersToDataSource()) {
|
|
13088
|
-
return;
|
|
13036
|
+
return true;
|
|
13089
13037
|
}
|
|
13090
13038
|
}
|
|
13039
|
+
return false;
|
|
13040
|
+
}
|
|
13041
|
+
/**
|
|
13042
|
+
* Writes toolbar filters from specs and pushes them onto the data source so refresh/reload keeps the parent scope.
|
|
13043
|
+
*/
|
|
13044
|
+
async applyRelatedFiltersFromContextAndDatasource(specs) {
|
|
13045
|
+
await this.applyRelatedFiltersFromContext(specs);
|
|
13046
|
+
await this.ensureToolbarFiltersOnDataSource();
|
|
13091
13047
|
}
|
|
13092
13048
|
/**
|
|
13093
13049
|
* Refreshes the embedded data list (toolbar / workflow). In wizard mode, `refresh` is patched to re-apply scoped filters first.
|
|
@@ -13095,7 +13051,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13095
13051
|
refreshGridWithParentScopedFilters() {
|
|
13096
13052
|
this.listWidget()?.instance?.call('refresh');
|
|
13097
13053
|
}
|
|
13098
|
-
/** Patches data-list `refresh` so
|
|
13054
|
+
/** Patches data-list `refresh` so reload keeps parent-scoped toolbar filters on the data source. */
|
|
13099
13055
|
#patchDataListRefreshEffect;
|
|
13100
13056
|
#effect;
|
|
13101
13057
|
/**
|
|
@@ -13110,7 +13066,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13110
13066
|
handleQueryChanges(queries, dataSource, listInstance, isMounted) {
|
|
13111
13067
|
const changeTracker = this.analyzeChanges(queries);
|
|
13112
13068
|
this.previousQueries = queries;
|
|
13113
|
-
this.applyDataSourceChanges(dataSource, queries, changeTracker);
|
|
13069
|
+
this.applyDataSourceChanges(dataSource, queries, changeTracker, isMounted);
|
|
13114
13070
|
this.handleListRefresh(listInstance, changeTracker, isMounted);
|
|
13115
13071
|
this.handleColumnChanges(changeTracker);
|
|
13116
13072
|
}
|
|
@@ -13137,8 +13093,9 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13137
13093
|
/**
|
|
13138
13094
|
* Applies filter and sort changes to the data source
|
|
13139
13095
|
*/
|
|
13140
|
-
applyDataSourceChanges(dataSource, queries, changeTracker) {
|
|
13141
|
-
|
|
13096
|
+
applyDataSourceChanges(dataSource, queries, changeTracker, isMounted) {
|
|
13097
|
+
const shouldApplyFilters = changeTracker.isFilterChanged || (!isMounted && (queries?.filters?.length ?? 0) > 0);
|
|
13098
|
+
if (shouldApplyFilters) {
|
|
13142
13099
|
dataSource.filter({
|
|
13143
13100
|
filters: queries?.filters,
|
|
13144
13101
|
});
|
|
@@ -13149,16 +13106,16 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13149
13106
|
}
|
|
13150
13107
|
}
|
|
13151
13108
|
/**
|
|
13152
|
-
* Handles list refresh logic based on changes and mount status
|
|
13109
|
+
* Handles list refresh logic based on changes and mount status.
|
|
13110
|
+
* Initial fetch is owned by {@link triggerInitialLoadIfNeeded} (manual fetchDataMode).
|
|
13153
13111
|
*/
|
|
13154
13112
|
handleListRefresh(listInstance, changeTracker, isMounted) {
|
|
13155
|
-
|
|
13156
|
-
|
|
13113
|
+
if (!isMounted) {
|
|
13114
|
+
return;
|
|
13115
|
+
}
|
|
13116
|
+
if (changeTracker.isFilterChanged || changeTracker.isSortChanged) {
|
|
13117
|
+
this.pushToolbarFiltersToDataSource();
|
|
13157
13118
|
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
13119
|
}
|
|
13163
13120
|
}
|
|
13164
13121
|
/**
|
|
@@ -15597,8 +15554,8 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15597
15554
|
this.setLoading = (loading) => {
|
|
15598
15555
|
this.isLoading.set(loading);
|
|
15599
15556
|
};
|
|
15600
|
-
|
|
15601
|
-
|
|
15557
|
+
/** @param syncContext When false, only updates UI (hydration/revert); skips context writes. */
|
|
15558
|
+
this.setItems = (items, syncContext = true) => {
|
|
15602
15559
|
// Ensure items is always an array
|
|
15603
15560
|
items = castArray(items);
|
|
15604
15561
|
// Filter out null/undefined items
|
|
@@ -15614,13 +15571,13 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15614
15571
|
return item;
|
|
15615
15572
|
});
|
|
15616
15573
|
this.selectedItems.set(items);
|
|
15617
|
-
|
|
15574
|
+
if (!syncContext) {
|
|
15575
|
+
return;
|
|
15576
|
+
}
|
|
15618
15577
|
const keys = items.map((item) => get(item, this.valueField()));
|
|
15619
15578
|
const text = items.map((item) => this.mlsResolver.resolve(get(item, displayField)));
|
|
15620
|
-
//
|
|
15621
|
-
// extract data from valueField and set context by expose path
|
|
15622
15579
|
if (this.expose()) {
|
|
15623
|
-
this.expoesItems(
|
|
15580
|
+
this.expoesItems();
|
|
15624
15581
|
}
|
|
15625
15582
|
const newValue = this.singleOrMultiple(keys);
|
|
15626
15583
|
if (this.filterMode()) {
|
|
@@ -15630,10 +15587,10 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15630
15587
|
operation: {
|
|
15631
15588
|
type: this.multiple() ? 'in' : 'equal',
|
|
15632
15589
|
},
|
|
15633
|
-
}
|
|
15590
|
+
});
|
|
15634
15591
|
}
|
|
15635
15592
|
else {
|
|
15636
|
-
this.setValue(newValue
|
|
15593
|
+
this.setValue(newValue);
|
|
15637
15594
|
}
|
|
15638
15595
|
};
|
|
15639
15596
|
}
|
|
@@ -15647,7 +15604,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15647
15604
|
? castArray(this.filterMode() ? rawValue.value : rawValue)
|
|
15648
15605
|
: [rawValue].filter((v) => v != null);
|
|
15649
15606
|
if (!values.length) {
|
|
15650
|
-
this.setItems([]);
|
|
15607
|
+
this.setItems([], false);
|
|
15651
15608
|
this.isLoading.set(false);
|
|
15652
15609
|
return;
|
|
15653
15610
|
}
|
|
@@ -15662,22 +15619,22 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15662
15619
|
.map((id) => entityDataAccessor.byKey(id)));
|
|
15663
15620
|
// Filter out null/undefined results
|
|
15664
15621
|
const validItems = items.filter((item) => item != null);
|
|
15665
|
-
this.setItems(validItems);
|
|
15622
|
+
this.setItems(validItems, false);
|
|
15666
15623
|
}
|
|
15667
15624
|
else {
|
|
15668
15625
|
const id = extractValue(this.filterMode() ? values[0].value : values[0], this.valueField());
|
|
15669
15626
|
if (id != null) {
|
|
15670
15627
|
const item = await entityDataAccessor.byKey(id);
|
|
15671
|
-
this.setItems(item != null ? [item] : []);
|
|
15628
|
+
this.setItems(item != null ? [item] : [], false);
|
|
15672
15629
|
}
|
|
15673
15630
|
else {
|
|
15674
|
-
this.setItems([]);
|
|
15631
|
+
this.setItems([], false);
|
|
15675
15632
|
}
|
|
15676
15633
|
}
|
|
15677
15634
|
}
|
|
15678
15635
|
catch (error) {
|
|
15679
15636
|
console.error('[LookupWidget] findByValue() error:', error);
|
|
15680
|
-
this.setItems([]);
|
|
15637
|
+
this.setItems([], false);
|
|
15681
15638
|
}
|
|
15682
15639
|
finally {
|
|
15683
15640
|
this.isLoading.set(false);
|
|
@@ -15685,7 +15642,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15685
15642
|
}
|
|
15686
15643
|
//#region ---- Event Handlers from Dumb Components ----
|
|
15687
15644
|
handleComponentValueChanged(items) {
|
|
15688
|
-
this.setItems(items ?? []
|
|
15645
|
+
this.setItems(items ?? []);
|
|
15689
15646
|
}
|
|
15690
15647
|
async handleCreateClick(_e) {
|
|
15691
15648
|
const entity = this.entityDef();
|
|
@@ -15710,10 +15667,10 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15710
15667
|
if (this.multiple()) {
|
|
15711
15668
|
const exists = currentItems.some((item) => get(item, valueField) === newId);
|
|
15712
15669
|
const newItems = exists ? currentItems : [...currentItems, createdItem];
|
|
15713
|
-
this.setItems(newItems
|
|
15670
|
+
this.setItems(newItems);
|
|
15714
15671
|
}
|
|
15715
15672
|
else {
|
|
15716
|
-
this.setItems([createdItem]
|
|
15673
|
+
this.setItems([createdItem]);
|
|
15717
15674
|
}
|
|
15718
15675
|
}
|
|
15719
15676
|
}
|
|
@@ -15730,7 +15687,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15730
15687
|
* so e.g. `{ person: { educationLevel: { id, title } } }` would replace the entire `person`
|
|
15731
15688
|
* object and drop sibling fields like `person.educationLevelId`, causing a value/effect loop.
|
|
15732
15689
|
*/
|
|
15733
|
-
expoesItems(
|
|
15690
|
+
expoesItems() {
|
|
15734
15691
|
const exposeValue = castArray(this.expose());
|
|
15735
15692
|
const items = this.selectedItems();
|
|
15736
15693
|
const isEmpty = !items || items.length === 0;
|
|
@@ -15743,7 +15700,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15743
15700
|
parentPaths.add(pathParts.slice(0, -1).join('.'));
|
|
15744
15701
|
}
|
|
15745
15702
|
else {
|
|
15746
|
-
this.contextService.update(i, null
|
|
15703
|
+
this.contextService.update(i, null);
|
|
15747
15704
|
}
|
|
15748
15705
|
}
|
|
15749
15706
|
else {
|
|
@@ -15752,25 +15709,25 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
15752
15709
|
parentPaths.add(pathParts.slice(0, -1).join('.'));
|
|
15753
15710
|
}
|
|
15754
15711
|
else {
|
|
15755
|
-
this.contextService.update(i.target, null
|
|
15712
|
+
this.contextService.update(i.target, null);
|
|
15756
15713
|
}
|
|
15757
15714
|
}
|
|
15758
15715
|
});
|
|
15759
15716
|
parentPaths.forEach((parentPath) => {
|
|
15760
|
-
this.contextService.update(parentPath, null
|
|
15717
|
+
this.contextService.update(parentPath, null);
|
|
15761
15718
|
});
|
|
15762
15719
|
return;
|
|
15763
15720
|
}
|
|
15764
15721
|
exposeValue.forEach((i) => {
|
|
15765
15722
|
if (typeof i === 'string') {
|
|
15766
15723
|
const values = items.map((item) => set({}, i, get(item, i)));
|
|
15767
|
-
this.contextService.update(i, this.singleOrMultiple(values)
|
|
15724
|
+
this.contextService.update(i, this.singleOrMultiple(values));
|
|
15768
15725
|
}
|
|
15769
15726
|
else {
|
|
15770
15727
|
const values = this.multiple()
|
|
15771
15728
|
? items.map((item) => set({}, i.source, get(item, i.source)))
|
|
15772
15729
|
: items.map((item) => get(item, i.source));
|
|
15773
|
-
this.contextService.update(i.target, this.singleOrMultiple(values)
|
|
15730
|
+
this.contextService.update(i.target, this.singleOrMultiple(values));
|
|
15774
15731
|
}
|
|
15775
15732
|
});
|
|
15776
15733
|
}
|
|
@@ -16185,7 +16142,7 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
16185
16142
|
if (!resolvedTitle) {
|
|
16186
16143
|
const displayTitle = formatLookupItemDisplay(headerItem, this.entityDef(), this.lookupDisplayOptions(), this.formatService, (value) => this.translation.resolve(value));
|
|
16187
16144
|
resolvedTitle = typeof displayTitle === 'string' ? displayTitle : this.translation.resolve(displayTitle);
|
|
16188
|
-
if (
|
|
16145
|
+
if (isUnresolvedEntityDisplayTemplate(resolvedTitle)) {
|
|
16189
16146
|
resolvedTitle = '';
|
|
16190
16147
|
}
|
|
16191
16148
|
}
|
|
@@ -19105,32 +19062,10 @@ function hasFileUploaderTitleOrDescriptionFields(editDialog) {
|
|
|
19105
19062
|
}
|
|
19106
19063
|
//#endregion
|
|
19107
19064
|
|
|
19108
|
-
//#region ----
|
|
19065
|
+
//#region ---- Imports ----
|
|
19109
19066
|
//#endregion
|
|
19110
|
-
//#region ----
|
|
19067
|
+
//#region ---- Title template resolution ----
|
|
19111
19068
|
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
19069
|
/** Resolves a row field or format result to a plain display string for the active locale. */
|
|
19135
19070
|
function resolveEntityRowDisplayText(value, activeLang) {
|
|
19136
19071
|
if (value == null || value === '') {
|
|
@@ -19138,7 +19073,7 @@ function resolveEntityRowDisplayText(value, activeLang) {
|
|
|
19138
19073
|
}
|
|
19139
19074
|
if (typeof value === 'string') {
|
|
19140
19075
|
const text = value.trim();
|
|
19141
|
-
if (!text || text === INVALID_DISPLAY_TEXT ||
|
|
19076
|
+
if (!text || text === INVALID_DISPLAY_TEXT || isUnresolvedEntityDisplayTemplate(text)) {
|
|
19142
19077
|
return '';
|
|
19143
19078
|
}
|
|
19144
19079
|
return text;
|
|
@@ -19156,21 +19091,25 @@ function resolveEntityRowDisplayText(value, activeLang) {
|
|
|
19156
19091
|
return '';
|
|
19157
19092
|
}
|
|
19158
19093
|
/**
|
|
19159
|
-
* Formats the entity row title for display using
|
|
19094
|
+
* Formats the entity row title for display using entity-driven templates and property paths.
|
|
19160
19095
|
*/
|
|
19161
19096
|
function formatEntityRowDisplayTitle(entity, rowData, formatService, activeLang) {
|
|
19162
19097
|
if (!rowData) {
|
|
19163
19098
|
return '';
|
|
19164
19099
|
}
|
|
19165
|
-
|
|
19166
|
-
|
|
19100
|
+
const titleContext = buildEntitySearchTitleContext(entity ?? {});
|
|
19101
|
+
for (const path of titleContext.fallbackFields) {
|
|
19102
|
+
const fromField = resolveEntityRowDisplayText(get(rowData, path), activeLang);
|
|
19167
19103
|
if (fromField) {
|
|
19168
19104
|
return fromField;
|
|
19169
19105
|
}
|
|
19170
19106
|
}
|
|
19171
|
-
const
|
|
19172
|
-
|
|
19173
|
-
|
|
19107
|
+
const templates = [
|
|
19108
|
+
resolveEntityRowTitleTemplate(entity),
|
|
19109
|
+
...titleContext.fallbackTemplates,
|
|
19110
|
+
].filter((template) => !!template?.trim());
|
|
19111
|
+
for (const template of templates) {
|
|
19112
|
+
const formatted = formatService.format(normalizeEntityDisplayTemplate(template), 'string', rowData);
|
|
19174
19113
|
const fromTemplate = resolveEntityRowDisplayText(formatted, activeLang);
|
|
19175
19114
|
if (fromTemplate) {
|
|
19176
19115
|
return fromTemplate;
|
|
@@ -21522,7 +21461,7 @@ class AXPLayoutAdapterBuilder {
|
|
|
21522
21461
|
load: this.createLoadFunction(),
|
|
21523
21462
|
pages: this.adapter.pages || [],
|
|
21524
21463
|
exitUrl: this.adapter.exitUrl,
|
|
21525
|
-
|
|
21464
|
+
getPageBadge: (context, isDirty) => this.badgeStatusService.getPageBadge(name, context, isDirty),
|
|
21526
21465
|
getPageStatus: (context, currentPage) => this.badgeStatusService.getPageStatus(name, context, currentPage),
|
|
21527
21466
|
};
|
|
21528
21467
|
}
|
|
@@ -22210,6 +22149,8 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
|
|
|
22210
22149
|
title: context.rootTitle ?? '',
|
|
22211
22150
|
label: relatedEntity.title,
|
|
22212
22151
|
icon: relatedEntity.icon || entityDef.icon,
|
|
22152
|
+
/** List-only page: scoped filters are system state, not user edits. */
|
|
22153
|
+
isReadonly: true,
|
|
22213
22154
|
actions: this.mergeActions(entityDef, actions)
|
|
22214
22155
|
?.filter((a) => a.priority === 'primary' && !a.isChild)
|
|
22215
22156
|
?.map((a) => {
|
|
@@ -22892,6 +22833,7 @@ class AXPMainEntityContentBuilder {
|
|
|
22892
22833
|
icon: 'fa-light fa-rotate-left',
|
|
22893
22834
|
color: 'default',
|
|
22894
22835
|
visible: '{{context.isDirty()}}',
|
|
22836
|
+
shortcuts: ['escape'],
|
|
22895
22837
|
command: {
|
|
22896
22838
|
name: 'discard',
|
|
22897
22839
|
},
|
|
@@ -22901,6 +22843,7 @@ class AXPMainEntityContentBuilder {
|
|
|
22901
22843
|
icon: 'fa-light fa-floppy-disk',
|
|
22902
22844
|
color: 'primary',
|
|
22903
22845
|
visible: '{{context.isDirty()}}',
|
|
22846
|
+
shortcuts: ['ctrl+s'],
|
|
22904
22847
|
command: {
|
|
22905
22848
|
name: 'update-entity',
|
|
22906
22849
|
},
|
|
@@ -23194,6 +23137,7 @@ class AXPMainEntityContentBuilder {
|
|
|
23194
23137
|
icon: action.icon,
|
|
23195
23138
|
color: action.color,
|
|
23196
23139
|
disabled: disabled || false,
|
|
23140
|
+
shortcuts: action.shortcuts,
|
|
23197
23141
|
zone: 'header',
|
|
23198
23142
|
priority: action.priority,
|
|
23199
23143
|
scope: action.scope === AXPEntityCommandScope.Individual ? AXPEntityCommandScope.TypeLevel : action.scope,
|
|
@@ -23256,17 +23200,25 @@ class AXPLayoutAdapterFactory {
|
|
|
23256
23200
|
async createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies) {
|
|
23257
23201
|
const entity = await entityResolver.resolve(moduleName, entityName);
|
|
23258
23202
|
if (!entity) {
|
|
23259
|
-
throw new
|
|
23203
|
+
throw new AXPNotFoundError(`Entity ${moduleName}.${entityName} not found`);
|
|
23260
23204
|
}
|
|
23261
23205
|
const rootContext = await this.loadRootContext(entity, id);
|
|
23262
|
-
|
|
23263
|
-
|
|
23264
|
-
|
|
23265
|
-
|
|
23266
|
-
const
|
|
23267
|
-
const
|
|
23206
|
+
if (axpIsEntityRecordNotFound(rootContext)) {
|
|
23207
|
+
throw new AXPNotFoundError(`Entity record ${moduleName}.${entityName}#${id} not found`);
|
|
23208
|
+
}
|
|
23209
|
+
// Evaluate hidden expressions for related entities and component pages once, reuse across building and composing
|
|
23210
|
+
const evaluatedRelatedEntities = await this.evaluateHiddenFlags(entity?.relatedEntities ?? [], rootContext, dependencies);
|
|
23211
|
+
const evaluatedPages = await this.evaluateHiddenFlags(entity?.pages ?? [], rootContext, dependencies);
|
|
23212
|
+
// Build main and related pages using evaluated related entities and pages
|
|
23213
|
+
const entityWithEvaluatedLayout = {
|
|
23214
|
+
...entity,
|
|
23215
|
+
relatedEntities: evaluatedRelatedEntities,
|
|
23216
|
+
pages: evaluatedPages,
|
|
23217
|
+
};
|
|
23218
|
+
const mainPage = await this.buildMainPage(entityWithEvaluatedLayout, rootContext, id, dependencies);
|
|
23219
|
+
const relatedPages = await this.buildRelatedPages(entityWithEvaluatedLayout, rootContext, dependencies);
|
|
23268
23220
|
// Compose ordered pages around the primary page
|
|
23269
|
-
const orderedPages = this.composePagesWithPositions(mainPage, relatedPages,
|
|
23221
|
+
const orderedPages = this.composePagesWithPositions(mainPage, relatedPages, entityWithEvaluatedLayout);
|
|
23270
23222
|
const applicationName = dependencies.session.application?.name ?? 'default';
|
|
23271
23223
|
const rootTitle = await this.getRootTitle(entity, rootContext, dependencies);
|
|
23272
23224
|
return this.layoutAdapterBuilder
|
|
@@ -23285,15 +23237,15 @@ class AXPLayoutAdapterFactory {
|
|
|
23285
23237
|
return this.mainEntityContentBuilder.build(entity, rootContext, { ...dependencies, reloadRootContext: () => this.loadRootContext(entity, id) }, await this.getRootTitle(entity, rootContext, dependencies));
|
|
23286
23238
|
}
|
|
23287
23239
|
/**
|
|
23288
|
-
* Evaluates the 'hidden' expression for
|
|
23289
|
-
* Returns a new array
|
|
23240
|
+
* Evaluates the 'hidden' expression for layout items using the expression evaluator.
|
|
23241
|
+
* Returns a new array with evaluated hidden values.
|
|
23290
23242
|
*/
|
|
23291
|
-
async
|
|
23292
|
-
if (!
|
|
23293
|
-
return
|
|
23243
|
+
async evaluateHiddenFlags(items, rootContext, dependencies) {
|
|
23244
|
+
if (!items?.length || !dependencies?.expressionEvaluator) {
|
|
23245
|
+
return items ?? [];
|
|
23294
23246
|
}
|
|
23295
|
-
return Promise.all(
|
|
23296
|
-
let hidden =
|
|
23247
|
+
return Promise.all(items.map(async (item) => {
|
|
23248
|
+
let hidden = item.hidden;
|
|
23297
23249
|
if (hidden && typeof hidden === 'string') {
|
|
23298
23250
|
try {
|
|
23299
23251
|
const scope = {
|
|
@@ -23308,9 +23260,12 @@ class AXPLayoutAdapterFactory {
|
|
|
23308
23260
|
// Keep original hidden value if evaluation fails
|
|
23309
23261
|
}
|
|
23310
23262
|
}
|
|
23311
|
-
return { ...
|
|
23263
|
+
return { ...item, hidden };
|
|
23312
23264
|
}));
|
|
23313
23265
|
}
|
|
23266
|
+
async evaluateRelatedEntitiesHidden(relatedEntities, rootContext, dependencies) {
|
|
23267
|
+
return this.evaluateHiddenFlags(relatedEntities, rootContext, dependencies);
|
|
23268
|
+
}
|
|
23314
23269
|
async buildRelatedPages(entity, rootContext, dependencies) {
|
|
23315
23270
|
const pages = [];
|
|
23316
23271
|
const rootTitle = await this.getRootTitle(entity, rootContext, dependencies);
|
|
@@ -23475,7 +23430,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
23475
23430
|
}]
|
|
23476
23431
|
}], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }, { type: AXPMainEntityContentBuilder }, { type: AXPLayoutAdapterBuilder }, { type: i4$3.AXPFilterOperatorMiddlewareService }] });
|
|
23477
23432
|
|
|
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)) => {
|
|
23433
|
+
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
23434
|
const moduleName = route.parent?.paramMap.get('module');
|
|
23480
23435
|
const entityName = route.paramMap.get('entity');
|
|
23481
23436
|
const id = route.paramMap.get('id');
|
|
@@ -23487,8 +23442,15 @@ const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver =
|
|
|
23487
23442
|
workflowService,
|
|
23488
23443
|
commandService,
|
|
23489
23444
|
};
|
|
23490
|
-
|
|
23491
|
-
|
|
23445
|
+
try {
|
|
23446
|
+
return await layoutAdapterFactory.createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies);
|
|
23447
|
+
}
|
|
23448
|
+
catch (error) {
|
|
23449
|
+
if (error instanceof AXPNotFoundError) {
|
|
23450
|
+
return axpRedirectToNotFound(router);
|
|
23451
|
+
}
|
|
23452
|
+
throw error;
|
|
23453
|
+
}
|
|
23492
23454
|
};
|
|
23493
23455
|
|
|
23494
23456
|
class AXPEntityPreloadFilterGuard {
|
|
@@ -24262,7 +24224,7 @@ const AXPCrudModifier = {
|
|
|
24262
24224
|
queries.list = {
|
|
24263
24225
|
execute: async (e) => {
|
|
24264
24226
|
const res = await dataService.query(e);
|
|
24265
|
-
console.log('query', res, ctx.module.get() + '.' + ctx.name.get(), e);
|
|
24227
|
+
// console.log('query', res, ctx.module.get() + '.' + ctx.name.get(), e);
|
|
24266
24228
|
return res;
|
|
24267
24229
|
},
|
|
24268
24230
|
type: AXPEntityQueryType.List,
|
|
@@ -24305,6 +24267,8 @@ class AXPEntitySearchDefinitionProvider {
|
|
|
24305
24267
|
this.entityRegister.getAll().forEach((entity) => {
|
|
24306
24268
|
const manifest = this.manifestRegistry.get(entity.module);
|
|
24307
24269
|
const i18nScope = manifest?.i18n ?? moduleNameToI18nScope(entity.module);
|
|
24270
|
+
const searchTitleTemplate = entity.formats.searchResult?.title;
|
|
24271
|
+
const titleContext = buildEntitySearchTitleContext(entity, searchTitleTemplate);
|
|
24308
24272
|
context.addDefinition(`Module.${entity.module}.${entity.name}`, `@${i18nScope}:module.title`, `Module.${entity.module}`, entity.icon ?? 'fa-solid fa-objects-column', 4, {
|
|
24309
24273
|
actions: [
|
|
24310
24274
|
{
|
|
@@ -24314,9 +24278,11 @@ class AXPEntitySearchDefinitionProvider {
|
|
|
24314
24278
|
},
|
|
24315
24279
|
],
|
|
24316
24280
|
format: {
|
|
24317
|
-
title:
|
|
24281
|
+
title: searchTitleTemplate,
|
|
24318
24282
|
description: (entity.formats.searchResult?.description) ?? `${entity.module} / ${entity.title}`,
|
|
24319
24283
|
id: '{{data.id}}',
|
|
24284
|
+
titleFallbackTemplates: titleContext.fallbackTemplates,
|
|
24285
|
+
titleFallbackFields: titleContext.fallbackFields,
|
|
24320
24286
|
},
|
|
24321
24287
|
});
|
|
24322
24288
|
});
|
|
@@ -25000,7 +24966,7 @@ function routesFacory() {
|
|
|
25000
24966
|
loadComponent: () => {
|
|
25001
24967
|
return config.viewers.root();
|
|
25002
24968
|
},
|
|
25003
|
-
canActivate: [
|
|
24969
|
+
canActivate: [...AXP_PROTECTED_ROUTE_GUARDS],
|
|
25004
24970
|
children: [
|
|
25005
24971
|
{
|
|
25006
24972
|
path: ':module',
|
|
@@ -25038,6 +25004,7 @@ function routesFacory() {
|
|
|
25038
25004
|
loadComponent: () => {
|
|
25039
25005
|
return config.viewers.master.details();
|
|
25040
25006
|
},
|
|
25007
|
+
canDeactivate: [axpDetailsViewCanDeactivateGuard],
|
|
25041
25008
|
runGuardsAndResolvers: (from, to) => {
|
|
25042
25009
|
const entityChanged = from.params['module'] !== to.params['module'] || from.params['entity'] !== to.params['entity'];
|
|
25043
25010
|
const idChanged = from.params['id'] !== to.params['id'];
|
|
@@ -25056,8 +25023,16 @@ function routesFacory() {
|
|
|
25056
25023
|
redirectTo: ':entity/list',
|
|
25057
25024
|
pathMatch: 'full',
|
|
25058
25025
|
},
|
|
25026
|
+
{
|
|
25027
|
+
path: '**',
|
|
25028
|
+
redirectTo: AXP_NOT_FOUND_ROUTE,
|
|
25029
|
+
},
|
|
25059
25030
|
],
|
|
25060
25031
|
},
|
|
25032
|
+
{
|
|
25033
|
+
path: '**',
|
|
25034
|
+
redirectTo: AXP_NOT_FOUND_ROUTE,
|
|
25035
|
+
},
|
|
25061
25036
|
],
|
|
25062
25037
|
},
|
|
25063
25038
|
];
|
|
@@ -25376,38 +25351,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
25376
25351
|
}]
|
|
25377
25352
|
}] });
|
|
25378
25353
|
|
|
25379
|
-
/** Entity query filter field for {@link AXPRecordWorkflowInfo.instanceId}. */
|
|
25380
|
-
const AXP_RECORD_WORKFLOW_INFO_INSTANCE_ID_FIELD = 'workflowInfo.instanceId';
|
|
25381
|
-
/** Entity query filter field for {@link AXPRecordWorkflowInfo.correlationId}. */
|
|
25382
|
-
const AXP_RECORD_WORKFLOW_INFO_CORRELATION_ID_FIELD = 'workflowInfo.correlationId';
|
|
25383
|
-
/** Entity query filter field for {@link AXPRecordWorkflowInfo.definitionId}. */
|
|
25384
|
-
const AXP_RECORD_WORKFLOW_INFO_DEFINITION_ID_FIELD = 'workflowInfo.definitionId';
|
|
25385
|
-
/** Returns a trimmed workflow instance id from a record, if present. */
|
|
25386
|
-
function getRecordWorkflowInstanceId(record) {
|
|
25387
|
-
const id = record?.workflowInfo?.instanceId?.trim();
|
|
25388
|
-
return id && id.length > 0 ? id : null;
|
|
25389
|
-
}
|
|
25390
|
-
/** Returns a trimmed workflow correlation id from a record, if present. */
|
|
25391
|
-
function getRecordWorkflowCorrelationId(record) {
|
|
25392
|
-
const id = record?.workflowInfo?.correlationId?.trim();
|
|
25393
|
-
return id && id.length > 0 ? id : null;
|
|
25394
|
-
}
|
|
25395
|
-
/** Builds canonical workflow metadata for a domain record (engine / middleware). */
|
|
25396
|
-
function buildAXPRecordWorkflowInfo(params) {
|
|
25397
|
-
const instanceId = params.instanceId?.trim();
|
|
25398
|
-
if (!instanceId) {
|
|
25399
|
-
return {};
|
|
25400
|
-
}
|
|
25401
|
-
const definitionId = params.definitionId?.trim();
|
|
25402
|
-
const correlationId = params.correlationId?.trim();
|
|
25403
|
-
return {
|
|
25404
|
-
instanceId,
|
|
25405
|
-
...(definitionId ? { definitionId } : { definitionId: null }),
|
|
25406
|
-
...(correlationId ? { correlationId } : { correlationId: null }),
|
|
25407
|
-
...(params.pinnedVersion != null ? { pinnedVersion: params.pinnedVersion } : {}),
|
|
25408
|
-
};
|
|
25409
|
-
}
|
|
25410
|
-
|
|
25411
25354
|
/**
|
|
25412
25355
|
* Registers entity CRUD commands and queries for the given entity keys.
|
|
25413
25356
|
* Use in app/module providers; consumes AXPEntityService from this package.
|
|
@@ -25539,7 +25482,7 @@ class AXPGetEntityDetailsQuery {
|
|
|
25539
25482
|
constructor() {
|
|
25540
25483
|
//#region ---- Services & Dependencies ----
|
|
25541
25484
|
this.entityDefinitionRegistry = inject(AXPEntityDefinitionRegistryService);
|
|
25542
|
-
this.
|
|
25485
|
+
this.entityService = inject(AXPEntityService);
|
|
25543
25486
|
}
|
|
25544
25487
|
//#region ---- Query Execution ----
|
|
25545
25488
|
/**
|
|
@@ -25585,10 +25528,10 @@ class AXPGetEntityDetailsQuery {
|
|
|
25585
25528
|
* @returns Promise resolving to entity data
|
|
25586
25529
|
*/
|
|
25587
25530
|
async getEntityData(entity, id) {
|
|
25588
|
-
const dataService =
|
|
25531
|
+
const dataService = this.entityService.withEntity(entity).data();
|
|
25589
25532
|
try {
|
|
25590
25533
|
// Fetch the entity data
|
|
25591
|
-
return await dataService.
|
|
25534
|
+
return await dataService.byKey(id);
|
|
25592
25535
|
}
|
|
25593
25536
|
catch (error) {
|
|
25594
25537
|
throw new Error(`Failed to fetch entity data: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
@@ -25611,5 +25554,5 @@ var getEntityDetails_query = /*#__PURE__*/Object.freeze({
|
|
|
25611
25554
|
* Generated bundle index. Do not edit.
|
|
25612
25555
|
*/
|
|
25613
25556
|
|
|
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,
|
|
25557
|
+
export { ATTACHMENTS_PAGE_COMPONENT_KEY, AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCategoryTreeService, AXPCreateEntityCommand, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEditFileUploaderCommand, AXPEntitiesListDataSourceDefinition, AXPEntityApplyUpdatesAction, AXPEntityCategoryTreeSelectorComponent, AXPEntityCategoryWidget, AXPEntityCategoryWidgetColumnComponent, AXPEntityCategoryWidgetEditComponent, AXPEntityCategoryWidgetViewComponent, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDataSelectorRowActionsService, AXPEntityDataSelectorService, AXPEntityDataSourceKeys, AXPEntityDefinitionProviderWidget, AXPEntityDefinitionProviderWidgetEditComponent, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailPopoverComponent, AXPEntityDetailPopoverService, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityEventsKeys, AXPEntityFormBuilderService, AXPEntityListPersistenceModeDefault, AXPEntityListTableService, AXPEntityListToolbarService, AXPEntityListViewCardFieldViewModel, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityListWidget, AXPEntityListWidgetViewComponent, AXPEntityMasterCreateViewModel, AXPEntityMasterListCardSelectActionName, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityPreloadFiltersContainerComponent, AXPEntityPreloadFiltersViewModel, AXPEntityPreloadFiltersViewModelResolver, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPEntityUpdateViewSectionViewModel, AXPFileListComponent, AXPFileUploaderLoadFilesQuery, AXPFileUploaderSaveFilesCommand, AXPFileUploaderWidget, AXPFileUploaderWidgetColumnComponent, AXPFileUploaderWidgetEditComponent, AXPFileUploaderWidgetService, AXPFileUploaderWidgetViewComponent, AXPGetEntityDetailsQuery, AXPLayoutOrderingConfigService, AXPLookupWidget, AXPLookupWidgetColumnComponent, AXPLookupWidgetEditComponent, AXPLookupWidgetViewComponent, AXPMiddlewareAbortError, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPMultiSourceDefinitionProviderContext, AXPMultiSourceDefinitionProviderService, AXPMultiSourceFederatedSearchService, AXPMultiSourceSelectorComponent, AXPMultiSourceSelectorService, AXPMultiSourceSelectorWidget, AXPMultiSourceSelectorWidgetColumnComponent, AXPMultiSourceSelectorWidgetEditComponent, AXPMultiSourceSelectorWidgetViewComponent, AXPMultiSourceType, AXPOpenEntityDetailsCommand, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPRelatedColumnEnrichmentService, AXPRelatedColumnMetadataResolver, AXPSelectorStructureWidget, AXPSelectorStructureWidgetColumnComponent, AXPSelectorStructureWidgetEditComponent, AXPSelectorStructureWidgetViewComponent, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXPTruncatedBreadcrumbComponent, AXPUpdateEntityCommand, AXPViewEntityDetailsCommand, AXP_CATEGORY_TREE_ROOT_TITLE_I18N_KEY, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, AXP_MULTI_SOURCE_DEFINITION_PROVIDER, AXP_RECORD_WORKFLOW_INFO_CORRELATION_ID_FIELD, AXP_RECORD_WORKFLOW_INFO_DEFINITION_ID_FIELD, AXP_RECORD_WORKFLOW_INFO_INSTANCE_ID_FIELD, DEFAULT_COLUMN_ORDER, DEFAULT_PAIR_SPAN_RULES, DEFAULT_PROPERTY_ORDER, DEFAULT_SECTION_ORDER, ENTITY_LIST_ROUTE_CONTEXT_SESSION_KEY, EntityBuilder, EntityDataAccessor, actionExists, applyDataSourcePagingWithoutLoad, attachmentFieldCount, attachmentsPlugin, attachmentsSemanticallyEqual, axpCreateEntityAiToolInputDefaults, axpCreateEntityCommandDefinition, buildAXPRecordWorkflowInfo, canPersistEntityListState, cloneLayoutArrays, collectEntityQuickSearchFieldPaths, collectNestedCreateHiddenProperties, collectNestedFieldPathsFromEntityColumns, collectQuickSearchPathsFromSingleEntityDefinition, columnOrderingMiddleware, columnOrderingMiddlewareProvider, columnWidthMiddleware, columnWidthMiddlewareProvider, commandMessageTextForError, committedAttachments, computeEntityAggregates, createColumnOrderingMiddlewareProvider, createLayoutOrderingMiddlewareProvider, createModifierContext, defaultCardLayoutMiddleware, defaultCardLayoutMiddlewareProvider, defaultMultiLanguageMiddleware, defaultMultiLanguageMiddlewareProvider, detectEntityChanges, ensureLayoutPropertyView, ensureLayoutSection, ensureListActions, entityDetailsCreateActions, entityDetailsCreateActionsDeferredParent, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsNewEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterEditAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware, filterSortEntityRows, findEntityListRowDataInTree, fingerprintAttachmentItem, fingerprintAttachments, formatLookupItemDisplay, getDataSourcePageIndex, getEntityListRowId, getMasterInterfacePropertySortKey, getRecordWorkflowCorrelationId, getRecordWorkflowInstanceId, hasFileUploaderTitleOrDescriptionFields, isAXPMiddlewareAbortError, isAttachmentListEntry, isCategoryEntity, isCategoryFilter, isFileListItem, isFileUploaderEditDialogAuto, isLegacyEntityDataSelectorOptions, layoutOrderingMiddlewareFactory, layoutOrderingMiddlewareProvider, mapEntityStorageErrorToCommandResult, mapLegacyEntityDataSelectorOptions, mergeForeignKeyFieldIntoCreateActions, normalizeEntityDataSelectorOptions, normalizeEntityFieldToFileList, normalizeEntityListPersistenceMode, normalizeListPaging, persistedAttachments, provideEntity, resolveEntityPluginDetailPageOrder, resolveFileUploaderEditDialog, resolveFileUploaderEntityScope, resolveLookupDisplayField, resolveLookupDisplayTemplate, restoreEntityListExpandedRows, runEntityQuery, searchResultDescriptionMiddleware, searchResultDescriptionMiddlewareProvider, shouldLoadEntityListStateFromStorage, shouldResetEntityListStateOnRouteEntry };
|
|
25615
25558
|
//# sourceMappingURL=acorex-platform-layout-entity.mjs.map
|