@acorex/platform 21.0.0-next.39 → 21.0.0-next.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/acorex-platform-common.mjs +6 -2
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +8 -1
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-domain.mjs +3 -0
- package/fesm2022/acorex-platform-domain.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +22 -5
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +25 -13
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +203 -55
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +622 -121
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +169 -85
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs +643 -311
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-runtime.mjs +120 -9
- package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-default-entity-master-create-view.component-Cvvr4HnL.mjs → acorex-platform-themes-default-entity-master-create-view.component-Cx1lLUaR.mjs} +3 -3
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-Cx1lLUaR.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-entity-master-modify-view.component-TYoLN1Jq.mjs → acorex-platform-themes-default-entity-master-modify-view.component-AOrcgjDF.mjs} +3 -3
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-AOrcgjDF.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-C2z5Lq9y.mjs → acorex-platform-themes-default-entity-master-single-view.component-BfCeUU5F.mjs} +3 -3
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-BfCeUU5F.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +10 -10
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-shared-settings.provider-DSs1o1M6.mjs → acorex-platform-themes-shared-settings.provider-D13QB3Hr.mjs} +2 -2
- package/fesm2022/acorex-platform-themes-shared-settings.provider-D13QB3Hr.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-D566Kdvy.mjs +94 -0
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-D566Kdvy.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-shared-theme-color-chooser-view.component-BSmvnUVq.mjs → acorex-platform-themes-shared-theme-color-chooser-view.component-D7-rCGl7.mjs} +38 -16
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-D7-rCGl7.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared.mjs +183 -84
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/fesm2022/acorex-platform-workflow.mjs +50 -10
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/package.json +1 -1
- package/types/acorex-platform-core.d.ts +13 -2
- package/types/acorex-platform-domain.d.ts +28 -2
- package/types/acorex-platform-layout-builder.d.ts +41 -27
- package/types/acorex-platform-layout-designer.d.ts +55 -15
- package/types/acorex-platform-layout-entity.d.ts +145 -11
- package/types/acorex-platform-layout-widget-core.d.ts +81 -68
- package/types/acorex-platform-layout-widgets.d.ts +25 -5
- package/types/acorex-platform-runtime.d.ts +156 -61
- package/types/acorex-platform-workflow.d.ts +37 -2
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-Cvvr4HnL.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-TYoLN1Jq.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-C2z5Lq9y.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-settings.provider-DSs1o1M6.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-CHfrTtol.mjs +0 -65
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-CHfrTtol.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-BSmvnUVq.mjs.map +0 -1
|
@@ -4,14 +4,14 @@ import { AXTranslationService, AXTranslationModule, resolveMultiLanguageString }
|
|
|
4
4
|
import * as i4$4 from '@acorex/platform/common';
|
|
5
5
|
import { AXPSettingsService, AXPCommonSettings, AXPFilterOperatorMiddlewareService, AXPEntityCommandScope, getEntityInfo, AXPRefreshEvent, AXPReloadEvent, AXPCleanNestedFilters, AXPDefaultMultiLanguageConfigService, withDefaultMultiLanguageOnWidgetNodeTree, AXPEntityQueryType, AXPWorkflowNavigateAction, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER, AXPMenuItemsDataSourceDefinition } from '@acorex/platform/common';
|
|
6
6
|
import * as i0 from '@angular/core';
|
|
7
|
-
import { InjectionToken, inject, Injector, runInInjectionContext, Injectable, input, viewChild, signal, ElementRef, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent,
|
|
7
|
+
import { InjectionToken, inject, Injector, runInInjectionContext, Injectable, input, viewChild, signal, computed, ElementRef, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent, ChangeDetectorRef, effect, Input, afterNextRender, untracked, ViewEncapsulation, viewChildren, linkedSignal, HostBinding, output, NgModule, makeEnvironmentProviders } from '@angular/core';
|
|
8
8
|
import { Subject, takeUntil } from 'rxjs';
|
|
9
9
|
import { AXPLayoutBuilderService, LayoutBuilderModule } from '@acorex/platform/layout/builder';
|
|
10
|
-
import { AXPDeviceService, AXPBroadcastEventService, applyFilterArray, applySortArray, resolveActionLook, AXPExpressionEvaluatorService, AXPDistributedEventListenerService, AXPPlatformScope, AXHighlightService, extractValue, setSmart, getChangedPaths, AXPColumnWidthService, AXPModuleManifestRegistry, defaultColumnWidthProvider, AXP_COLUMN_WIDTH_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXPModuleManifestsDataSourceDefinition, AXPSystemActionType } from '@acorex/platform/core';
|
|
10
|
+
import { AXPDeviceService, AXPBroadcastEventService, applyFilterArray, applySortArray, resolveActionLook, AXPExpressionEvaluatorService, AXPDistributedEventListenerService, AXPPlatformScope, AXHighlightService, extractValue, setSmart, getChangedPaths, objectKeyValueTransforms, AXPColumnWidthService, AXPModuleManifestRegistry, defaultColumnWidthProvider, AXP_COLUMN_WIDTH_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXPModuleManifestsDataSourceDefinition, AXPSystemActionType } from '@acorex/platform/core';
|
|
11
11
|
import { merge, get, castArray, cloneDeep, set, orderBy, omit, isNil, isEmpty, isEqual } from 'lodash-es';
|
|
12
12
|
import { AXPSessionService, AXPAuthGuard, AXPPermissionDefinitionsDataSourceDefinition } from '@acorex/platform/auth';
|
|
13
13
|
import { Router, ActivatedRoute, RouterModule, ROUTES } from '@angular/router';
|
|
14
|
-
import { defineCommand, AXPCommandService, AXPQueryService, AXPQueryExecutor, provideCommandSetups, provideQuerySetups, AXPCommandRegistry, AXPQueryRegistry } from '@acorex/platform/runtime';
|
|
14
|
+
import { defineCommand, AXP_COMMAND_DEFINITION_CATEGORY_ENTITY, AXPCommandService, AXPQueryService, AXPQueryExecutor, provideCommandSetups, provideQuerySetups, AXPCommandRegistry, AXPQueryRegistry } from '@acorex/platform/runtime';
|
|
15
15
|
import * as i1 from '@acorex/components/button';
|
|
16
16
|
import { AXButtonModule } from '@acorex/components/button';
|
|
17
17
|
import * as i4 from '@acorex/components/loading';
|
|
@@ -119,6 +119,28 @@ const AXP_ENTITY_ACTION_PLUGIN = new InjectionToken('AXP_ENTITY_ACTION_PLUGIN');
|
|
|
119
119
|
function createModifierContext(entity) {
|
|
120
120
|
const ctx = {
|
|
121
121
|
entity,
|
|
122
|
+
plugins: {
|
|
123
|
+
list: () => entity.plugins ?? [],
|
|
124
|
+
add: (...items) => {
|
|
125
|
+
entity.plugins ??= [];
|
|
126
|
+
entity.plugins.push(...items);
|
|
127
|
+
return ctx;
|
|
128
|
+
},
|
|
129
|
+
remove: (predicate) => {
|
|
130
|
+
if (entity.plugins)
|
|
131
|
+
entity.plugins = entity.plugins.filter((p) => !predicate(p));
|
|
132
|
+
return ctx;
|
|
133
|
+
},
|
|
134
|
+
find: (name) => ({
|
|
135
|
+
get: () => entity.plugins?.find((p) => p.name === name),
|
|
136
|
+
update: (updater) => {
|
|
137
|
+
const index = entity.plugins?.findIndex((p) => p.name === name);
|
|
138
|
+
if (index !== undefined && index !== -1 && entity.plugins)
|
|
139
|
+
entity.plugins[index] = updater(entity.plugins[index]);
|
|
140
|
+
return ctx;
|
|
141
|
+
},
|
|
142
|
+
}),
|
|
143
|
+
},
|
|
122
144
|
title: {
|
|
123
145
|
get: () => entity.title,
|
|
124
146
|
set: (newTitle) => {
|
|
@@ -781,6 +803,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
781
803
|
}]
|
|
782
804
|
}] });
|
|
783
805
|
|
|
806
|
+
/**
|
|
807
|
+
* Maps entity property `description` (or any i18n key / multi-language payload) to `form-field`
|
|
808
|
+
* widget options. Returns `undefined` when there is nothing to show.
|
|
809
|
+
*/
|
|
810
|
+
function hintFormFieldOptionsFromDescription(description) {
|
|
811
|
+
if (description == null) {
|
|
812
|
+
return undefined;
|
|
813
|
+
}
|
|
814
|
+
if (typeof description === 'string' && description.trim() === '') {
|
|
815
|
+
return undefined;
|
|
816
|
+
}
|
|
817
|
+
return { hint: description, hintDisplayMode: 'icon' };
|
|
818
|
+
}
|
|
819
|
+
//#endregion
|
|
820
|
+
|
|
784
821
|
//#endregion
|
|
785
822
|
class AXPEntityFormBuilderService {
|
|
786
823
|
constructor() {
|
|
@@ -1190,6 +1227,17 @@ class PropertyFilter {
|
|
|
1190
1227
|
fs.setLook('fieldset');
|
|
1191
1228
|
fs.setTitle((getGroupTitleFromList(allGroups, groupId) || groupId));
|
|
1192
1229
|
fs.setCols(12);
|
|
1230
|
+
// Section label visibility (fieldset title/legend)
|
|
1231
|
+
// Prefer current interface (create/update/single) section layout, fallback to master.single section layout.
|
|
1232
|
+
const sectionLabelVisible = section?.layout?.label?.visible ??
|
|
1233
|
+
entity?.interfaces?.master?.single?.sections?.find((s) => s?.id === groupId)?.layout?.label
|
|
1234
|
+
?.visible;
|
|
1235
|
+
if (sectionLabelVisible === false) {
|
|
1236
|
+
// Different parts of the system refer to this concept with different keys.
|
|
1237
|
+
// - Fieldset view renderer currently uses `showTitle`
|
|
1238
|
+
// - Fieldset designer/property system uses `showHeader`
|
|
1239
|
+
fs.setOptions({ showTitle: false, showHeader: false });
|
|
1240
|
+
}
|
|
1193
1241
|
// Sort properties by order within section
|
|
1194
1242
|
const orderedProps = [...sectionProps].sort((a, b) => {
|
|
1195
1243
|
const aOrder = a.__order ?? Infinity;
|
|
@@ -1220,6 +1268,10 @@ class PropertyFilter {
|
|
|
1220
1268
|
if (fieldLayout?.label?.visible === false) {
|
|
1221
1269
|
field.setShowLabel(false);
|
|
1222
1270
|
}
|
|
1271
|
+
const hintOpts = hintFormFieldOptionsFromDescription(prop.description);
|
|
1272
|
+
if (hintOpts) {
|
|
1273
|
+
field.setOptions(hintOpts);
|
|
1274
|
+
}
|
|
1223
1275
|
const widgetType = prop.schema?.interface?.type || '';
|
|
1224
1276
|
const widgetOptions = buildWidgetOptions(prop);
|
|
1225
1277
|
const extendedProperties = buildWidgetExtendedProperties(prop);
|
|
@@ -1911,6 +1963,7 @@ const axpCreateEntityCommandDefinition = defineCommand({
|
|
|
1911
1963
|
summary: 'Dialog submit persists entity; navigation/toast behavior per entity form builder and settings.',
|
|
1912
1964
|
derivesFrom: 'AXPExecuteCommandResult<any> from entity form chain and AXPOpenEntityDetailsCommand',
|
|
1913
1965
|
},
|
|
1966
|
+
capabilities: ['ai'],
|
|
1914
1967
|
ai: {
|
|
1915
1968
|
shortDescription: 'Opens create dialog with pre-filled data; execution waits until the user submits or cancels, then returns—use for human-confirmed inserts into mock storage.',
|
|
1916
1969
|
usage: {
|
|
@@ -1925,6 +1978,7 @@ const axpCreateEntityCommandDefinition = defineCommand({
|
|
|
1925
1978
|
tags: ['entity', 'create', 'form', 'dialog', 'human-in-the-loop', 'mock', 'entity-storage', 'wait-user'],
|
|
1926
1979
|
toolInputDefaults: { ...axpCreateEntityAiToolInputDefaults },
|
|
1927
1980
|
},
|
|
1981
|
+
categories: [AXP_COMMAND_DEFINITION_CATEGORY_ENTITY],
|
|
1928
1982
|
});
|
|
1929
1983
|
|
|
1930
1984
|
class AXPUpdateEntityCommand {
|
|
@@ -2193,6 +2247,18 @@ class AXPEntityDetailPopoverComponent {
|
|
|
2193
2247
|
this.entityDetails = signal(null, ...(ngDevMode ? [{ debugName: "entityDetails" }] : /* istanbul ignore next */ []));
|
|
2194
2248
|
this.isLoadingDetails = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingDetails" }] : /* istanbul ignore next */ []));
|
|
2195
2249
|
this.isDetailPopoverOpen = signal(false, ...(ngDevMode ? [{ debugName: "isDetailPopoverOpen" }] : /* istanbul ignore next */ []));
|
|
2250
|
+
/**
|
|
2251
|
+
* Stable list of property widgets for the template. Must be a signal (computed), not a method:
|
|
2252
|
+
* calling a method from the template rebuilds nodes every CD cycle and can make the widget renderer loop.
|
|
2253
|
+
*/
|
|
2254
|
+
this.entityPropertiesWithWidgets = computed(() => {
|
|
2255
|
+
const details = this.entityDetails();
|
|
2256
|
+
const data = details?.entityData;
|
|
2257
|
+
const entityDefinition = details?.entityDefinition;
|
|
2258
|
+
if (!data || !entityDefinition?.properties)
|
|
2259
|
+
return [];
|
|
2260
|
+
return this.buildEntityPropertiesWithWidgets(data, entityDefinition, this.textField(), this.valueField());
|
|
2261
|
+
}, ...(ngDevMode ? [{ debugName: "entityPropertiesWithWidgets" }] : /* istanbul ignore next */ []));
|
|
2196
2262
|
}
|
|
2197
2263
|
//#endregion
|
|
2198
2264
|
//#region ---- Public Methods ----
|
|
@@ -2347,16 +2413,12 @@ class AXPEntityDetailPopoverComponent {
|
|
|
2347
2413
|
}
|
|
2348
2414
|
return 0;
|
|
2349
2415
|
}
|
|
2350
|
-
|
|
2351
|
-
const data = this.entityDetails()?.entityData;
|
|
2352
|
-
const entityDefinition = this.entityDetails()?.entityDefinition;
|
|
2353
|
-
if (!data || !entityDefinition?.properties)
|
|
2354
|
-
return [];
|
|
2416
|
+
buildEntityPropertiesWithWidgets(data, entityDefinition, textFieldValue, valueFieldValue) {
|
|
2355
2417
|
// Use properties (not columns) for correct titles and schema; columns may have dataPath that doesn't match
|
|
2356
|
-
|
|
2418
|
+
return entityDefinition.properties
|
|
2357
2419
|
.filter((prop) => {
|
|
2358
2420
|
// Exclude technical fields
|
|
2359
|
-
if (prop.name === 'id' || prop.name ===
|
|
2421
|
+
if (prop.name === 'id' || prop.name === textFieldValue || prop.name === valueFieldValue) {
|
|
2360
2422
|
return false;
|
|
2361
2423
|
}
|
|
2362
2424
|
// Only include properties that have a meaningful value (using get for dotted paths)
|
|
@@ -2424,7 +2486,6 @@ class AXPEntityDetailPopoverComponent {
|
|
|
2424
2486
|
node: widgetNode,
|
|
2425
2487
|
};
|
|
2426
2488
|
});
|
|
2427
|
-
return importantProperties;
|
|
2428
2489
|
}
|
|
2429
2490
|
/**
|
|
2430
2491
|
* Resolves the data path for a property. For lookups with expose, returns the expanded path
|
|
@@ -2447,11 +2508,11 @@ class AXPEntityDetailPopoverComponent {
|
|
|
2447
2508
|
return prop.name;
|
|
2448
2509
|
}
|
|
2449
2510
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailPopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2450
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPEntityDetailPopoverComponent, isStandalone: true, selector: "axp-entity-detail-popover", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: true, transformFunction: null }, entityId: { classPropertyName: "entityId", publicName: "entityId", isSignal: true, isRequired: true, transformFunction: null }, textField: { classPropertyName: "textField", publicName: "textField", isSignal: true, isRequired: false, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: true, isRequired: false, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: false, transformFunction: null }, breadcrumb: { classPropertyName: "breadcrumb", publicName: "breadcrumb", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "detailPopover", first: true, predicate: ["detailPopover"], descendants: true, isSignal: true }], ngImport: i0, template: "<ax-popover [openOn]=\"'manual'\" #detailPopover (openChange)=\"onDetailPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-border ax-rounded-lg ax-shadow-lg ax-p-4 ax-min-w-[400px]\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold ax-text-on-lightest-surface\">\n {{ entityDetails()?.entityData?.[textField()] ?? item()?.[textField()] | translate | async }}\n </h3>\n @if (breadcrumb()) {\n <div class=\"ax-text-xs ax-text-neutral-500 ax-mt-1\">{{ breadcrumb() }}</div>\n }\n </div>\n @if (isLoadingDetails()) {\n <div class=\"ax-flex ax-items-center ax-justify-center ax-py-8\">\n <ax-loading>Loading details...</ax-loading>\n </div>\n } @else if (entityDetails()) {\n <div class=\"ax-space-y-3 ax-mb-4\">\n <!-- Important Entity Data -->\n @if (entityDetails()?.entityData) {\n <axp-widgets-container [context]=\"entityDetails()?.entityData\">\n <div class=\"ax-space-y-2\">\n @for (item of
|
|
2511
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPEntityDetailPopoverComponent, isStandalone: true, selector: "axp-entity-detail-popover", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: true, transformFunction: null }, entityId: { classPropertyName: "entityId", publicName: "entityId", isSignal: true, isRequired: true, transformFunction: null }, textField: { classPropertyName: "textField", publicName: "textField", isSignal: true, isRequired: false, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: true, isRequired: false, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: false, transformFunction: null }, breadcrumb: { classPropertyName: "breadcrumb", publicName: "breadcrumb", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "detailPopover", first: true, predicate: ["detailPopover"], descendants: true, isSignal: true }], ngImport: i0, template: "<ax-popover [openOn]=\"'manual'\" #detailPopover (openChange)=\"onDetailPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-border ax-rounded-lg ax-shadow-lg ax-p-4 ax-min-w-[400px]\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold ax-text-on-lightest-surface\">\n {{ entityDetails()?.entityData?.[textField()] ?? item()?.[textField()] | translate | async }}\n </h3>\n @if (breadcrumb()) {\n <div class=\"ax-text-xs ax-text-neutral-500 ax-mt-1\">{{ breadcrumb() }}</div>\n }\n </div>\n @if (isLoadingDetails()) {\n <div class=\"ax-flex ax-items-center ax-justify-center ax-py-8\">\n <ax-loading>Loading details...</ax-loading>\n </div>\n } @else if (entityDetails()) {\n <div class=\"ax-space-y-3 ax-mb-4\">\n <!-- Important Entity Data -->\n @if (entityDetails()?.entityData) {\n <axp-widgets-container [context]=\"entityDetails()?.entityData\">\n <div class=\"ax-space-y-2\">\n @for (item of entityPropertiesWithWidgets(); track item.name) {\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <span class=\"ax-text-sm ax-font-medium\">{{ item.title | translate | async }}:</span>\n <div class=\"ax-flex-1 ax-ml-2 ax-max-w-48\">\n <ng-container axp-widget-renderer [node]=\"item.node\" [mode]=\"'view'\"></ng-container>\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n }\n </div>\n <div class=\"ax-flex ax-gap-2 ax-justify-end ax-sm\">\n <ax-button\n [color]=\"'primary'\"\n [look]=\"'solid'\"\n [text]=\"'@general:actions.open-details.title' | translate | async\"\n (click)=\"navigateToDetails()\"\n >\n </ax-button>\n </div>\n }\n </div>\n</ax-popover>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "repositionOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i3.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i3.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2451
2512
|
}
|
|
2452
2513
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailPopoverComponent, decorators: [{
|
|
2453
2514
|
type: Component,
|
|
2454
|
-
args: [{ selector: 'axp-entity-detail-popover', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, AXButtonModule, AXPopoverModule, AXPWidgetCoreModule, AXTranslationModule, AXLoadingModule], template: "<ax-popover [openOn]=\"'manual'\" #detailPopover (openChange)=\"onDetailPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-border ax-rounded-lg ax-shadow-lg ax-p-4 ax-min-w-[400px]\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold ax-text-on-lightest-surface\">\n {{ entityDetails()?.entityData?.[textField()] ?? item()?.[textField()] | translate | async }}\n </h3>\n @if (breadcrumb()) {\n <div class=\"ax-text-xs ax-text-neutral-500 ax-mt-1\">{{ breadcrumb() }}</div>\n }\n </div>\n @if (isLoadingDetails()) {\n <div class=\"ax-flex ax-items-center ax-justify-center ax-py-8\">\n <ax-loading>Loading details...</ax-loading>\n </div>\n } @else if (entityDetails()) {\n <div class=\"ax-space-y-3 ax-mb-4\">\n <!-- Important Entity Data -->\n @if (entityDetails()?.entityData) {\n <axp-widgets-container [context]=\"entityDetails()?.entityData\">\n <div class=\"ax-space-y-2\">\n @for (item of
|
|
2515
|
+
args: [{ selector: 'axp-entity-detail-popover', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, AXButtonModule, AXPopoverModule, AXPWidgetCoreModule, AXTranslationModule, AXLoadingModule], template: "<ax-popover [openOn]=\"'manual'\" #detailPopover (openChange)=\"onDetailPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-border ax-rounded-lg ax-shadow-lg ax-p-4 ax-min-w-[400px]\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold ax-text-on-lightest-surface\">\n {{ entityDetails()?.entityData?.[textField()] ?? item()?.[textField()] | translate | async }}\n </h3>\n @if (breadcrumb()) {\n <div class=\"ax-text-xs ax-text-neutral-500 ax-mt-1\">{{ breadcrumb() }}</div>\n }\n </div>\n @if (isLoadingDetails()) {\n <div class=\"ax-flex ax-items-center ax-justify-center ax-py-8\">\n <ax-loading>Loading details...</ax-loading>\n </div>\n } @else if (entityDetails()) {\n <div class=\"ax-space-y-3 ax-mb-4\">\n <!-- Important Entity Data -->\n @if (entityDetails()?.entityData) {\n <axp-widgets-container [context]=\"entityDetails()?.entityData\">\n <div class=\"ax-space-y-2\">\n @for (item of entityPropertiesWithWidgets(); track item.name) {\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <span class=\"ax-text-sm ax-font-medium\">{{ item.title | translate | async }}:</span>\n <div class=\"ax-flex-1 ax-ml-2 ax-max-w-48\">\n <ng-container axp-widget-renderer [node]=\"item.node\" [mode]=\"'view'\"></ng-container>\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n }\n </div>\n <div class=\"ax-flex ax-gap-2 ax-justify-end ax-sm\">\n <ax-button\n [color]=\"'primary'\"\n [look]=\"'solid'\"\n [text]=\"'@general:actions.open-details.title' | translate | async\"\n (click)=\"navigateToDetails()\"\n >\n </ax-button>\n </div>\n }\n </div>\n</ax-popover>\n" }]
|
|
2455
2516
|
}], propDecorators: { entity: [{ type: i0.Input, args: [{ isSignal: true, alias: "entity", required: true }] }], entityId: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityId", required: true }] }], textField: [{ type: i0.Input, args: [{ isSignal: true, alias: "textField", required: false }] }], valueField: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueField", required: false }] }], item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: false }] }], breadcrumb: [{ type: i0.Input, args: [{ isSignal: true, alias: "breadcrumb", required: false }] }], detailPopover: [{ type: i0.ViewChild, args: ['detailPopover', { isSignal: true }] }] } });
|
|
2456
2517
|
|
|
2457
2518
|
class AXPEntityDetailPopoverService {
|
|
@@ -4151,6 +4212,7 @@ class AXPEntityMasterListViewModel {
|
|
|
4151
4212
|
return this.sortedFields().filter((i) => i.dir).length;
|
|
4152
4213
|
};
|
|
4153
4214
|
this.sortedFields = signal([], ...(ngDevMode ? [{ debugName: "sortedFields" }] : /* istanbul ignore next */ []));
|
|
4215
|
+
//#endregion
|
|
4154
4216
|
this.evaluateExpressions = async (options, data) => {
|
|
4155
4217
|
const scope = this.createExpressionScope(data);
|
|
4156
4218
|
return await this.expressionEvaluator.evaluate(options, scope);
|
|
@@ -4623,7 +4685,8 @@ class AXPEntityMasterListViewModel {
|
|
|
4623
4685
|
const command = resolvedTriggerName.split('&')[0];
|
|
4624
4686
|
const options = await this.evaluateExpressions(action?.options, data);
|
|
4625
4687
|
const baseData = action?.scope == AXPEntityCommandScope.Selected ? this.selectedItems() : data;
|
|
4626
|
-
|
|
4688
|
+
let commandData = this.mergeViewConditionsForCreate(command, baseData);
|
|
4689
|
+
commandData = this.mergeDefaultCategoryForCreate(command, commandData);
|
|
4627
4690
|
if (this.workflow.exists(command)) {
|
|
4628
4691
|
await this.workflow.execute(command, {
|
|
4629
4692
|
entity: getEntityInfo(this.entityDef).source,
|
|
@@ -4705,6 +4768,38 @@ class AXPEntityMasterListViewModel {
|
|
|
4705
4768
|
}
|
|
4706
4769
|
return baseData;
|
|
4707
4770
|
}
|
|
4771
|
+
//#region ---- Create command defaults from list view ----
|
|
4772
|
+
/**
|
|
4773
|
+
* Seeds create payloads with fixed list-view conditions (e.g. scope=T on the tenant dashboards view)
|
|
4774
|
+
* so new rows match the view context and downstream queries (such as home dashboard) can find them.
|
|
4775
|
+
*/
|
|
4776
|
+
mergeViewConditionsForCreate(command, baseData) {
|
|
4777
|
+
const isCreateCommand = command === 'Entity:Create' || command === 'create-entity';
|
|
4778
|
+
if (!isCreateCommand) {
|
|
4779
|
+
return baseData;
|
|
4780
|
+
}
|
|
4781
|
+
const conditions = this.view()?.conditions ?? [];
|
|
4782
|
+
if (conditions.length === 0) {
|
|
4783
|
+
return baseData;
|
|
4784
|
+
}
|
|
4785
|
+
const seed = {};
|
|
4786
|
+
for (const c of conditions) {
|
|
4787
|
+
if (!c?.name || c.operator?.type !== 'equal' || c.value === undefined) {
|
|
4788
|
+
continue;
|
|
4789
|
+
}
|
|
4790
|
+
seed[c.name] = c.value;
|
|
4791
|
+
}
|
|
4792
|
+
if (Object.keys(seed).length === 0) {
|
|
4793
|
+
return baseData;
|
|
4794
|
+
}
|
|
4795
|
+
if (baseData == null) {
|
|
4796
|
+
return seed;
|
|
4797
|
+
}
|
|
4798
|
+
if (typeof baseData === 'object' && !Array.isArray(baseData)) {
|
|
4799
|
+
return { ...seed, ...baseData };
|
|
4800
|
+
}
|
|
4801
|
+
return baseData;
|
|
4802
|
+
}
|
|
4708
4803
|
async execute(command) {
|
|
4709
4804
|
switch (command?.name) {
|
|
4710
4805
|
case 'navigate':
|
|
@@ -9858,7 +9953,7 @@ class AXPEntityListTableService {
|
|
|
9858
9953
|
animation: true,
|
|
9859
9954
|
},
|
|
9860
9955
|
// 🎪 Events
|
|
9861
|
-
...this.createDefaultEvents(entity, allActions),
|
|
9956
|
+
...this.createDefaultEvents(entity, allActions, options?.excludeProperties),
|
|
9862
9957
|
};
|
|
9863
9958
|
console.log('listOptions', listOptions);
|
|
9864
9959
|
return listOptions;
|
|
@@ -9948,7 +10043,7 @@ class AXPEntityListTableService {
|
|
|
9948
10043
|
/**
|
|
9949
10044
|
* Handle execution of a row command (shared by double-click and command handlers)
|
|
9950
10045
|
*/
|
|
9951
|
-
async handleRowCommand(e, selectedRows, entity, allActions) {
|
|
10046
|
+
async handleRowCommand(e, selectedRows, entity, allActions, relatedListExcludeProperties) {
|
|
9952
10047
|
const data = e.data;
|
|
9953
10048
|
const commandName = e.name;
|
|
9954
10049
|
const action = allActions.find((c) => {
|
|
@@ -9959,7 +10054,8 @@ class AXPEntityListTableService {
|
|
|
9959
10054
|
c.scope == AXPEntityCommandScope.TypeLevel));
|
|
9960
10055
|
});
|
|
9961
10056
|
const command = commandName.split('&')[0];
|
|
9962
|
-
const
|
|
10057
|
+
const evaluatedOptions = await this.evaluateExpressions(action?.options, data);
|
|
10058
|
+
const options = this.mergeRelatedListFormOptions(command, evaluatedOptions, relatedListExcludeProperties);
|
|
9963
10059
|
if (this.commandService.exists(command)) {
|
|
9964
10060
|
await this.commandService.execute(command, {
|
|
9965
10061
|
__context__: {
|
|
@@ -9995,10 +10091,25 @@ class AXPEntityListTableService {
|
|
|
9995
10091
|
});
|
|
9996
10092
|
}
|
|
9997
10093
|
}
|
|
10094
|
+
/**
|
|
10095
|
+
* When a related entity list declares `excludeProperties`, row commands bypass the details page
|
|
10096
|
+
* `execute()` merge — apply the same exclusions for embedded create/update commands.
|
|
10097
|
+
*/
|
|
10098
|
+
mergeRelatedListFormOptions(command, evaluatedOptions, relatedListExcludeProperties) {
|
|
10099
|
+
const exclusions = relatedListExcludeProperties?.filter(Boolean);
|
|
10100
|
+
if (!exclusions?.length ||
|
|
10101
|
+
(command !== 'Entity:Create' && command !== 'Entity:Update')) {
|
|
10102
|
+
return evaluatedOptions;
|
|
10103
|
+
}
|
|
10104
|
+
return {
|
|
10105
|
+
...evaluatedOptions,
|
|
10106
|
+
excludeProperties: exclusions,
|
|
10107
|
+
};
|
|
10108
|
+
}
|
|
9998
10109
|
/**
|
|
9999
10110
|
* Create default events
|
|
10000
10111
|
*/
|
|
10001
|
-
createDefaultEvents(entity, allActions) {
|
|
10112
|
+
createDefaultEvents(entity, allActions, relatedListExcludeProperties) {
|
|
10002
10113
|
return {
|
|
10003
10114
|
onRowClick: (row) => {
|
|
10004
10115
|
console.log('Entity List - Row clicked:', row);
|
|
@@ -10017,13 +10128,13 @@ class AXPEntityListTableService {
|
|
|
10017
10128
|
name: defaultAction.name,
|
|
10018
10129
|
data: e.data,
|
|
10019
10130
|
};
|
|
10020
|
-
this.handleRowCommand(d, undefined, entity, allActions);
|
|
10131
|
+
this.handleRowCommand(d, undefined, entity, allActions, relatedListExcludeProperties);
|
|
10021
10132
|
},
|
|
10022
10133
|
onSelectionChange: (selectedRows) => {
|
|
10023
10134
|
console.log('Entity List - Selection changed:', selectedRows);
|
|
10024
10135
|
},
|
|
10025
10136
|
onRowCommand: async (e, selectedRows) => {
|
|
10026
|
-
await this.handleRowCommand(e, selectedRows, entity, allActions);
|
|
10137
|
+
await this.handleRowCommand(e, selectedRows, entity, allActions, relatedListExcludeProperties);
|
|
10027
10138
|
},
|
|
10028
10139
|
};
|
|
10029
10140
|
}
|
|
@@ -10380,7 +10491,12 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
10380
10491
|
const commandData = action?.scope == AXPEntityCommandScope.Selected
|
|
10381
10492
|
? this.selectedItems()
|
|
10382
10493
|
: action?.options?.['process']?.data || null;
|
|
10383
|
-
const
|
|
10494
|
+
const evaluatedToolbarOptions = await this.evaluateToolbarExpressions(action?.options, commandData);
|
|
10495
|
+
const relatedExcludes = this.options()['excludeProperties'];
|
|
10496
|
+
const exclusions = relatedExcludes?.filter(Boolean);
|
|
10497
|
+
const options = exclusions?.length && (command === 'Entity:Create' || command === 'Entity:Update')
|
|
10498
|
+
? { ...evaluatedToolbarOptions, excludeProperties: exclusions }
|
|
10499
|
+
: evaluatedToolbarOptions;
|
|
10384
10500
|
if (this.commandService.exists(command)) {
|
|
10385
10501
|
await this.commandService.execute(command, {
|
|
10386
10502
|
__context__: {
|
|
@@ -10529,6 +10645,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
10529
10645
|
includeColumns: this.includeColumns(),
|
|
10530
10646
|
relatedTableColumns: this.relatedTableColumns(),
|
|
10531
10647
|
customFilterDefinitions: this.customFilterDefinitions(),
|
|
10648
|
+
excludeProperties: this.options()['excludeProperties'],
|
|
10532
10649
|
};
|
|
10533
10650
|
const listOptions = await this.entityListTableService.convertEntityToListOptions(resolvedEntity, options, this.allActions());
|
|
10534
10651
|
const toolbarOptions = await this.entityListToolbarService.convertEntityToolbarOptions(resolvedEntity, options);
|
|
@@ -10846,7 +10963,7 @@ const AXPEntityListWidget = {
|
|
|
10846
10963
|
type: 'view',
|
|
10847
10964
|
categories: [],
|
|
10848
10965
|
groups: [AXPWidgetGroupEnum.EntityWidget],
|
|
10849
|
-
icon: 'fa-
|
|
10966
|
+
icon: 'fa-light fa-square',
|
|
10850
10967
|
properties: [AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY],
|
|
10851
10968
|
components: {
|
|
10852
10969
|
view: {
|
|
@@ -12517,36 +12634,47 @@ var lookupWidgetEdit_component = /*#__PURE__*/Object.freeze({
|
|
|
12517
12634
|
|
|
12518
12635
|
class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
12519
12636
|
constructor() {
|
|
12520
|
-
super(
|
|
12521
|
-
//#region ----
|
|
12637
|
+
super();
|
|
12638
|
+
//#region ---- Dependencies ----
|
|
12522
12639
|
this.entityDetailPopoverService = inject(AXPEntityDetailPopoverService);
|
|
12523
|
-
this.
|
|
12640
|
+
this.translation = inject(AXTranslationService);
|
|
12524
12641
|
this.formatService = inject(AXFormatService);
|
|
12642
|
+
this.entityService = inject(AXPEntityService);
|
|
12643
|
+
this.queryExecutor = inject(AXPQueryExecutor);
|
|
12525
12644
|
//#endregion
|
|
12526
|
-
//#region ----
|
|
12645
|
+
//#region ---- View Children ----
|
|
12527
12646
|
this.moreButton = viewChild('moreButton', ...(ngDevMode ? [{ debugName: "moreButton" }] : /* istanbul ignore next */ []));
|
|
12647
|
+
this.lazyTrigger = viewChild('lazyTrigger', ...(ngDevMode ? [{ debugName: "lazyTrigger" }] : /* istanbul ignore next */ []));
|
|
12528
12648
|
this.morePopover = viewChild('morePopover', ...(ngDevMode ? [{ debugName: "morePopover" }] : /* istanbul ignore next */ []));
|
|
12529
12649
|
//#endregion
|
|
12530
|
-
//#region ----
|
|
12650
|
+
//#region ---- Properties ----
|
|
12531
12651
|
this.host = inject(ElementRef);
|
|
12532
12652
|
this.valueField = this.options['valueField'] ?? 'id';
|
|
12533
12653
|
this.textField = this.options['textField'] ?? 'title';
|
|
12534
|
-
this.entity = this.options['entity'] ?? '
|
|
12654
|
+
this.entity = this.options['entity'] ?? '';
|
|
12535
12655
|
this.columnName = this.options['columnName'] ?? 'title';
|
|
12536
12656
|
this.maxVisible = this.options['maxVisible'] ?? 2;
|
|
12537
12657
|
this.displayFormat = computed(() => {
|
|
12538
12658
|
const template = this.options['displayFormat'];
|
|
12539
12659
|
return template ? template.replace(/\{/g, '{{').replace(/\}/g, '}}') : undefined;
|
|
12540
12660
|
}, ...(ngDevMode ? [{ debugName: "displayFormat" }] : /* istanbul ignore next */ []));
|
|
12541
|
-
this.displayField = computed(() => {
|
|
12542
|
-
|
|
12543
|
-
|
|
12661
|
+
this.displayField = computed(() => this.textField ?? 'title', ...(ngDevMode ? [{ debugName: "displayField" }] : /* istanbul ignore next */ []));
|
|
12662
|
+
this.columnResolve = computed(() => this.options['columnResolve'], ...(ngDevMode ? [{ debugName: "columnResolve" }] : /* istanbul ignore next */ []));
|
|
12663
|
+
this.resolveStrategy = computed(() => {
|
|
12664
|
+
return this.columnResolve()?.strategy ?? 'hydrated';
|
|
12665
|
+
}, ...(ngDevMode ? [{ debugName: "resolveStrategy" }] : /* istanbul ignore next */ []));
|
|
12666
|
+
this.isHydratedStrategy = computed(() => this.resolveStrategy() === 'hydrated', ...(ngDevMode ? [{ debugName: "isHydratedStrategy" }] : /* istanbul ignore next */ []));
|
|
12544
12667
|
//#endregion
|
|
12545
|
-
//#region ----
|
|
12668
|
+
//#region ---- Signals ----
|
|
12546
12669
|
this.isMorePopoverOpen = signal(false, ...(ngDevMode ? [{ debugName: "isMorePopoverOpen" }] : /* istanbul ignore next */ []));
|
|
12547
12670
|
this.selectedItemIndex = signal(-1, ...(ngDevMode ? [{ debugName: "selectedItemIndex" }] : /* istanbul ignore next */ []));
|
|
12671
|
+
this.resolvedPopoverItems = signal([], ...(ngDevMode ? [{ debugName: "resolvedPopoverItems" }] : /* istanbul ignore next */ []));
|
|
12672
|
+
this.resolveStatus = signal('idle', ...(ngDevMode ? [{ debugName: "resolveStatus" }] : /* istanbul ignore next */ []));
|
|
12673
|
+
this.resolveError = signal(null, ...(ngDevMode ? [{ debugName: "resolveError" }] : /* istanbul ignore next */ []));
|
|
12674
|
+
this.summaryLabel = signal('', ...(ngDevMode ? [{ debugName: "summaryLabel" }] : /* istanbul ignore next */ []));
|
|
12675
|
+
this.popoverHeader = signal('', ...(ngDevMode ? [{ debugName: "popoverHeader" }] : /* istanbul ignore next */ []));
|
|
12548
12676
|
//#endregion
|
|
12549
|
-
//#region ----
|
|
12677
|
+
//#region ---- Computed ----
|
|
12550
12678
|
this.displayItems = computed(() => isNil(this.rawValue)
|
|
12551
12679
|
? []
|
|
12552
12680
|
: castArray(this.rawValue)
|
|
@@ -12557,34 +12685,127 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
12557
12685
|
const items = this.allItems();
|
|
12558
12686
|
return items.slice(0, this.maxVisible);
|
|
12559
12687
|
}, ...(ngDevMode ? [{ debugName: "visibleItems" }] : /* istanbul ignore next */ []));
|
|
12560
|
-
this.hasMoreItems = computed(() => {
|
|
12561
|
-
|
|
12562
|
-
|
|
12563
|
-
|
|
12564
|
-
|
|
12565
|
-
|
|
12688
|
+
this.hasMoreItems = computed(() => this.allItems().length > this.maxVisible, ...(ngDevMode ? [{ debugName: "hasMoreItems" }] : /* istanbul ignore next */ []));
|
|
12689
|
+
this.idsFromRow = computed(() => {
|
|
12690
|
+
const cr = this.columnResolve();
|
|
12691
|
+
const path = cr?.idsPath;
|
|
12692
|
+
const source = path ? get(this.rowData, path) : this.rawValue;
|
|
12693
|
+
if (isNil(source)) {
|
|
12694
|
+
return [];
|
|
12695
|
+
}
|
|
12696
|
+
return castArray(source)
|
|
12697
|
+
.map((x) => (typeof x === 'object' && x != null ? get(x, this.valueField) : x))
|
|
12698
|
+
.filter((id) => id != null && id !== '');
|
|
12699
|
+
}, ...(ngDevMode ? [{ debugName: "idsFromRow" }] : /* istanbul ignore next */ []));
|
|
12700
|
+
this.displayCount = computed(() => {
|
|
12701
|
+
const cr = this.columnResolve();
|
|
12702
|
+
const countPath = cr?.countFieldPath;
|
|
12703
|
+
if (countPath) {
|
|
12704
|
+
const v = get(this.rowData, countPath);
|
|
12705
|
+
if (typeof v === 'number' && !Number.isNaN(v)) {
|
|
12706
|
+
return v;
|
|
12707
|
+
}
|
|
12708
|
+
if (typeof v === 'string' && v !== '') {
|
|
12709
|
+
const n = Number(v);
|
|
12710
|
+
return Number.isNaN(n) ? 0 : n;
|
|
12711
|
+
}
|
|
12712
|
+
return 0;
|
|
12713
|
+
}
|
|
12714
|
+
if (this.resolveStrategy() === 'idsWithCount') {
|
|
12715
|
+
return this.idsFromRow().length;
|
|
12716
|
+
}
|
|
12717
|
+
if (this.resolveStrategy() === 'countOnly') {
|
|
12718
|
+
return 0;
|
|
12719
|
+
}
|
|
12720
|
+
return 0;
|
|
12721
|
+
}, ...(ngDevMode ? [{ debugName: "displayCount" }] : /* istanbul ignore next */ []));
|
|
12722
|
+
this.popoverListItems = computed(() => {
|
|
12723
|
+
if (this.isHydratedStrategy()) {
|
|
12724
|
+
return this.allItems();
|
|
12725
|
+
}
|
|
12726
|
+
return this.resolvedPopoverItems();
|
|
12727
|
+
}, ...(ngDevMode ? [{ debugName: "popoverListItems" }] : /* istanbul ignore next */ []));
|
|
12728
|
+
//#endregion
|
|
12729
|
+
//#region ---- Constructor effects ----
|
|
12730
|
+
/** Avoid resetting lazy cache on every CD when `rowData` is a new object reference for the same row. */
|
|
12731
|
+
this.previousLazyRowId = undefined;
|
|
12732
|
+
effect(() => {
|
|
12733
|
+
const id = this.rowData?.['id'];
|
|
12734
|
+
const key = id != null && id !== '' ? String(id) : undefined;
|
|
12735
|
+
if (key === this.previousLazyRowId) {
|
|
12736
|
+
return;
|
|
12737
|
+
}
|
|
12738
|
+
this.previousLazyRowId = key;
|
|
12739
|
+
this.resetLazyState();
|
|
12740
|
+
});
|
|
12741
|
+
effect(() => {
|
|
12742
|
+
if (!this.isHydratedStrategy()) {
|
|
12743
|
+
const count = this.displayCount();
|
|
12744
|
+
void this.refreshSummaryLabel(count);
|
|
12745
|
+
}
|
|
12746
|
+
});
|
|
12747
|
+
effect(() => {
|
|
12748
|
+
const hydrated = this.isHydratedStrategy();
|
|
12749
|
+
const count = hydrated
|
|
12750
|
+
? this.allItems().length
|
|
12751
|
+
: this.resolveStatus() === 'ready'
|
|
12752
|
+
? this.resolvedPopoverItems().length
|
|
12753
|
+
: this.displayCount();
|
|
12754
|
+
void this.refreshPopoverHeader(count);
|
|
12755
|
+
});
|
|
12566
12756
|
}
|
|
12567
12757
|
//#endregion
|
|
12568
|
-
//#region ----
|
|
12758
|
+
//#region ---- Public methods ----
|
|
12569
12759
|
showMoreItems() {
|
|
12570
12760
|
this.entityDetailPopoverService.hide();
|
|
12571
|
-
this.
|
|
12761
|
+
this.openPopoverFromRef(this.moreButton());
|
|
12572
12762
|
}
|
|
12573
|
-
|
|
12574
|
-
this.
|
|
12763
|
+
openLazyPopover() {
|
|
12764
|
+
this.entityDetailPopoverService.hide();
|
|
12765
|
+
this.openPopoverFromRef(this.lazyTrigger());
|
|
12766
|
+
if (!this.isHydratedStrategy()) {
|
|
12767
|
+
void this.ensureLazyItemsLoaded();
|
|
12768
|
+
}
|
|
12769
|
+
}
|
|
12770
|
+
onPopoverOpenChange(event) {
|
|
12771
|
+
const open = this.coercePopoverOpenEvent(event);
|
|
12772
|
+
this.isMorePopoverOpen.set(open);
|
|
12773
|
+
if (open && !this.isHydratedStrategy()) {
|
|
12774
|
+
void this.ensureLazyItemsLoaded();
|
|
12775
|
+
}
|
|
12575
12776
|
}
|
|
12576
12777
|
async showItemDetail(item, index) {
|
|
12577
12778
|
if (this.options['disableDetailPopover']) {
|
|
12578
12779
|
return;
|
|
12579
12780
|
}
|
|
12580
|
-
const columnData = this.rowData[this.columnName];
|
|
12581
|
-
const id = Array.isArray(columnData) ? columnData[index] : columnData;
|
|
12582
12781
|
this.selectedItemIndex.set(index);
|
|
12583
12782
|
this.closeMorePopover();
|
|
12584
|
-
//
|
|
12783
|
+
// Prefer the row's FK / stored value (columnName) first. List columns often use options.dataPath so
|
|
12784
|
+
// rawValue (and thus `item`) is only display text (e.g. manager.person.fullName) while managerId holds the real id.
|
|
12785
|
+
const columnData = this.rowData?.[this.columnName];
|
|
12786
|
+
let id;
|
|
12787
|
+
if (Array.isArray(columnData)) {
|
|
12788
|
+
const cell = columnData[index];
|
|
12789
|
+
id =
|
|
12790
|
+
typeof cell === 'object' && cell != null
|
|
12791
|
+
? get(cell, this.valueField)
|
|
12792
|
+
: cell;
|
|
12793
|
+
}
|
|
12794
|
+
else if (!isNil(columnData) && columnData !== '') {
|
|
12795
|
+
id =
|
|
12796
|
+
typeof columnData === 'object' && columnData != null
|
|
12797
|
+
? get(columnData, this.valueField)
|
|
12798
|
+
: columnData;
|
|
12799
|
+
}
|
|
12800
|
+
if (isNil(id) || id === '') {
|
|
12801
|
+
id = get(item, this.valueField);
|
|
12802
|
+
}
|
|
12803
|
+
if (isNil(id) || id === '') {
|
|
12804
|
+
return;
|
|
12805
|
+
}
|
|
12585
12806
|
await this.entityDetailPopoverService.show(this.host, {
|
|
12586
12807
|
entity: this.entity,
|
|
12587
|
-
id
|
|
12808
|
+
id,
|
|
12588
12809
|
textField: this.textField,
|
|
12589
12810
|
valueField: this.valueField,
|
|
12590
12811
|
item,
|
|
@@ -12596,36 +12817,25 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
12596
12817
|
}
|
|
12597
12818
|
const items = this.allItems();
|
|
12598
12819
|
if (index < items.length) {
|
|
12599
|
-
|
|
12600
|
-
this.showItemDetail(item, index);
|
|
12820
|
+
this.showItemDetail(items[index], index);
|
|
12601
12821
|
}
|
|
12602
12822
|
}
|
|
12603
|
-
|
|
12604
|
-
|
|
12605
|
-
|
|
12606
|
-
if (this.morePopover() && this.moreButton()) {
|
|
12607
|
-
this.morePopover().target = this.moreButton().nativeElement;
|
|
12608
|
-
this.morePopover().open();
|
|
12609
|
-
this.isMorePopoverOpen.set(true);
|
|
12823
|
+
handleResolvedItemClick(index) {
|
|
12824
|
+
if (this.options['disableDetailPopover']) {
|
|
12825
|
+
return;
|
|
12610
12826
|
}
|
|
12611
|
-
|
|
12612
|
-
|
|
12613
|
-
|
|
12614
|
-
this.morePopover().close();
|
|
12615
|
-
this.isMorePopoverOpen.set(false);
|
|
12827
|
+
const items = this.resolvedPopoverItems();
|
|
12828
|
+
if (index < items.length) {
|
|
12829
|
+
this.showItemDetail(items[index], index);
|
|
12616
12830
|
}
|
|
12617
12831
|
}
|
|
12618
|
-
|
|
12619
|
-
if (
|
|
12620
|
-
|
|
12832
|
+
handlePopoverItemClick(index) {
|
|
12833
|
+
if (this.isHydratedStrategy()) {
|
|
12834
|
+
this.handleItemClick(index);
|
|
12621
12835
|
}
|
|
12622
|
-
|
|
12623
|
-
|
|
12836
|
+
else {
|
|
12837
|
+
this.handleResolvedItemClick(index);
|
|
12624
12838
|
}
|
|
12625
|
-
return {
|
|
12626
|
-
[this.valueField]: item,
|
|
12627
|
-
[this.textField]: item,
|
|
12628
|
-
};
|
|
12629
12839
|
}
|
|
12630
12840
|
getDisplayRaw(item) {
|
|
12631
12841
|
if (isNil(item)) {
|
|
@@ -12643,6 +12853,178 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
12643
12853
|
}
|
|
12644
12854
|
return resolved ?? '';
|
|
12645
12855
|
}
|
|
12856
|
+
//#endregion
|
|
12857
|
+
//#region ---- Private methods ----
|
|
12858
|
+
async refreshSummaryLabel(count) {
|
|
12859
|
+
const text = await this.translation.translateAsync('@general:widgets.lookup.column.items-count', {
|
|
12860
|
+
params: { count: String(count) },
|
|
12861
|
+
});
|
|
12862
|
+
this.summaryLabel.set(text);
|
|
12863
|
+
}
|
|
12864
|
+
async refreshPopoverHeader(count) {
|
|
12865
|
+
const text = await this.translation.translateAsync('@general:widgets.lookup.column.popover-title', {
|
|
12866
|
+
params: { count: String(count) },
|
|
12867
|
+
});
|
|
12868
|
+
this.popoverHeader.set(text);
|
|
12869
|
+
}
|
|
12870
|
+
resetLazyState() {
|
|
12871
|
+
this.resolvedPopoverItems.set([]);
|
|
12872
|
+
this.resolveStatus.set('idle');
|
|
12873
|
+
this.resolveError.set(null);
|
|
12874
|
+
}
|
|
12875
|
+
openPopoverFromRef(ref) {
|
|
12876
|
+
const popover = this.morePopover();
|
|
12877
|
+
if (popover && ref) {
|
|
12878
|
+
popover.target = ref.nativeElement;
|
|
12879
|
+
popover.open();
|
|
12880
|
+
this.isMorePopoverOpen.set(true);
|
|
12881
|
+
}
|
|
12882
|
+
}
|
|
12883
|
+
closeMorePopover() {
|
|
12884
|
+
const popover = this.morePopover();
|
|
12885
|
+
if (popover) {
|
|
12886
|
+
popover.close();
|
|
12887
|
+
this.isMorePopoverOpen.set(false);
|
|
12888
|
+
}
|
|
12889
|
+
}
|
|
12890
|
+
async ensureLazyItemsLoaded() {
|
|
12891
|
+
if (this.resolveStatus() === 'loading') {
|
|
12892
|
+
return;
|
|
12893
|
+
}
|
|
12894
|
+
const strategy = this.resolveStrategy();
|
|
12895
|
+
if (strategy === 'idsWithCount') {
|
|
12896
|
+
await this.loadByIds();
|
|
12897
|
+
return;
|
|
12898
|
+
}
|
|
12899
|
+
if (strategy === 'countOnly') {
|
|
12900
|
+
await this.loadByNamedQuery();
|
|
12901
|
+
}
|
|
12902
|
+
}
|
|
12903
|
+
/**
|
|
12904
|
+
* ax-popover may emit a boolean, CustomEvent with detail, or a DOM Event depending on version.
|
|
12905
|
+
*/
|
|
12906
|
+
coercePopoverOpenEvent(event) {
|
|
12907
|
+
if (typeof event === 'boolean') {
|
|
12908
|
+
return event;
|
|
12909
|
+
}
|
|
12910
|
+
if (event && typeof event === 'object') {
|
|
12911
|
+
const o = event;
|
|
12912
|
+
if ('detail' in o) {
|
|
12913
|
+
return Boolean(o['detail']);
|
|
12914
|
+
}
|
|
12915
|
+
if ('open' in o) {
|
|
12916
|
+
return Boolean(o['open']);
|
|
12917
|
+
}
|
|
12918
|
+
}
|
|
12919
|
+
return false;
|
|
12920
|
+
}
|
|
12921
|
+
async loadByIds() {
|
|
12922
|
+
const ids = this.idsFromRow();
|
|
12923
|
+
if (!ids.length) {
|
|
12924
|
+
this.resolvedPopoverItems.set([]);
|
|
12925
|
+
this.resolveStatus.set('ready');
|
|
12926
|
+
return;
|
|
12927
|
+
}
|
|
12928
|
+
if (!this.entity?.includes('.')) {
|
|
12929
|
+
const msg = await this.translation.translateAsync('@general:widgets.lookup.column.load-failed');
|
|
12930
|
+
this.resolveError.set(msg);
|
|
12931
|
+
this.resolveStatus.set('error');
|
|
12932
|
+
return;
|
|
12933
|
+
}
|
|
12934
|
+
this.resolveStatus.set('loading');
|
|
12935
|
+
this.resolveError.set(null);
|
|
12936
|
+
try {
|
|
12937
|
+
const accessor = this.entityService.withEntity(this.entity).data();
|
|
12938
|
+
const results = await Promise.all(ids.map((id) => accessor.byKey(id)));
|
|
12939
|
+
this.resolvedPopoverItems.set(results.filter((item) => item != null));
|
|
12940
|
+
this.resolveStatus.set('ready');
|
|
12941
|
+
}
|
|
12942
|
+
catch {
|
|
12943
|
+
const msg = await this.translation.translateAsync('@general:widgets.lookup.column.load-failed');
|
|
12944
|
+
this.resolveError.set(msg);
|
|
12945
|
+
this.resolveStatus.set('error');
|
|
12946
|
+
this.resolvedPopoverItems.set([]);
|
|
12947
|
+
}
|
|
12948
|
+
}
|
|
12949
|
+
async loadByNamedQuery() {
|
|
12950
|
+
const cr = this.columnResolve();
|
|
12951
|
+
const key = cr?.queryKey;
|
|
12952
|
+
if (!key?.trim()) {
|
|
12953
|
+
const msg = await this.translation.translateAsync('@general:widgets.lookup.column.load-failed');
|
|
12954
|
+
this.resolveError.set(msg);
|
|
12955
|
+
this.resolveStatus.set('error');
|
|
12956
|
+
return;
|
|
12957
|
+
}
|
|
12958
|
+
this.resolveStatus.set('loading');
|
|
12959
|
+
this.resolveError.set(null);
|
|
12960
|
+
try {
|
|
12961
|
+
const input = this.buildNamedQueryInput();
|
|
12962
|
+
const result = await this.queryExecutor.fetch(key, input);
|
|
12963
|
+
const items = this.extractItemsFromQueryResult(result);
|
|
12964
|
+
this.resolvedPopoverItems.set(items);
|
|
12965
|
+
this.resolveStatus.set('ready');
|
|
12966
|
+
}
|
|
12967
|
+
catch {
|
|
12968
|
+
const msg = await this.translation.translateAsync('@general:widgets.lookup.column.load-failed');
|
|
12969
|
+
this.resolveError.set(msg);
|
|
12970
|
+
this.resolveStatus.set('error');
|
|
12971
|
+
this.resolvedPopoverItems.set([]);
|
|
12972
|
+
}
|
|
12973
|
+
}
|
|
12974
|
+
buildNamedQueryInput() {
|
|
12975
|
+
const map = this.parseQueryParamsMap();
|
|
12976
|
+
const row = this.rowData ?? {};
|
|
12977
|
+
if (!map) {
|
|
12978
|
+
return {};
|
|
12979
|
+
}
|
|
12980
|
+
const out = {};
|
|
12981
|
+
for (const [param, path] of Object.entries(map)) {
|
|
12982
|
+
out[param] = get(row, path);
|
|
12983
|
+
}
|
|
12984
|
+
return out;
|
|
12985
|
+
}
|
|
12986
|
+
parseQueryParamsMap() {
|
|
12987
|
+
const raw = this.columnResolve()?.queryParams;
|
|
12988
|
+
if (raw == null) {
|
|
12989
|
+
return null;
|
|
12990
|
+
}
|
|
12991
|
+
if (typeof raw === 'string') {
|
|
12992
|
+
try {
|
|
12993
|
+
const parsed = JSON.parse(raw);
|
|
12994
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
12995
|
+
? parsed
|
|
12996
|
+
: null;
|
|
12997
|
+
}
|
|
12998
|
+
catch {
|
|
12999
|
+
return null;
|
|
13000
|
+
}
|
|
13001
|
+
}
|
|
13002
|
+
return raw;
|
|
13003
|
+
}
|
|
13004
|
+
extractItemsFromQueryResult(result) {
|
|
13005
|
+
if (result == null) {
|
|
13006
|
+
return [];
|
|
13007
|
+
}
|
|
13008
|
+
if (Array.isArray(result)) {
|
|
13009
|
+
return result;
|
|
13010
|
+
}
|
|
13011
|
+
const cr = this.columnResolve();
|
|
13012
|
+
const path = cr?.queryResultItemsPath ?? 'items';
|
|
13013
|
+
const nested = get(result, path);
|
|
13014
|
+
return Array.isArray(nested) ? nested : [];
|
|
13015
|
+
}
|
|
13016
|
+
extractItem(item) {
|
|
13017
|
+
if (isNil(item)) {
|
|
13018
|
+
return null;
|
|
13019
|
+
}
|
|
13020
|
+
if (typeof item === 'object') {
|
|
13021
|
+
return item;
|
|
13022
|
+
}
|
|
13023
|
+
return {
|
|
13024
|
+
[this.valueField]: item,
|
|
13025
|
+
[this.textField]: item,
|
|
13026
|
+
};
|
|
13027
|
+
}
|
|
12646
13028
|
resolveDisplayValue(item) {
|
|
12647
13029
|
if (isNil(item)) {
|
|
12648
13030
|
return '';
|
|
@@ -12657,18 +13039,18 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
12657
13039
|
if (!isNil(rawDisplayValue)) {
|
|
12658
13040
|
return this.resolveDisplayValue(rawDisplayValue);
|
|
12659
13041
|
}
|
|
12660
|
-
if (this.
|
|
12661
|
-
return this.
|
|
13042
|
+
if (this.translation.isValidMultiLanguageObject(item)) {
|
|
13043
|
+
return this.translation.resolve(item);
|
|
12662
13044
|
}
|
|
12663
13045
|
return '';
|
|
12664
13046
|
}
|
|
12665
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetColumnComponent, deps:
|
|
12666
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLookupWidgetColumnComponent, isStandalone: true, selector: "ng-component", inputs: { rawValue: "rawValue", rowData: "rowData" }, viewQueries: [{ propertyName: "moreButton", first: true, predicate: ["moreButton"], descendants: true, isSignal: true }, { propertyName: "morePopover", first: true, predicate: ["morePopover"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-flex ax-
|
|
13047
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetColumnComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
13048
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLookupWidgetColumnComponent, isStandalone: true, selector: "ng-component", inputs: { rawValue: "rawValue", rowData: "rowData" }, viewQueries: [{ propertyName: "moreButton", first: true, predicate: ["moreButton"], descendants: true, isSignal: true }, { propertyName: "lazyTrigger", first: true, predicate: ["lazyTrigger"], descendants: true, isSignal: true }, { propertyName: "morePopover", first: true, predicate: ["morePopover"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@if (isHydratedStrategy()) {\n<div class=\"ax-relative ax-flex ax-min-w-0 ax-items-center ax-gap-1\">\n @for (item of visibleItems(); track $index) {\n @let label = getDisplayRaw(item);\n <span\n [class.ax-cursor-pointer]=\"!options['disableDetailPopover']\"\n [class.hover:ax-text-primary]=\"!options['disableDetailPopover']\"\n [class.hover:ax-underline]=\"!options['disableDetailPopover']\"\n (click)=\"handleItemClick($index)\"\n >\n {{ label }}\n </span>\n @if ($index < visibleItems().length - 1) {\n <span class=\"ax-text-muted\">\u2022</span>\n }\n } @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n @if (hasMoreItems()) {\n <span\n class=\"ax-absolute ax-end-0 ax-flex ax-h-full ax-cursor-pointer ax-items-center ax-px-1 hover:ax-primary-lighter\"\n (click)=\"showMoreItems(); $event.stopPropagation()\"\n #moreButton\n >\n <i class=\"fa-light fa-ellipsis-vertical\"></i>\n </span>\n }\n</div>\n} @else {\n<div class=\"ax-flex ax-min-w-0 ax-items-center ax-gap-1\">\n @if (displayCount() > 0) {\n <span\n class=\"ax-cursor-pointer ax-text-primary hover:ax-underline\"\n (click)=\"openLazyPopover(); $event.stopPropagation()\"\n #lazyTrigger\n >\n {{ summaryLabel() }}\n </span>\n } @else {\n <span class=\"ax-text-muted\">---</span>\n }\n</div>\n}\n\n<ax-popover [openOn]=\"'manual'\" #morePopover (openChange)=\"onPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-min-w-[280px] ax-rounded-lg ax-border ax-p-4 ax-shadow-lg\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold\">{{ popoverHeader() }}</h3>\n </div>\n\n @if (!isHydratedStrategy() && resolveStatus() === 'loading') {\n <div class=\"ax-flex ax-min-h-[120px] ax-items-center ax-justify-center\">\n <ax-loading></ax-loading>\n </div>\n } @else if (!isHydratedStrategy() && resolveStatus() === 'error') {\n <div class=\"ax-text-danger ax-text-sm\">{{ resolveError() }}</div>\n } @else {\n <div class=\"ax-flex ax-max-h-64 ax-flex-col ax-gap-3\">\n @for (item of popoverListItems(); track $index) {\n @let label = getDisplayRaw(item);\n <span\n [class.ax-cursor-pointer]=\"!options['disableDetailPopover']\"\n [class.hover:ax-text-primary]=\"!options['disableDetailPopover']\"\n [class.hover:ax-underline]=\"!options['disableDetailPopover']\"\n (click)=\"handlePopoverItemClick($index)\"\n >\n {{ label }}\n </span>\n } @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n </div>\n }\n </div>\n</ax-popover>\n", dependencies: [{ kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "repositionOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
12667
13049
|
}
|
|
12668
13050
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetColumnComponent, decorators: [{
|
|
12669
13051
|
type: Component,
|
|
12670
|
-
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
12671
|
-
}], propDecorators: { moreButton: [{ type: i0.ViewChild, args: ['moreButton', { isSignal: true }] }], morePopover: [{ type: i0.ViewChild, args: ['morePopover', { isSignal: true }] }] } });
|
|
13052
|
+
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, imports: [AXLoadingModule, AXPopoverModule], inputs: ['rawValue', 'rowData'], template: "@if (isHydratedStrategy()) {\n<div class=\"ax-relative ax-flex ax-min-w-0 ax-items-center ax-gap-1\">\n @for (item of visibleItems(); track $index) {\n @let label = getDisplayRaw(item);\n <span\n [class.ax-cursor-pointer]=\"!options['disableDetailPopover']\"\n [class.hover:ax-text-primary]=\"!options['disableDetailPopover']\"\n [class.hover:ax-underline]=\"!options['disableDetailPopover']\"\n (click)=\"handleItemClick($index)\"\n >\n {{ label }}\n </span>\n @if ($index < visibleItems().length - 1) {\n <span class=\"ax-text-muted\">\u2022</span>\n }\n } @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n @if (hasMoreItems()) {\n <span\n class=\"ax-absolute ax-end-0 ax-flex ax-h-full ax-cursor-pointer ax-items-center ax-px-1 hover:ax-primary-lighter\"\n (click)=\"showMoreItems(); $event.stopPropagation()\"\n #moreButton\n >\n <i class=\"fa-light fa-ellipsis-vertical\"></i>\n </span>\n }\n</div>\n} @else {\n<div class=\"ax-flex ax-min-w-0 ax-items-center ax-gap-1\">\n @if (displayCount() > 0) {\n <span\n class=\"ax-cursor-pointer ax-text-primary hover:ax-underline\"\n (click)=\"openLazyPopover(); $event.stopPropagation()\"\n #lazyTrigger\n >\n {{ summaryLabel() }}\n </span>\n } @else {\n <span class=\"ax-text-muted\">---</span>\n }\n</div>\n}\n\n<ax-popover [openOn]=\"'manual'\" #morePopover (openChange)=\"onPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-min-w-[280px] ax-rounded-lg ax-border ax-p-4 ax-shadow-lg\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold\">{{ popoverHeader() }}</h3>\n </div>\n\n @if (!isHydratedStrategy() && resolveStatus() === 'loading') {\n <div class=\"ax-flex ax-min-h-[120px] ax-items-center ax-justify-center\">\n <ax-loading></ax-loading>\n </div>\n } @else if (!isHydratedStrategy() && resolveStatus() === 'error') {\n <div class=\"ax-text-danger ax-text-sm\">{{ resolveError() }}</div>\n } @else {\n <div class=\"ax-flex ax-max-h-64 ax-flex-col ax-gap-3\">\n @for (item of popoverListItems(); track $index) {\n @let label = getDisplayRaw(item);\n <span\n [class.ax-cursor-pointer]=\"!options['disableDetailPopover']\"\n [class.hover:ax-text-primary]=\"!options['disableDetailPopover']\"\n [class.hover:ax-underline]=\"!options['disableDetailPopover']\"\n (click)=\"handlePopoverItemClick($index)\"\n >\n {{ label }}\n </span>\n } @empty {\n <span class=\"ax-text-muted\">---</span>\n }\n </div>\n }\n </div>\n</ax-popover>\n" }]
|
|
13053
|
+
}], ctorParameters: () => [], propDecorators: { moreButton: [{ type: i0.ViewChild, args: ['moreButton', { isSignal: true }] }], lazyTrigger: [{ type: i0.ViewChild, args: ['lazyTrigger', { isSignal: true }] }], morePopover: [{ type: i0.ViewChild, args: ['morePopover', { isSignal: true }] }] } });
|
|
12672
13054
|
|
|
12673
13055
|
var lookupWidgetColumn_component = /*#__PURE__*/Object.freeze({
|
|
12674
13056
|
__proto__: null,
|
|
@@ -12730,6 +13112,100 @@ const AXPLookupWidget = {
|
|
|
12730
13112
|
},
|
|
12731
13113
|
visible: true,
|
|
12732
13114
|
},
|
|
13115
|
+
{
|
|
13116
|
+
name: 'columnResolveStrategy',
|
|
13117
|
+
title: 'Column resolve strategy',
|
|
13118
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
|
13119
|
+
schema: {
|
|
13120
|
+
dataType: 'string',
|
|
13121
|
+
defaultValue: 'hydrated',
|
|
13122
|
+
interface: {
|
|
13123
|
+
name: 'columnResolveStrategy',
|
|
13124
|
+
path: 'options.columnResolve.strategy',
|
|
13125
|
+
type: AXPWidgetsCatalog.select,
|
|
13126
|
+
valueTransforms: objectKeyValueTransforms('id'),
|
|
13127
|
+
options: {
|
|
13128
|
+
dataSource: [
|
|
13129
|
+
{ id: 'hydrated', title: 'Hydrated (titles on row)' },
|
|
13130
|
+
{ id: 'idsWithCount', title: 'Ids + count on row (load titles on open)' },
|
|
13131
|
+
{ id: 'countOnly', title: 'Count on row (named query on open)' },
|
|
13132
|
+
],
|
|
13133
|
+
},
|
|
13134
|
+
},
|
|
13135
|
+
},
|
|
13136
|
+
visible: true,
|
|
13137
|
+
},
|
|
13138
|
+
{
|
|
13139
|
+
name: 'columnResolveCountFieldPath',
|
|
13140
|
+
title: 'Column resolve — count field path',
|
|
13141
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
|
13142
|
+
schema: {
|
|
13143
|
+
dataType: 'string',
|
|
13144
|
+
interface: {
|
|
13145
|
+
name: 'columnResolveCountFieldPath',
|
|
13146
|
+
path: 'options.columnResolve.countFieldPath',
|
|
13147
|
+
type: AXPWidgetsCatalog.text,
|
|
13148
|
+
},
|
|
13149
|
+
},
|
|
13150
|
+
visible: true,
|
|
13151
|
+
},
|
|
13152
|
+
{
|
|
13153
|
+
name: 'columnResolveIdsPath',
|
|
13154
|
+
title: 'Column resolve — ids path',
|
|
13155
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
|
13156
|
+
schema: {
|
|
13157
|
+
dataType: 'string',
|
|
13158
|
+
interface: {
|
|
13159
|
+
name: 'columnResolveIdsPath',
|
|
13160
|
+
path: 'options.columnResolve.idsPath',
|
|
13161
|
+
type: AXPWidgetsCatalog.text,
|
|
13162
|
+
},
|
|
13163
|
+
},
|
|
13164
|
+
visible: true,
|
|
13165
|
+
},
|
|
13166
|
+
{
|
|
13167
|
+
name: 'columnResolveQueryKey',
|
|
13168
|
+
title: 'Column resolve — query key (countOnly)',
|
|
13169
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
|
13170
|
+
schema: {
|
|
13171
|
+
dataType: 'string',
|
|
13172
|
+
interface: {
|
|
13173
|
+
name: 'columnResolveQueryKey',
|
|
13174
|
+
path: 'options.columnResolve.queryKey',
|
|
13175
|
+
type: AXPWidgetsCatalog.text,
|
|
13176
|
+
},
|
|
13177
|
+
},
|
|
13178
|
+
visible: true,
|
|
13179
|
+
},
|
|
13180
|
+
{
|
|
13181
|
+
name: 'columnResolveQueryParams',
|
|
13182
|
+
title: 'Column resolve — query params (JSON: param → row path)',
|
|
13183
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
|
13184
|
+
schema: {
|
|
13185
|
+
dataType: 'string',
|
|
13186
|
+
interface: {
|
|
13187
|
+
name: 'columnResolveQueryParams',
|
|
13188
|
+
path: 'options.columnResolve.queryParams',
|
|
13189
|
+
type: AXPWidgetsCatalog.text,
|
|
13190
|
+
},
|
|
13191
|
+
},
|
|
13192
|
+
visible: true,
|
|
13193
|
+
},
|
|
13194
|
+
{
|
|
13195
|
+
name: 'columnResolveQueryResultItemsPath',
|
|
13196
|
+
title: 'Column resolve — query result items path',
|
|
13197
|
+
group: AXP_DATA_PROPERTY_GROUP,
|
|
13198
|
+
schema: {
|
|
13199
|
+
dataType: 'string',
|
|
13200
|
+
defaultValue: 'items',
|
|
13201
|
+
interface: {
|
|
13202
|
+
name: 'columnResolveQueryResultItemsPath',
|
|
13203
|
+
path: 'options.columnResolve.queryResultItemsPath',
|
|
13204
|
+
type: AXPWidgetsCatalog.text,
|
|
13205
|
+
},
|
|
13206
|
+
},
|
|
13207
|
+
visible: true,
|
|
13208
|
+
},
|
|
12733
13209
|
],
|
|
12734
13210
|
components: {
|
|
12735
13211
|
view: {
|
|
@@ -12747,6 +13223,8 @@ const AXPLookupWidget = {
|
|
|
12747
13223
|
},
|
|
12748
13224
|
};
|
|
12749
13225
|
|
|
13226
|
+
//#endregion
|
|
13227
|
+
|
|
12750
13228
|
/**
|
|
12751
13229
|
* Source type
|
|
12752
13230
|
*/
|
|
@@ -15336,13 +15814,18 @@ class AXPDetailsViewBadgeStatusService {
|
|
|
15336
15814
|
if (!entityDefinition) {
|
|
15337
15815
|
return null;
|
|
15338
15816
|
}
|
|
15339
|
-
const
|
|
15340
|
-
if (
|
|
15817
|
+
const statusPlugins = (entityDefinition.plugins ?? []).filter((p) => p.name === 'status');
|
|
15818
|
+
if (statusPlugins.length === 0) {
|
|
15341
15819
|
return null;
|
|
15342
15820
|
}
|
|
15343
|
-
const
|
|
15821
|
+
const explicitPrimary = statusPlugins.find((p) => p.options?.isPrimary === true);
|
|
15822
|
+
const primaryPlugin = explicitPrimary ??
|
|
15823
|
+
statusPlugins.find((p) => p.options?.isPrimary !== false) ??
|
|
15824
|
+
statusPlugins[0];
|
|
15825
|
+
const statusOptions = primaryPlugin.options;
|
|
15344
15826
|
const statusField = statusOptions.field ?? 'statusId';
|
|
15345
15827
|
const statusDefinitionKey = statusOptions.definition;
|
|
15828
|
+
const pluginReadonly = statusOptions.readonly === true;
|
|
15346
15829
|
let definitionKey = typeof statusDefinitionKey === 'string' ? statusDefinitionKey : undefined;
|
|
15347
15830
|
if (!definitionKey) {
|
|
15348
15831
|
const statusProperty = entityDefinition.properties?.find((p) => p.name === statusField);
|
|
@@ -15363,7 +15846,7 @@ class AXPDetailsViewBadgeStatusService {
|
|
|
15363
15846
|
definitionKey,
|
|
15364
15847
|
value: String(value),
|
|
15365
15848
|
dataPath: statusField,
|
|
15366
|
-
readonly: currentPage?.isReadonly ?? false,
|
|
15849
|
+
readonly: pluginReadonly || (currentPage?.isReadonly ?? false),
|
|
15367
15850
|
};
|
|
15368
15851
|
}
|
|
15369
15852
|
catch (error) {
|
|
@@ -15546,34 +16029,35 @@ class AXPBaseRelatedEntityConverter {
|
|
|
15546
16029
|
groups,
|
|
15547
16030
|
};
|
|
15548
16031
|
}
|
|
15549
|
-
|
|
15550
|
-
return
|
|
16032
|
+
createGridLayoutStructure(singleInterface, helpers, includeProperties) {
|
|
16033
|
+
return this.createGridLayoutStructureInternal(singleInterface, helpers, includeProperties);
|
|
15551
16034
|
}
|
|
15552
|
-
//#region ----
|
|
15553
|
-
|
|
16035
|
+
//#region ---- Property visibility (layout) ----
|
|
16036
|
+
/**
|
|
16037
|
+
* Chooses which properties appear in the related-entity grid layout.
|
|
16038
|
+
* Boolean `schema.visible === false` excludes a property. String templates are kept in the layout
|
|
16039
|
+
* and passed on `form-field.options.visible`; `AXPWidgetRendererDirective` uses
|
|
16040
|
+
* `AXPExpressionEvaluatorService` in `updateVisibility()` to evaluate them when context updates.
|
|
16041
|
+
*/
|
|
16042
|
+
getVisiblePropertiesByGroupId(sectionId, helpers, includeProperties) {
|
|
15554
16043
|
let properties = helpers.getPropertyByGroupId(sectionId) ?? [];
|
|
15555
16044
|
// Filter by includeProperties if provided
|
|
15556
16045
|
if (includeProperties && includeProperties.length > 0) {
|
|
15557
16046
|
const includeSet = new Set(includeProperties);
|
|
15558
16047
|
properties = properties.filter((p) => includeSet.has(p.name));
|
|
15559
16048
|
}
|
|
15560
|
-
const evaluated =
|
|
15561
|
-
|
|
15562
|
-
if (typeof visible === 'string'
|
|
15563
|
-
|
|
15564
|
-
|
|
15565
|
-
visible = result.visible;
|
|
15566
|
-
}
|
|
15567
|
-
catch {
|
|
15568
|
-
visible = true;
|
|
15569
|
-
}
|
|
16049
|
+
const evaluated = properties.map((property) => {
|
|
16050
|
+
const visible = property?.schema?.visible;
|
|
16051
|
+
if (typeof visible === 'string') {
|
|
16052
|
+
// Include in layout; runtime evaluation via `AXPExpressionEvaluatorService` (widget renderer).
|
|
16053
|
+
return { property, visible: true };
|
|
15570
16054
|
}
|
|
15571
16055
|
return { property, visible: visible ?? true };
|
|
15572
|
-
})
|
|
16056
|
+
});
|
|
15573
16057
|
return evaluated.filter((x) => x.visible !== false).map((x) => x.property);
|
|
15574
16058
|
}
|
|
15575
|
-
|
|
15576
|
-
const visibleProperties =
|
|
16059
|
+
createPropertyGrid(sectionId, helpers, includeProperties) {
|
|
16060
|
+
const visibleProperties = this.getVisiblePropertiesByGroupId(sectionId, helpers, includeProperties);
|
|
15577
16061
|
return {
|
|
15578
16062
|
type: 'grid-layout',
|
|
15579
16063
|
mode: 'edit',
|
|
@@ -15588,6 +16072,15 @@ class AXPBaseRelatedEntityConverter {
|
|
|
15588
16072
|
},
|
|
15589
16073
|
children: visibleProperties.map((p) => {
|
|
15590
16074
|
const layout = helpers.getPropertyLayout(p.name);
|
|
16075
|
+
const sv = p.schema?.visible;
|
|
16076
|
+
let formFieldVisible;
|
|
16077
|
+
if (typeof sv === 'string') {
|
|
16078
|
+
// Evaluated by `AXPExpressionEvaluatorService` in `AXPWidgetRendererDirective.updateVisibility()`.
|
|
16079
|
+
formFieldVisible = sv;
|
|
16080
|
+
}
|
|
16081
|
+
else if (sv === false) {
|
|
16082
|
+
formFieldVisible = false;
|
|
16083
|
+
}
|
|
15591
16084
|
return {
|
|
15592
16085
|
type: 'grid-item-layout',
|
|
15593
16086
|
name: p.name,
|
|
@@ -15602,6 +16095,8 @@ class AXPBaseRelatedEntityConverter {
|
|
|
15602
16095
|
options: {
|
|
15603
16096
|
label: p.title,
|
|
15604
16097
|
showLabel: layout?.label?.visible ?? true,
|
|
16098
|
+
...(formFieldVisible !== undefined ? { visible: formFieldVisible } : {}),
|
|
16099
|
+
...(hintFormFieldOptionsFromDescription(p.description) ?? {}),
|
|
15605
16100
|
},
|
|
15606
16101
|
children: [
|
|
15607
16102
|
{
|
|
@@ -15621,13 +16116,15 @@ class AXPBaseRelatedEntityConverter {
|
|
|
15621
16116
|
}),
|
|
15622
16117
|
};
|
|
15623
16118
|
}
|
|
15624
|
-
|
|
16119
|
+
createGridLayoutStructureInternal(singleInterface, helpers, includeProperties) {
|
|
15625
16120
|
// Filter out empty sections (sections with no visible properties)
|
|
15626
|
-
const sectionsWithProperties =
|
|
15627
|
-
const visibleProperties =
|
|
16121
|
+
const sectionsWithProperties = (singleInterface?.sections ?? []).map((s) => {
|
|
16122
|
+
const visibleProperties = this.getVisiblePropertiesByGroupId(s.id, helpers, includeProperties);
|
|
15628
16123
|
return { section: s, hasProperties: visibleProperties.length > 0 };
|
|
15629
|
-
})
|
|
15630
|
-
const validSections = sectionsWithProperties
|
|
16124
|
+
});
|
|
16125
|
+
const validSections = sectionsWithProperties
|
|
16126
|
+
.filter((item) => item.hasProperties)
|
|
16127
|
+
.map((item) => item.section);
|
|
15631
16128
|
return {
|
|
15632
16129
|
type: 'grid-layout',
|
|
15633
16130
|
options: {
|
|
@@ -15639,7 +16136,7 @@ class AXPBaseRelatedEntityConverter {
|
|
|
15639
16136
|
},
|
|
15640
16137
|
},
|
|
15641
16138
|
},
|
|
15642
|
-
children:
|
|
16139
|
+
children: validSections.map((s) => ({
|
|
15643
16140
|
type: 'grid-item-layout',
|
|
15644
16141
|
name: s.id,
|
|
15645
16142
|
options: {
|
|
@@ -15653,11 +16150,12 @@ class AXPBaseRelatedEntityConverter {
|
|
|
15653
16150
|
options: {
|
|
15654
16151
|
title: helpers.getGroupById(s.id)?.title ?? '',
|
|
15655
16152
|
collapsible: true,
|
|
16153
|
+
showTitle: s.layout?.label?.visible ?? true,
|
|
15656
16154
|
},
|
|
15657
|
-
children: [
|
|
16155
|
+
children: [this.createPropertyGrid(s.id, helpers, includeProperties)],
|
|
15658
16156
|
},
|
|
15659
16157
|
],
|
|
15660
|
-
}))
|
|
16158
|
+
})),
|
|
15661
16159
|
};
|
|
15662
16160
|
}
|
|
15663
16161
|
}
|
|
@@ -15860,7 +16358,7 @@ class AXPPageDetailsConverter extends AXPBaseRelatedEntityConverter {
|
|
|
15860
16358
|
execute: this.createExecuteFunction(entityDef, actions, evaluateExpressions, context),
|
|
15861
16359
|
actions: await this.buildEvaluatedActions(actions, evaluateExpressions),
|
|
15862
16360
|
// tabs: [...tabDetailTabs, ...tabListTabs],
|
|
15863
|
-
content: [
|
|
16361
|
+
content: [this.createGridLayoutStructure(helpers.singleInterface, helpers, relatedEntity.properties)],
|
|
15864
16362
|
};
|
|
15865
16363
|
}
|
|
15866
16364
|
//#region ---- Utility Methods ----
|
|
@@ -16252,6 +16750,7 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
|
|
|
16252
16750
|
includeColumns,
|
|
16253
16751
|
relatedTableColumns,
|
|
16254
16752
|
customFilterDefinitions: relatedEntity.customFilterDefinitions,
|
|
16753
|
+
excludeProperties: relatedEntity.excludeProperties,
|
|
16255
16754
|
},
|
|
16256
16755
|
},
|
|
16257
16756
|
],
|
|
@@ -16310,7 +16809,7 @@ class AXPTabDetailsConverter extends AXPBaseRelatedEntityConverter {
|
|
|
16310
16809
|
title: relatedEntity.title ?? entityDef?.title ?? '',
|
|
16311
16810
|
icon: relatedEntity.icon || entityDef.icon,
|
|
16312
16811
|
content: [
|
|
16313
|
-
|
|
16812
|
+
this.createGridLayoutStructure(helpers.singleInterface, helpers, relatedEntity.properties),
|
|
16314
16813
|
],
|
|
16315
16814
|
};
|
|
16316
16815
|
}
|
|
@@ -16370,6 +16869,7 @@ class AXPTabListConverter extends AXPBaseRelatedEntityConverter {
|
|
|
16370
16869
|
includeColumns,
|
|
16371
16870
|
relatedTableColumns,
|
|
16372
16871
|
customFilterDefinitions: relatedEntity.customFilterDefinitions,
|
|
16872
|
+
excludeProperties: relatedEntity.excludeProperties,
|
|
16373
16873
|
},
|
|
16374
16874
|
},
|
|
16375
16875
|
],
|
|
@@ -16866,20 +17366,18 @@ class AXPMainEntityContentBuilder {
|
|
|
16866
17366
|
const visibleInRelated = isFromRelated ? !!p.__layout : false;
|
|
16867
17367
|
return visibleInMain || visibleInRelated;
|
|
16868
17368
|
});
|
|
16869
|
-
|
|
16870
|
-
|
|
16871
|
-
|
|
16872
|
-
|
|
16873
|
-
|
|
16874
|
-
|
|
16875
|
-
|
|
16876
|
-
|
|
16877
|
-
|
|
16878
|
-
}
|
|
17369
|
+
// String `schema.visible` is not evaluated here (no `dependencies.expressionEvaluator` call).
|
|
17370
|
+
// The template is placed on `form-field.options.visible` below; at render time
|
|
17371
|
+
// `AXPWidgetRendererDirective` injects `AXPExpressionEvaluatorService` and evaluates it in
|
|
17372
|
+
// `updateVisibility()` (and on context changes via `hasVisibilityDependency`). Evaluating once
|
|
17373
|
+
// at build time would freeze visibility and break detail/edit when data changes.
|
|
17374
|
+
const visibilityEvaluated = inView.map((p) => {
|
|
17375
|
+
const v = p.schema?.visible;
|
|
17376
|
+
if (typeof v === 'string') {
|
|
17377
|
+
return { property: p, resolvedVisible: true };
|
|
16879
17378
|
}
|
|
16880
|
-
|
|
16881
|
-
|
|
16882
|
-
}));
|
|
17379
|
+
return { property: p, resolvedVisible: v !== false };
|
|
17380
|
+
});
|
|
16883
17381
|
const visibleProperties = visibilityEvaluated
|
|
16884
17382
|
.filter((x) => x.resolvedVisible)
|
|
16885
17383
|
.map((x) => x.property);
|
|
@@ -16903,6 +17401,7 @@ class AXPMainEntityContentBuilder {
|
|
|
16903
17401
|
collapsible: true,
|
|
16904
17402
|
isOpen: !s.collapsed,
|
|
16905
17403
|
look: 'card',
|
|
17404
|
+
showTitle: s.layout?.label?.visible !== false,
|
|
16906
17405
|
},
|
|
16907
17406
|
children: [
|
|
16908
17407
|
{
|
|
@@ -16927,8 +17426,9 @@ class AXPMainEntityContentBuilder {
|
|
|
16927
17426
|
const hasOwnDisabled = p.schema.interface?.options?.disabled !== undefined;
|
|
16928
17427
|
let formFieldVisible;
|
|
16929
17428
|
const sv = p.schema?.visible;
|
|
17429
|
+
// Template strings are evaluated by `AXPExpressionEvaluatorService` in the widget renderer, not here.
|
|
16930
17430
|
if (typeof sv === 'string') {
|
|
16931
|
-
formFieldVisible =
|
|
17431
|
+
formFieldVisible = sv;
|
|
16932
17432
|
}
|
|
16933
17433
|
else if (sv === false) {
|
|
16934
17434
|
formFieldVisible = false;
|
|
@@ -16945,6 +17445,7 @@ class AXPMainEntityContentBuilder {
|
|
|
16945
17445
|
rowStart: layout?.positions?.lg?.rowStart,
|
|
16946
17446
|
rowEnd: layout?.positions?.lg?.rowEnd,
|
|
16947
17447
|
...(formFieldVisible !== undefined ? { visible: formFieldVisible } : {}),
|
|
17448
|
+
...(hintFormFieldOptionsFromDescription(p.description) ?? {}),
|
|
16948
17449
|
},
|
|
16949
17450
|
children: [
|
|
16950
17451
|
{
|