@acorex/platform 21.0.0-next.59 → 21.0.0-next.64
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 +131 -1
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +208 -21
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +497 -123
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +7 -6
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +87 -16
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs +2682 -2271
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-default.mjs +48 -15
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-shared.mjs +31 -46
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/package.json +1 -1
- package/types/acorex-platform-common.d.ts +25 -7
- package/types/acorex-platform-layout-components.d.ts +57 -3
- package/types/acorex-platform-layout-entity.d.ts +132 -51
- package/types/acorex-platform-layout-views.d.ts +2 -1
- package/types/acorex-platform-layout-widget-core.d.ts +12 -3
- package/types/acorex-platform-layout-widgets.d.ts +132 -43
- package/types/acorex-platform-themes-default.d.ts +4 -1
|
@@ -21,12 +21,12 @@ import * as i4 from '@acorex/components/skeleton';
|
|
|
21
21
|
import { AXSkeletonModule } from '@acorex/components/skeleton';
|
|
22
22
|
import * as i2 from '@acorex/components/popover';
|
|
23
23
|
import { AXPopoverModule } from '@acorex/components/popover';
|
|
24
|
+
import { AXFormatService } from '@acorex/core/format';
|
|
24
25
|
import * as i5 from '@angular/common';
|
|
25
26
|
import { CommonModule, AsyncPipe } from '@angular/common';
|
|
26
27
|
import { AXPThemeLayoutBlockComponent, AXPPreloadFiltersComponent, AXPStateMessageComponent, AXPColumnItemListComponent, AXPDataSelectorService, AXPPageComponentRegistryService } from '@acorex/platform/layout/components';
|
|
27
28
|
import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageComponentInstanceRegistryService } from '@acorex/platform/layout/views';
|
|
28
29
|
import { AXDataSource } from '@acorex/cdk/common';
|
|
29
|
-
import { AXFormatService } from '@acorex/core/format';
|
|
30
30
|
import * as i1$3 from '@acorex/platform/workflow';
|
|
31
31
|
import { AXPWorkflowService, ofType, createWorkFlowEvent, AXPWorkflowAction, AXPWorkflowEventService, AXPWorkflowModule } from '@acorex/platform/workflow';
|
|
32
32
|
import { AXPLayoutThemeService } from '@acorex/platform/themes/shared';
|
|
@@ -2845,17 +2845,119 @@ var viewEntityDetails_command = /*#__PURE__*/Object.freeze({
|
|
|
2845
2845
|
AXPViewEntityDetailsCommand: AXPViewEntityDetailsCommand
|
|
2846
2846
|
});
|
|
2847
2847
|
|
|
2848
|
+
//#region ---- Template resolution ----
|
|
2849
|
+
/**
|
|
2850
|
+
* Normalizes lookup/search display templates for row-based formatting.
|
|
2851
|
+
* Converts `context.eval('path')` expressions to `{{ path }}` and single braces to mustache form.
|
|
2852
|
+
*/
|
|
2853
|
+
function normalizeLookupDisplayTemplate(template) {
|
|
2854
|
+
const withContextEval = template.replace(/\{\{\s*context\.eval\(['"]([^'"]+)['"]\)\s*\}\}/g, '{{ $1 }}');
|
|
2855
|
+
if (withContextEval.includes('{{')) {
|
|
2856
|
+
return withContextEval;
|
|
2857
|
+
}
|
|
2858
|
+
return withContextEval.replace(/\{/g, '{{').replace(/\}/g, '}}');
|
|
2859
|
+
}
|
|
2860
|
+
/**
|
|
2861
|
+
* Resolves the display template for a lookup item.
|
|
2862
|
+
* Priority: explicit `displayFormat` → entity `formats.lookup` (template) → entity `formats.searchResult.title`.
|
|
2863
|
+
* Returns undefined when `textField` is set or no template applies (use {@link resolveLookupDisplayField} instead).
|
|
2864
|
+
*/
|
|
2865
|
+
function resolveLookupDisplayTemplate(entity, options) {
|
|
2866
|
+
const explicit = options.displayFormat?.trim();
|
|
2867
|
+
if (explicit) {
|
|
2868
|
+
return normalizeLookupDisplayTemplate(explicit);
|
|
2869
|
+
}
|
|
2870
|
+
if (options.textField?.trim()) {
|
|
2871
|
+
return undefined;
|
|
2872
|
+
}
|
|
2873
|
+
const lookupFormat = entity?.formats?.lookup?.trim();
|
|
2874
|
+
if (lookupFormat && (lookupFormat.includes('{{') || lookupFormat.includes('{'))) {
|
|
2875
|
+
return normalizeLookupDisplayTemplate(lookupFormat);
|
|
2876
|
+
}
|
|
2877
|
+
const searchTitle = entity?.formats?.searchResult?.title?.trim();
|
|
2878
|
+
if (searchTitle) {
|
|
2879
|
+
return normalizeLookupDisplayTemplate(searchTitle);
|
|
2880
|
+
}
|
|
2881
|
+
return undefined;
|
|
2882
|
+
}
|
|
2883
|
+
/**
|
|
2884
|
+
* Resolves the property path used for lookup display when no template applies.
|
|
2885
|
+
* Priority: explicit `textField` → entity `formats.lookup` (simple path) → common property names.
|
|
2886
|
+
*/
|
|
2887
|
+
function resolveLookupDisplayField(entity, options) {
|
|
2888
|
+
if (options.textField?.trim()) {
|
|
2889
|
+
return options.textField.trim();
|
|
2890
|
+
}
|
|
2891
|
+
const lookupFormat = entity?.formats?.lookup?.trim();
|
|
2892
|
+
if (lookupFormat && !lookupFormat.includes('{') && !lookupFormat.includes('{{')) {
|
|
2893
|
+
return lookupFormat;
|
|
2894
|
+
}
|
|
2895
|
+
const defaults = ['title', 'name', 'code', 'description'];
|
|
2896
|
+
const found = defaults.find((name) => entity?.properties?.some((p) => p.name === name));
|
|
2897
|
+
return found ?? 'title';
|
|
2898
|
+
}
|
|
2899
|
+
/**
|
|
2900
|
+
* Formats a lookup row for display using template and/or field resolution.
|
|
2901
|
+
*/
|
|
2902
|
+
function formatLookupItemDisplay(item, entity, options, formatService, resolveMultiLanguage) {
|
|
2903
|
+
if (item == null) {
|
|
2904
|
+
return '';
|
|
2905
|
+
}
|
|
2906
|
+
if (typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean') {
|
|
2907
|
+
return String(item);
|
|
2908
|
+
}
|
|
2909
|
+
if (typeof item !== 'object') {
|
|
2910
|
+
return '';
|
|
2911
|
+
}
|
|
2912
|
+
if (options.isMultiLanguage?.(item) && resolveMultiLanguage) {
|
|
2913
|
+
return resolveMultiLanguage(item);
|
|
2914
|
+
}
|
|
2915
|
+
const template = resolveLookupDisplayTemplate(entity, options);
|
|
2916
|
+
if (template) {
|
|
2917
|
+
const formatted = formatService.format(template, 'string', item);
|
|
2918
|
+
if (formatted) {
|
|
2919
|
+
const text = String(formatted);
|
|
2920
|
+
if (!isUnresolvedLookupDisplayTemplate(text)) {
|
|
2921
|
+
return text;
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
const field = resolveLookupDisplayField(entity, options);
|
|
2926
|
+
const raw = get(item, field);
|
|
2927
|
+
if (raw == null) {
|
|
2928
|
+
return '';
|
|
2929
|
+
}
|
|
2930
|
+
if (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') {
|
|
2931
|
+
return String(raw);
|
|
2932
|
+
}
|
|
2933
|
+
if (typeof raw === 'object' && !Array.isArray(raw)) {
|
|
2934
|
+
if (resolveMultiLanguage) {
|
|
2935
|
+
return resolveMultiLanguage(raw);
|
|
2936
|
+
}
|
|
2937
|
+
return raw;
|
|
2938
|
+
}
|
|
2939
|
+
return String(raw);
|
|
2940
|
+
}
|
|
2941
|
+
/** True when a formatted label still contains unresolved template markers. */
|
|
2942
|
+
function isUnresolvedLookupDisplayTemplate(value) {
|
|
2943
|
+
return /\{\{/.test(value) || /context\.eval\s*\(/.test(value);
|
|
2944
|
+
}
|
|
2945
|
+
//#endregion
|
|
2946
|
+
|
|
2848
2947
|
class AXPEntityDetailPopoverComponent {
|
|
2849
2948
|
constructor() {
|
|
2850
2949
|
//#region ---- Dependencies ----
|
|
2851
2950
|
this.commandService = inject(AXPCommandService);
|
|
2852
2951
|
this.queryService = inject(AXPQueryService);
|
|
2952
|
+
this.formatService = inject(AXFormatService);
|
|
2953
|
+
this.translation = inject(AXTranslationService);
|
|
2853
2954
|
//#endregion
|
|
2854
2955
|
//#region ---- Inputs ----
|
|
2855
2956
|
this.entity = input.required(...(ngDevMode ? [{ debugName: "entity" }] : /* istanbul ignore next */ []));
|
|
2856
2957
|
this.entityId = input.required(...(ngDevMode ? [{ debugName: "entityId" }] : /* istanbul ignore next */ []));
|
|
2857
2958
|
this.textField = input('title', ...(ngDevMode ? [{ debugName: "textField" }] : /* istanbul ignore next */ []));
|
|
2858
2959
|
this.valueField = input('id', ...(ngDevMode ? [{ debugName: "valueField" }] : /* istanbul ignore next */ []));
|
|
2960
|
+
this.displayTitle = input('', ...(ngDevMode ? [{ debugName: "displayTitle" }] : /* istanbul ignore next */ []));
|
|
2859
2961
|
this.item = input(...(ngDevMode ? [undefined, { debugName: "item" }] : /* istanbul ignore next */ []));
|
|
2860
2962
|
this.breadcrumb = input(null, ...(ngDevMode ? [{ debugName: "breadcrumb" }] : /* istanbul ignore next */ []));
|
|
2861
2963
|
//#endregion
|
|
@@ -2868,6 +2970,29 @@ class AXPEntityDetailPopoverComponent {
|
|
|
2868
2970
|
this.isDetailPopoverOpen = signal(false, ...(ngDevMode ? [{ debugName: "isDetailPopoverOpen" }] : /* istanbul ignore next */ []));
|
|
2869
2971
|
/** Placeholder rows for the loading skeleton (matches typical property count). */
|
|
2870
2972
|
this.loadingSkeletonRows = [1, 2, 3, 4, 5];
|
|
2973
|
+
this.headerTitle = computed(() => {
|
|
2974
|
+
const details = this.entityDetails();
|
|
2975
|
+
const entityDefinition = details?.entityDefinition;
|
|
2976
|
+
const data = details?.entityData;
|
|
2977
|
+
if (data && entityDefinition) {
|
|
2978
|
+
const fromDetails = this.resolveLookupDisplayLabel(data, entityDefinition);
|
|
2979
|
+
if (fromDetails) {
|
|
2980
|
+
return fromDetails;
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
const preset = this.displayTitle()?.trim();
|
|
2984
|
+
if (preset && !isUnresolvedLookupDisplayTemplate(preset)) {
|
|
2985
|
+
return preset;
|
|
2986
|
+
}
|
|
2987
|
+
const fallbackItem = this.item();
|
|
2988
|
+
if (fallbackItem) {
|
|
2989
|
+
const fromItem = this.resolveLookupDisplayLabel(fallbackItem, entityDefinition);
|
|
2990
|
+
if (fromItem) {
|
|
2991
|
+
return fromItem;
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
return preset ?? '';
|
|
2995
|
+
}, ...(ngDevMode ? [{ debugName: "headerTitle" }] : /* istanbul ignore next */ []));
|
|
2871
2996
|
/**
|
|
2872
2997
|
* Stable list of property widgets for the template. Must be a signal (computed), not a method:
|
|
2873
2998
|
* calling a method from the template rebuilds nodes every CD cycle and can make the widget renderer loop.
|
|
@@ -2952,6 +3077,11 @@ class AXPEntityDetailPopoverComponent {
|
|
|
2952
3077
|
}
|
|
2953
3078
|
//#endregion
|
|
2954
3079
|
//#region ---- Helper Methods ----
|
|
3080
|
+
resolveLookupDisplayLabel(item, entityDefinition) {
|
|
3081
|
+
const label = formatLookupItemDisplay(item, entityDefinition, { textField: this.textField() }, this.formatService, (value) => this.translation.resolve(value));
|
|
3082
|
+
const resolved = typeof label === 'string' ? label : this.translation.resolve(label);
|
|
3083
|
+
return resolved && !isUnresolvedLookupDisplayTemplate(resolved) ? resolved : '';
|
|
3084
|
+
}
|
|
2955
3085
|
/**
|
|
2956
3086
|
* Returns true if a value is meaningful for display (non-empty/non-null).
|
|
2957
3087
|
*/
|
|
@@ -3129,12 +3259,12 @@ class AXPEntityDetailPopoverComponent {
|
|
|
3129
3259
|
return prop.name;
|
|
3130
3260
|
}
|
|
3131
3261
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailPopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3132
|
-
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
|
|
3262
|
+
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 }, displayTitle: { classPropertyName: "displayTitle", publicName: "displayTitle", 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-p-4 ax-w-[min(600px,calc(100vw-2rem))]\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold ax-text-on-lightest-surface\">\n {{ headerTitle() }}\n </h3>\n @if (breadcrumb()) {\n <div class=\"ax-text-xs ax-text-neutral-500 ax-mt-1\">{{ breadcrumb() }}</div>\n }\n </div>\n @if (isLoadingDetails()) {\n <div class=\"ax-space-y-2 ax-mb-4\">\n @for (row of loadingSkeletonRows; track row) {\n <div class=\"ax-grid ax-grid-cols-[minmax(7rem,35%)_1fr] ax-gap-x-4 ax-items-start\">\n <ax-skeleton [animated]=\"true\" class=\"ax-h-4 ax-w-2/3 ax-rounded\"></ax-skeleton>\n @if (row === 2) {\n <ax-skeleton [animated]=\"true\" class=\"ax-h-16 ax-w-full ax-rounded\"></ax-skeleton>\n } @else {\n <ax-skeleton [animated]=\"true\" class=\"ax-h-4 ax-w-full ax-rounded\"></ax-skeleton>\n }\n </div>\n }\n </div>\n <div class=\"ax-flex ax-justify-end\">\n <ax-skeleton [animated]=\"true\" class=\"ax-h-9 ax-w-28 ax-rounded\"></ax-skeleton>\n </div>\n } @else if (entityDetails()) {\n <div class=\"ax-space-y-3 ax-mb-4\">\n <!-- 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-grid ax-grid-cols-[minmax(7rem,35%)_1fr] ax-gap-x-4 ax-gap-y-1 ax-items-start\">\n <span class=\"ax-text-sm ax-font-medium ax-text-neutral-600 ax-shrink-0\">{{ item.title | translate | async\n }}:</span>\n <div class=\"ax-min-w-0 ax-text-sm\">\n <ng-container axp-widget-renderer [node]=\"item.node\" [mode]=\"'view'\"></ng-container>\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n }\n </div>\n <div class=\"ax-flex ax-gap-2 ax-justify-end ax-sm\">\n <ax-button [color]=\"'primary'\" [look]=\"'solid'\" [text]=\"'@general:actions.open-details.title' | translate | async\"\n (click)=\"navigateToDetails()\">\n </ax-button>\n </div>\n }\n </div>\n</ax-popover>", 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", "closeOnScroll", "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: AXSkeletonModule }, { kind: "component", type: i4.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3133
3263
|
}
|
|
3134
3264
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityDetailPopoverComponent, decorators: [{
|
|
3135
3265
|
type: Component,
|
|
3136
|
-
args: [{ selector: 'axp-entity-detail-popover', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, AXButtonModule, AXPopoverModule, AXPWidgetCoreModule, AXTranslationModule, AXSkeletonModule], template: "<ax-popover [openOn]=\"'manual'\" #detailPopover (openChange)=\"onDetailPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface
|
|
3137
|
-
}], 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 }] }] } });
|
|
3266
|
+
args: [{ selector: 'axp-entity-detail-popover', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, AXButtonModule, AXPopoverModule, AXPWidgetCoreModule, AXTranslationModule, AXSkeletonModule], template: "<ax-popover [openOn]=\"'manual'\" #detailPopover (openChange)=\"onDetailPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-p-4 ax-w-[min(600px,calc(100vw-2rem))]\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold ax-text-on-lightest-surface\">\n {{ headerTitle() }}\n </h3>\n @if (breadcrumb()) {\n <div class=\"ax-text-xs ax-text-neutral-500 ax-mt-1\">{{ breadcrumb() }}</div>\n }\n </div>\n @if (isLoadingDetails()) {\n <div class=\"ax-space-y-2 ax-mb-4\">\n @for (row of loadingSkeletonRows; track row) {\n <div class=\"ax-grid ax-grid-cols-[minmax(7rem,35%)_1fr] ax-gap-x-4 ax-items-start\">\n <ax-skeleton [animated]=\"true\" class=\"ax-h-4 ax-w-2/3 ax-rounded\"></ax-skeleton>\n @if (row === 2) {\n <ax-skeleton [animated]=\"true\" class=\"ax-h-16 ax-w-full ax-rounded\"></ax-skeleton>\n } @else {\n <ax-skeleton [animated]=\"true\" class=\"ax-h-4 ax-w-full ax-rounded\"></ax-skeleton>\n }\n </div>\n }\n </div>\n <div class=\"ax-flex ax-justify-end\">\n <ax-skeleton [animated]=\"true\" class=\"ax-h-9 ax-w-28 ax-rounded\"></ax-skeleton>\n </div>\n } @else if (entityDetails()) {\n <div class=\"ax-space-y-3 ax-mb-4\">\n <!-- 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-grid ax-grid-cols-[minmax(7rem,35%)_1fr] ax-gap-x-4 ax-gap-y-1 ax-items-start\">\n <span class=\"ax-text-sm ax-font-medium ax-text-neutral-600 ax-shrink-0\">{{ item.title | translate | async\n }}:</span>\n <div class=\"ax-min-w-0 ax-text-sm\">\n <ng-container axp-widget-renderer [node]=\"item.node\" [mode]=\"'view'\"></ng-container>\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n }\n </div>\n <div class=\"ax-flex ax-gap-2 ax-justify-end ax-sm\">\n <ax-button [color]=\"'primary'\" [look]=\"'solid'\" [text]=\"'@general:actions.open-details.title' | translate | async\"\n (click)=\"navigateToDetails()\">\n </ax-button>\n </div>\n }\n </div>\n</ax-popover>" }]
|
|
3267
|
+
}], propDecorators: { entity: [{ type: i0.Input, args: [{ isSignal: true, alias: "entity", required: true }] }], entityId: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityId", required: true }] }], textField: [{ type: i0.Input, args: [{ isSignal: true, alias: "textField", required: false }] }], valueField: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueField", required: false }] }], displayTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayTitle", required: false }] }], item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: false }] }], breadcrumb: [{ type: i0.Input, args: [{ isSignal: true, alias: "breadcrumb", required: false }] }], detailPopover: [{ type: i0.ViewChild, args: ['detailPopover', { isSignal: true }] }] } });
|
|
3138
3268
|
|
|
3139
3269
|
class AXPEntityDetailPopoverService {
|
|
3140
3270
|
constructor() {
|
|
@@ -3164,6 +3294,7 @@ class AXPEntityDetailPopoverService {
|
|
|
3164
3294
|
this.activePopoverRef.setInput('entityId', options.id);
|
|
3165
3295
|
this.activePopoverRef.setInput('textField', options.textField || 'title');
|
|
3166
3296
|
this.activePopoverRef.setInput('valueField', options.valueField || 'id');
|
|
3297
|
+
this.activePopoverRef.setInput('displayTitle', options.displayTitle ?? '');
|
|
3167
3298
|
this.activePopoverRef.setInput('breadcrumb', options.breadcrumb || null);
|
|
3168
3299
|
this.activePopoverRef.setInput('item', options.item);
|
|
3169
3300
|
// Attach to application
|
|
@@ -3964,7 +4095,6 @@ class AXPEntityListViewColumnViewModel {
|
|
|
3964
4095
|
this.name = this.property.name;
|
|
3965
4096
|
this.title = this.column.title ?? this.property.title;
|
|
3966
4097
|
this.visible = this.column?.options?.visible ?? true;
|
|
3967
|
-
this.dir = this.column.sort?.dir;
|
|
3968
4098
|
this.sortEnabled = this.property.options?.sort?.enabled;
|
|
3969
4099
|
this.node = computed(() => {
|
|
3970
4100
|
const widget = this.property.schema.interface;
|
|
@@ -4977,7 +5107,7 @@ class AXPEntityMasterListViewModel {
|
|
|
4977
5107
|
this.events$.next({ action: 'refresh' });
|
|
4978
5108
|
}
|
|
4979
5109
|
});
|
|
4980
|
-
this.sortedFields.set(
|
|
5110
|
+
this.sortedFields.set([]);
|
|
4981
5111
|
void this.syncShowRowIndexColumnSetting();
|
|
4982
5112
|
this.settings.onLoaded.pipe(takeUntil(this.destroyed)).subscribe(() => {
|
|
4983
5113
|
void this.syncShowRowIndexColumnSetting();
|
|
@@ -5080,10 +5210,8 @@ class AXPEntityMasterListViewModel {
|
|
|
5080
5210
|
.sort((a, b) => columns.findIndex((col) => col.name === (a.column?.options?.dataPath ?? a.name)) -
|
|
5081
5211
|
columns.findIndex((col) => col.name === (b.column?.options?.dataPath ?? b.name))));
|
|
5082
5212
|
}
|
|
5083
|
-
if (Array.isArray(sorts)) {
|
|
5084
|
-
|
|
5085
|
-
const sortsMap = new Map(sorts.map((s) => [s.name, s.dir]));
|
|
5086
|
-
this.sortedFields.update((prev) => prev.map((sf) => ({ ...sf, dir: sortsMap.get(sf.name) || sf.dir })));
|
|
5213
|
+
if (Array.isArray(sorts) && sorts.length) {
|
|
5214
|
+
this.setActiveSortsFromQueries(sorts);
|
|
5087
5215
|
}
|
|
5088
5216
|
// Don't override filters if they came from queryParams
|
|
5089
5217
|
if (Array.isArray(filters) && !this.hasQueryParamsFilters) {
|
|
@@ -5600,18 +5728,80 @@ class AXPEntityMasterListViewModel {
|
|
|
5600
5728
|
resetSorts() {
|
|
5601
5729
|
this.applyViewSorts();
|
|
5602
5730
|
}
|
|
5731
|
+
/**
|
|
5732
|
+
* Applies active sorts in the given order (click order, saved settings, or view defaults).
|
|
5733
|
+
*/
|
|
5734
|
+
setActiveSortsFromQueries(sorts) {
|
|
5735
|
+
const sortableByName = new Map(this.sortableFields().map((f) => [f.name, f]));
|
|
5736
|
+
this.sortedFields.set(sorts
|
|
5737
|
+
.filter((s) => s.dir && sortableByName.has(s.name))
|
|
5738
|
+
.map((s) => ({
|
|
5739
|
+
name: s.name,
|
|
5740
|
+
title: sortableByName.get(s.name).title,
|
|
5741
|
+
dir: s.dir,
|
|
5742
|
+
})));
|
|
5743
|
+
}
|
|
5603
5744
|
applyViewSorts() {
|
|
5604
|
-
const viewSorts = this.view().sorts;
|
|
5605
|
-
this.
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5745
|
+
const viewSorts = this.view().sorts ?? [];
|
|
5746
|
+
this.setActiveSortsFromQueries(viewSorts);
|
|
5747
|
+
}
|
|
5748
|
+
/**
|
|
5749
|
+
* Active sort direction for a column (synced with toolbar sort UI and dataSource).
|
|
5750
|
+
*/
|
|
5751
|
+
getColumnSortDirection(columnName) {
|
|
5752
|
+
const dir = this.sortedFields().find((sf) => sf.name === columnName)?.dir;
|
|
5753
|
+
return dir === 'asc' || dir === 'desc' ? dir : undefined;
|
|
5754
|
+
}
|
|
5755
|
+
/**
|
|
5756
|
+
* 1-based priority index when multiple columns are sorted (Ctrl+click order).
|
|
5757
|
+
*/
|
|
5758
|
+
getColumnSortIndex(columnName) {
|
|
5759
|
+
const index = this.sortedFields().findIndex((sf) => sf.name === columnName);
|
|
5760
|
+
return index >= 0 ? index + 1 : undefined;
|
|
5761
|
+
}
|
|
5762
|
+
/** True when active sorts still match the current view defaults (not yet customized). */
|
|
5763
|
+
isViewDefaultSorts(activeSorts) {
|
|
5764
|
+
const viewSorts = this.view().sorts ?? [];
|
|
5765
|
+
if (activeSorts.length !== viewSorts.length) {
|
|
5766
|
+
return false;
|
|
5767
|
+
}
|
|
5768
|
+
return activeSorts.every((s, i) => s.name === viewSorts[i]?.name && s.dir === viewSorts[i]?.dir);
|
|
5769
|
+
}
|
|
5770
|
+
/**
|
|
5771
|
+
* Toggles column sort (asc → desc → none). Without Ctrl, only one column is active.
|
|
5772
|
+
* With Ctrl/Cmd, multiple columns are sorted in click order (first clicked = primary).
|
|
5773
|
+
*/
|
|
5774
|
+
async toggleColumnSort(columnName, multiSort) {
|
|
5775
|
+
const fieldMeta = this.sortableFields().find((f) => f.name === columnName);
|
|
5776
|
+
if (!fieldMeta) {
|
|
5777
|
+
return;
|
|
5778
|
+
}
|
|
5779
|
+
let activeSorts = [...this.sortedFields()];
|
|
5780
|
+
const index = activeSorts.findIndex((sf) => sf.name === columnName);
|
|
5781
|
+
const currentDir = index >= 0 ? activeSorts[index].dir : undefined;
|
|
5782
|
+
const newDir = currentDir === 'asc' ? 'desc' : currentDir === 'desc' ? undefined : 'asc';
|
|
5783
|
+
if (!multiSort) {
|
|
5784
|
+
activeSorts = newDir ? [{ name: columnName, title: fieldMeta.title, dir: newDir }] : [];
|
|
5785
|
+
}
|
|
5786
|
+
else if (index >= 0) {
|
|
5787
|
+
const [item] = activeSorts.splice(index, 1);
|
|
5788
|
+
if (newDir) {
|
|
5789
|
+
// Re-click moves column to end so click order can override view/default order.
|
|
5790
|
+
activeSorts.push({ ...item, title: fieldMeta.title, dir: newDir });
|
|
5791
|
+
}
|
|
5792
|
+
}
|
|
5793
|
+
else if (newDir) {
|
|
5794
|
+
if (this.isViewDefaultSorts(activeSorts)) {
|
|
5795
|
+
activeSorts = [{ name: columnName, title: fieldMeta.title, dir: newDir }];
|
|
5796
|
+
}
|
|
5797
|
+
else {
|
|
5798
|
+
activeSorts.push({ name: columnName, title: fieldMeta.title, dir: newDir });
|
|
5799
|
+
}
|
|
5800
|
+
}
|
|
5801
|
+
this.sortedFields.set(activeSorts);
|
|
5802
|
+
this.lastAppliedSortKey = null;
|
|
5803
|
+
await this.saveSettings('sorts', activeSorts.map((s) => ({ name: s.name, dir: s.dir })));
|
|
5804
|
+
await this.applyFilterAndSort();
|
|
5615
5805
|
}
|
|
5616
5806
|
//****************** Commands ******************//
|
|
5617
5807
|
async executeCommand(commandName, data = null) {
|
|
@@ -12547,22 +12737,18 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
12547
12737
|
constructor() {
|
|
12548
12738
|
super(...arguments);
|
|
12549
12739
|
this.formatService = inject(AXFormatService);
|
|
12740
|
+
this.translation = inject(AXTranslationService);
|
|
12550
12741
|
this.entityResolver = inject(AXPEntityDefinitionRegistryService);
|
|
12551
12742
|
this.entity = computed(() => this.options()['entity'], ...(ngDevMode ? [{ debugName: "entity" }] : /* istanbul ignore next */ []));
|
|
12552
12743
|
this.multiple = computed(() => this.options()['multiple'], ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
|
|
12553
12744
|
this.valueField = computed(() => this.options()['valueField'] ?? 'id', ...(ngDevMode ? [{ debugName: "valueField" }] : /* istanbul ignore next */ []));
|
|
12554
12745
|
this.textField = computed(() => this.options()['textField'] ?? 'title', ...(ngDevMode ? [{ debugName: "textField" }] : /* istanbul ignore next */ []));
|
|
12555
12746
|
this.badgeClass = computed(() => this.options()['badgeClass'] ?? 'ax-accent1', ...(ngDevMode ? [{ debugName: "badgeClass" }] : /* istanbul ignore next */ []));
|
|
12556
|
-
this.displayFormat = computed(() => {
|
|
12557
|
-
|
|
12558
|
-
|
|
12559
|
-
}, ...(ngDevMode ? [{ debugName: "displayFormat" }] : /* istanbul ignore next */ []));
|
|
12560
|
-
this.displayField = computed(() => {
|
|
12561
|
-
return (this.textField() ??
|
|
12562
|
-
this.entityDef()?.formats.lookup ??
|
|
12563
|
-
this.entityDef()?.properties.find((c) => c.name != 'id')?.name ??
|
|
12564
|
-
'title');
|
|
12565
|
-
}, ...(ngDevMode ? [{ debugName: "displayField" }] : /* istanbul ignore next */ []));
|
|
12747
|
+
this.displayFormat = computed(() => resolveLookupDisplayTemplate(this.entityDef(), {
|
|
12748
|
+
displayFormat: this.options()['displayFormat'],
|
|
12749
|
+
textField: this.textField(),
|
|
12750
|
+
}), ...(ngDevMode ? [{ debugName: "displayFormat" }] : /* istanbul ignore next */ []));
|
|
12751
|
+
this.displayField = computed(() => resolveLookupDisplayField(this.entityDef(), { textField: this.textField() }), ...(ngDevMode ? [{ debugName: "displayField" }] : /* istanbul ignore next */ []));
|
|
12566
12752
|
this.loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
12567
12753
|
this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : /* istanbul ignore next */ []));
|
|
12568
12754
|
this.displayItems = signal([], ...(ngDevMode ? [{ debugName: "displayItems" }] : /* istanbul ignore next */ []));
|
|
@@ -12605,27 +12791,11 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
12605
12791
|
};
|
|
12606
12792
|
}
|
|
12607
12793
|
getDisplayRaw(item) {
|
|
12608
|
-
|
|
12609
|
-
|
|
12610
|
-
|
|
12611
|
-
|
|
12612
|
-
|
|
12613
|
-
const formatted = this.formatService.format(template, 'string', item);
|
|
12614
|
-
if (formatted) {
|
|
12615
|
-
return formatted;
|
|
12616
|
-
}
|
|
12617
|
-
}
|
|
12618
|
-
const raw = get(item, this.displayField());
|
|
12619
|
-
if (raw == null) {
|
|
12620
|
-
return '';
|
|
12621
|
-
}
|
|
12622
|
-
if (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') {
|
|
12623
|
-
return String(raw);
|
|
12624
|
-
}
|
|
12625
|
-
if (typeof raw === 'object' && !Array.isArray(raw)) {
|
|
12626
|
-
return raw;
|
|
12627
|
-
}
|
|
12628
|
-
return String(raw);
|
|
12794
|
+
const text = formatLookupItemDisplay(item, this.entityDef(), {
|
|
12795
|
+
displayFormat: this.options()['displayFormat'],
|
|
12796
|
+
textField: this.textField(),
|
|
12797
|
+
}, this.formatService, (value) => this.translation.resolve(value));
|
|
12798
|
+
return text;
|
|
12629
12799
|
}
|
|
12630
12800
|
get __class() {
|
|
12631
12801
|
const cls = {};
|
|
@@ -13520,27 +13690,10 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
|
|
|
13520
13690
|
//#endregion
|
|
13521
13691
|
//#region ---- Utility Methods ----
|
|
13522
13692
|
getDisplayRaw(item) {
|
|
13523
|
-
|
|
13524
|
-
|
|
13525
|
-
|
|
13526
|
-
|
|
13527
|
-
if (template) {
|
|
13528
|
-
const formatted = this.formatService.format(template, 'string', item);
|
|
13529
|
-
if (formatted) {
|
|
13530
|
-
return formatted;
|
|
13531
|
-
}
|
|
13532
|
-
}
|
|
13533
|
-
const raw = get(item, this.displayFieldValue());
|
|
13534
|
-
if (raw == null) {
|
|
13535
|
-
return '';
|
|
13536
|
-
}
|
|
13537
|
-
if (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') {
|
|
13538
|
-
return String(raw);
|
|
13539
|
-
}
|
|
13540
|
-
if (typeof raw === 'object' && !Array.isArray(raw)) {
|
|
13541
|
-
return raw;
|
|
13542
|
-
}
|
|
13543
|
-
return String(raw);
|
|
13693
|
+
return formatLookupItemDisplay(item, this.entityDef()(), {
|
|
13694
|
+
displayFormat: this.displayFormatValue(),
|
|
13695
|
+
textField: this.displayFieldValue(),
|
|
13696
|
+
}, this.formatService, (value) => this.translateService.resolve(value));
|
|
13544
13697
|
}
|
|
13545
13698
|
/**
|
|
13546
13699
|
* Get current input value from tag box
|
|
@@ -13792,6 +13945,18 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
13792
13945
|
this.disabled = computed(() => this.filterMode() ? false : this.options()['disabled'], ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
13793
13946
|
this.columns = computed(() => this.options()['columns'] ?? [], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
13794
13947
|
this.textField = computed(() => this.options()['textField'] ?? '', ...(ngDevMode ? [{ debugName: "textField" }] : /* istanbul ignore next */ []));
|
|
13948
|
+
/**
|
|
13949
|
+
* Template for select look (`ax-select-box`). Uses `textTemplate` when set, otherwise
|
|
13950
|
+
* falls back to `displayFormat` (same as tagbox). Single braces are expanded to `{{ }}`
|
|
13951
|
+
* for the select box template engine (see `AXPDataListWidgetComponent.textTemplate`).
|
|
13952
|
+
*/
|
|
13953
|
+
this.textTemplate = computed(() => {
|
|
13954
|
+
const explicit = this.options()['textTemplate'];
|
|
13955
|
+
if (explicit) {
|
|
13956
|
+
return explicit.replace(/\{/g, '{{').replace(/\}/g, '}}');
|
|
13957
|
+
}
|
|
13958
|
+
return this.displayFormat() ?? null;
|
|
13959
|
+
}, ...(ngDevMode ? [{ debugName: "textTemplate" }] : /* istanbul ignore next */ []));
|
|
13795
13960
|
this.hasClearButton = computed(() => (!this.filterMode() && this.options()['hasClearButton']) ?? false, ...(ngDevMode ? [{ debugName: "hasClearButton" }] : /* istanbul ignore next */ []));
|
|
13796
13961
|
this.showItemTooltip = computed(() => this.options()['showItemTooltip'] ?? false, ...(ngDevMode ? [{ debugName: "showItemTooltip" }] : /* istanbul ignore next */ []));
|
|
13797
13962
|
this.isItemTruncated = computed(() => this.options()['isItemTruncated'] ?? true, ...(ngDevMode ? [{ debugName: "isItemTruncated" }] : /* istanbul ignore next */ []));
|
|
@@ -13800,23 +13965,13 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
13800
13965
|
this.filterMode = computed(() => this.options()['filterMode'], ...(ngDevMode ? [{ debugName: "filterMode" }] : /* istanbul ignore next */ []));
|
|
13801
13966
|
this.multiple = computed(() => (this.options()['multiple'] ?? false), ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
|
|
13802
13967
|
this.look = computed(() => this.options()['look'] ?? 'lookup', ...(ngDevMode ? [{ debugName: "look" }] : /* istanbul ignore next */ []));
|
|
13803
|
-
this.
|
|
13804
|
-
const list = ['title', 'name', 'code', 'description'];
|
|
13805
|
-
const textField = list.find((c) => this.entityDef()?.properties.find((p) => p.name == c)) ?? 'title';
|
|
13806
|
-
return textField;
|
|
13807
|
-
}, ...(ngDevMode ? [{ debugName: "defaultTextField" }] : /* istanbul ignore next */ []));
|
|
13808
|
-
this.displayField = computed(() => {
|
|
13809
|
-
if (this.textField()) {
|
|
13810
|
-
return this.textField();
|
|
13811
|
-
}
|
|
13812
|
-
return this.defaultTextField();
|
|
13813
|
-
}, ...(ngDevMode ? [{ debugName: "displayField" }] : /* istanbul ignore next */ []));
|
|
13968
|
+
this.displayField = computed(() => resolveLookupDisplayField(this.entityDef(), { textField: this.textField() }), ...(ngDevMode ? [{ debugName: "displayField" }] : /* istanbul ignore next */ []));
|
|
13814
13969
|
this.allowCreate = computed(() => this.options()['allowCreate'] ?? 'none', ...(ngDevMode ? [{ debugName: "allowCreate" }] : /* istanbul ignore next */ []));
|
|
13815
13970
|
this.valueField = computed(() => this.entityDef()?.properties.find((c) => c.name == 'id')?.name ?? 'id', ...(ngDevMode ? [{ debugName: "valueField" }] : /* istanbul ignore next */ []));
|
|
13816
|
-
this.displayFormat = computed(() => {
|
|
13817
|
-
|
|
13818
|
-
|
|
13819
|
-
}, ...(ngDevMode ? [{ debugName: "displayFormat" }] : /* istanbul ignore next */ []));
|
|
13971
|
+
this.displayFormat = computed(() => resolveLookupDisplayTemplate(this.entityDef(), {
|
|
13972
|
+
displayFormat: this.options()['displayFormat'],
|
|
13973
|
+
textField: this.textField(),
|
|
13974
|
+
}), ...(ngDevMode ? [{ debugName: "displayFormat" }] : /* istanbul ignore next */ []));
|
|
13820
13975
|
this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : /* istanbul ignore next */ []));
|
|
13821
13976
|
this.selectedItems = signal([], ...(ngDevMode ? [{ debugName: "selectedItems" }] : /* istanbul ignore next */ []));
|
|
13822
13977
|
this.initialItems = signal(false, ...(ngDevMode ? [{ debugName: "initialItems" }] : /* istanbul ignore next */ []));
|
|
@@ -14212,6 +14367,7 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
14212
14367
|
this.translation = inject(AXTranslationService);
|
|
14213
14368
|
this.formatService = inject(AXFormatService);
|
|
14214
14369
|
this.entityService = inject(AXPEntityService);
|
|
14370
|
+
this.entityResolver = inject(AXPEntityDefinitionRegistryService);
|
|
14215
14371
|
this.queryExecutor = inject(AXPQueryExecutor);
|
|
14216
14372
|
//#endregion
|
|
14217
14373
|
//#region ---- View Children ----
|
|
@@ -14222,15 +14378,16 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
14222
14378
|
//#region ---- Properties ----
|
|
14223
14379
|
this.host = inject(ElementRef);
|
|
14224
14380
|
this.valueField = this.options['valueField'] ?? 'id';
|
|
14225
|
-
this.textField = this.options['textField'] ?? 'title';
|
|
14226
14381
|
this.entity = this.options['entity'] ?? '';
|
|
14227
14382
|
this.columnName = this.options['columnName'] ?? 'title';
|
|
14228
14383
|
this.maxVisible = this.options['maxVisible'] ?? 2;
|
|
14229
|
-
this.
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
14384
|
+
this.lookupDisplayOptions = computed(() => ({
|
|
14385
|
+
displayFormat: this.options['displayFormat'],
|
|
14386
|
+
textField: this.options['textField'],
|
|
14387
|
+
isMultiLanguage: (value) => this.translation.isValidMultiLanguageObject(value),
|
|
14388
|
+
}), ...(ngDevMode ? [{ debugName: "lookupDisplayOptions" }] : /* istanbul ignore next */ []));
|
|
14389
|
+
this.displayFormat = computed(() => resolveLookupDisplayTemplate(this.entityDef(), this.lookupDisplayOptions()), ...(ngDevMode ? [{ debugName: "displayFormat" }] : /* istanbul ignore next */ []));
|
|
14390
|
+
this.displayField = computed(() => resolveLookupDisplayField(this.entityDef(), this.lookupDisplayOptions()), ...(ngDevMode ? [{ debugName: "displayField" }] : /* istanbul ignore next */ []));
|
|
14234
14391
|
this.columnResolve = computed(() => this.options['columnResolve'], ...(ngDevMode ? [{ debugName: "columnResolve" }] : /* istanbul ignore next */ []));
|
|
14235
14392
|
this.resolveStrategy = computed(() => {
|
|
14236
14393
|
return this.columnResolve()?.strategy ?? 'hydrated';
|
|
@@ -14245,6 +14402,9 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
14245
14402
|
this.resolveError = signal(null, ...(ngDevMode ? [{ debugName: "resolveError" }] : /* istanbul ignore next */ []));
|
|
14246
14403
|
this.summaryLabel = signal('', ...(ngDevMode ? [{ debugName: "summaryLabel" }] : /* istanbul ignore next */ []));
|
|
14247
14404
|
this.popoverHeader = signal('', ...(ngDevMode ? [{ debugName: "popoverHeader" }] : /* istanbul ignore next */ []));
|
|
14405
|
+
this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : /* istanbul ignore next */ []));
|
|
14406
|
+
this.hydratedDisplayItems = signal(null, ...(ngDevMode ? [{ debugName: "hydratedDisplayItems" }] : /* istanbul ignore next */ []));
|
|
14407
|
+
this.hydrateRequestId = 0;
|
|
14248
14408
|
//#endregion
|
|
14249
14409
|
//#region ---- Computed ----
|
|
14250
14410
|
this.displayItems = computed(() => isNil(this.rawValue)
|
|
@@ -14252,7 +14412,13 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
14252
14412
|
: castArray(this.rawValue)
|
|
14253
14413
|
.map((item) => this.extractItem(item))
|
|
14254
14414
|
.filter((c) => c != null), ...(ngDevMode ? [{ debugName: "displayItems" }] : /* istanbul ignore next */ []));
|
|
14255
|
-
this.allItems = computed(() =>
|
|
14415
|
+
this.allItems = computed(() => {
|
|
14416
|
+
const hydrated = this.hydratedDisplayItems();
|
|
14417
|
+
if (hydrated != null && hydrated.length > 0) {
|
|
14418
|
+
return hydrated;
|
|
14419
|
+
}
|
|
14420
|
+
return this.displayItems();
|
|
14421
|
+
}, ...(ngDevMode ? [{ debugName: "allItems" }] : /* istanbul ignore next */ []));
|
|
14256
14422
|
this.visibleItems = computed(() => {
|
|
14257
14423
|
const items = this.allItems();
|
|
14258
14424
|
return items.slice(0, this.maxVisible);
|
|
@@ -14309,6 +14475,8 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
14309
14475
|
}
|
|
14310
14476
|
this.previousLazyRowId = key;
|
|
14311
14477
|
this.resetLazyState();
|
|
14478
|
+
this.hydratedDisplayItems.set(null);
|
|
14479
|
+
this.hydrateRequestId++;
|
|
14312
14480
|
});
|
|
14313
14481
|
effect(() => {
|
|
14314
14482
|
if (!this.isHydratedStrategy()) {
|
|
@@ -14325,6 +14493,40 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
14325
14493
|
: this.displayCount();
|
|
14326
14494
|
void this.refreshPopoverHeader(count);
|
|
14327
14495
|
});
|
|
14496
|
+
effect(() => {
|
|
14497
|
+
const key = this.entity;
|
|
14498
|
+
if (!key?.includes('.')) {
|
|
14499
|
+
this.entityDef.set(null);
|
|
14500
|
+
return;
|
|
14501
|
+
}
|
|
14502
|
+
const [module, name] = key.split('.');
|
|
14503
|
+
void this.entityResolver.resolve(module, name).then((def) => this.entityDef.set(def));
|
|
14504
|
+
});
|
|
14505
|
+
effect(() => {
|
|
14506
|
+
if (!this.isHydratedStrategy()) {
|
|
14507
|
+
this.hydratedDisplayItems.set(null);
|
|
14508
|
+
return;
|
|
14509
|
+
}
|
|
14510
|
+
const entityKey = this.entity;
|
|
14511
|
+
const raw = this.rawValue;
|
|
14512
|
+
if (!entityKey?.includes('.') || isNil(raw)) {
|
|
14513
|
+
this.hydratedDisplayItems.set(null);
|
|
14514
|
+
return;
|
|
14515
|
+
}
|
|
14516
|
+
// Display text is already on the row (dataPath, denormalized title, nested object, etc.) — no byKey fetch.
|
|
14517
|
+
if (this.hasPreresolvedDisplay()) {
|
|
14518
|
+
this.hydratedDisplayItems.set(null);
|
|
14519
|
+
return;
|
|
14520
|
+
}
|
|
14521
|
+
const values = castArray(raw).filter((value) => value != null && value !== '');
|
|
14522
|
+
const needsHydrate = values.length > 0 &&
|
|
14523
|
+
values.every((value) => typeof value !== 'object' && this.isLikelyEntityId(value));
|
|
14524
|
+
if (!needsHydrate) {
|
|
14525
|
+
this.hydratedDisplayItems.set(null);
|
|
14526
|
+
return;
|
|
14527
|
+
}
|
|
14528
|
+
void this.hydrateScalarIds(entityKey, values);
|
|
14529
|
+
});
|
|
14328
14530
|
}
|
|
14329
14531
|
//#endregion
|
|
14330
14532
|
//#region ---- Public methods ----
|
|
@@ -14354,7 +14556,7 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
14354
14556
|
this.closeMorePopover();
|
|
14355
14557
|
// Prefer the row's FK / stored value (columnName) first. List columns often use options.dataPath so
|
|
14356
14558
|
// rawValue (and thus `item`) is only display text (e.g. manager.person.fullName) while managerId holds the real id.
|
|
14357
|
-
const columnData = this.rowData
|
|
14559
|
+
const columnData = get(this.rowData, this.columnName);
|
|
14358
14560
|
let id;
|
|
14359
14561
|
if (Array.isArray(columnData)) {
|
|
14360
14562
|
const cell = columnData[index];
|
|
@@ -14375,11 +14577,33 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
14375
14577
|
if (isNil(id) || id === '') {
|
|
14376
14578
|
return;
|
|
14377
14579
|
}
|
|
14580
|
+
const headerItem = this.allItems()[index] ?? item;
|
|
14581
|
+
let resolvedTitle = '';
|
|
14582
|
+
if (headerItem != null && this.hasDisplayTextOnLookupValue(headerItem)) {
|
|
14583
|
+
resolvedTitle =
|
|
14584
|
+
typeof headerItem === 'object'
|
|
14585
|
+
? this.renderLookupLabel(headerItem)
|
|
14586
|
+
: this.formatDisplayValue(headerItem);
|
|
14587
|
+
}
|
|
14588
|
+
else if (!this.isMultiValueLookup()) {
|
|
14589
|
+
const rowText = this.getRowDisplayTextFromTextField();
|
|
14590
|
+
if (!isNil(rowText) && rowText !== '') {
|
|
14591
|
+
resolvedTitle = this.formatDisplayValue(rowText);
|
|
14592
|
+
}
|
|
14593
|
+
}
|
|
14594
|
+
if (!resolvedTitle) {
|
|
14595
|
+
const displayTitle = formatLookupItemDisplay(headerItem, this.entityDef(), this.lookupDisplayOptions(), this.formatService, (value) => this.translation.resolve(value));
|
|
14596
|
+
resolvedTitle = typeof displayTitle === 'string' ? displayTitle : this.translation.resolve(displayTitle);
|
|
14597
|
+
if (isUnresolvedLookupDisplayTemplate(resolvedTitle)) {
|
|
14598
|
+
resolvedTitle = '';
|
|
14599
|
+
}
|
|
14600
|
+
}
|
|
14378
14601
|
await this.entityDetailPopoverService.show(this.host, {
|
|
14379
14602
|
entity: this.entity,
|
|
14380
14603
|
id,
|
|
14381
|
-
textField: this.textField,
|
|
14604
|
+
textField: this.options['textField'] ?? this.displayField(),
|
|
14382
14605
|
valueField: this.valueField,
|
|
14606
|
+
displayTitle: resolvedTitle,
|
|
14383
14607
|
item,
|
|
14384
14608
|
});
|
|
14385
14609
|
}
|
|
@@ -14409,21 +14633,45 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
14409
14633
|
this.handleResolvedItemClick(index);
|
|
14410
14634
|
}
|
|
14411
14635
|
}
|
|
14636
|
+
/**
|
|
14637
|
+
* True when the cell can render without fetching row data via byKey.
|
|
14638
|
+
* Uses textField / expose targets on the row — not merely whether column dataPath differs from columnName.
|
|
14639
|
+
*/
|
|
14640
|
+
hasPreresolvedDisplay() {
|
|
14641
|
+
if (this.isMultiValueLookup()) {
|
|
14642
|
+
const values = castArray(this.rawValue).filter((value) => value != null && value !== '');
|
|
14643
|
+
return values.length > 0 && values.every((value) => this.hasDisplayTextOnLookupValue(value));
|
|
14644
|
+
}
|
|
14645
|
+
const rowText = this.getRowDisplayTextFromTextField();
|
|
14646
|
+
if (!isNil(rowText) &&
|
|
14647
|
+
rowText !== '' &&
|
|
14648
|
+
(typeof rowText !== 'string' || !this.isLikelyEntityId(rowText))) {
|
|
14649
|
+
return true;
|
|
14650
|
+
}
|
|
14651
|
+
const raw = this.rawValue;
|
|
14652
|
+
if (isNil(raw)) {
|
|
14653
|
+
return false;
|
|
14654
|
+
}
|
|
14655
|
+
const values = castArray(raw).filter((value) => value != null && value !== '');
|
|
14656
|
+
return values.length > 0 && values.every((value) => this.hasDisplayTextOnLookupValue(value));
|
|
14657
|
+
}
|
|
14412
14658
|
getDisplayRaw(item) {
|
|
14413
|
-
if (
|
|
14414
|
-
return
|
|
14659
|
+
if (item != null && typeof item === 'object' && this.translation.isValidMultiLanguageObject(item)) {
|
|
14660
|
+
return this.translation.resolve(item);
|
|
14415
14661
|
}
|
|
14416
|
-
|
|
14417
|
-
|
|
14418
|
-
|
|
14419
|
-
|
|
14420
|
-
|
|
14421
|
-
|
|
14422
|
-
|
|
14423
|
-
|
|
14424
|
-
|
|
14662
|
+
if (!this.isMultiValueLookup()) {
|
|
14663
|
+
const rowText = this.getRowDisplayTextFromTextField();
|
|
14664
|
+
if (!isNil(rowText) && rowText !== '') {
|
|
14665
|
+
return this.formatDisplayValue(rowText);
|
|
14666
|
+
}
|
|
14667
|
+
}
|
|
14668
|
+
if (item != null && this.hasDisplayTextOnLookupValue(item)) {
|
|
14669
|
+
if (typeof item === 'object') {
|
|
14670
|
+
return this.renderLookupLabel(item);
|
|
14671
|
+
}
|
|
14672
|
+
return this.formatDisplayValue(item);
|
|
14425
14673
|
}
|
|
14426
|
-
return
|
|
14674
|
+
return this.renderLookupLabel(item);
|
|
14427
14675
|
}
|
|
14428
14676
|
//#endregion
|
|
14429
14677
|
//#region ---- Private methods ----
|
|
@@ -14594,28 +14842,154 @@ class AXPLookupWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
14594
14842
|
}
|
|
14595
14843
|
return {
|
|
14596
14844
|
[this.valueField]: item,
|
|
14597
|
-
[this.
|
|
14845
|
+
[this.displayField()]: item,
|
|
14598
14846
|
};
|
|
14599
14847
|
}
|
|
14600
|
-
|
|
14601
|
-
|
|
14602
|
-
|
|
14848
|
+
async hydrateScalarIds(entityKey, ids) {
|
|
14849
|
+
const requestId = ++this.hydrateRequestId;
|
|
14850
|
+
try {
|
|
14851
|
+
const accessor = this.entityService.withEntity(entityKey).data();
|
|
14852
|
+
const items = await Promise.all(ids.map((id) => accessor.byKey(id)));
|
|
14853
|
+
if (requestId !== this.hydrateRequestId) {
|
|
14854
|
+
return;
|
|
14855
|
+
}
|
|
14856
|
+
const resolved = items.filter((item) => item != null);
|
|
14857
|
+
this.hydratedDisplayItems.set(resolved.length > 0 ? resolved : null);
|
|
14603
14858
|
}
|
|
14604
|
-
|
|
14605
|
-
|
|
14859
|
+
catch {
|
|
14860
|
+
if (requestId === this.hydrateRequestId) {
|
|
14861
|
+
this.hydratedDisplayItems.set(null);
|
|
14862
|
+
}
|
|
14606
14863
|
}
|
|
14607
|
-
|
|
14608
|
-
|
|
14864
|
+
}
|
|
14865
|
+
isMultiValueLookup() {
|
|
14866
|
+
return Array.isArray(this.rawValue) && this.rawValue.length > 0;
|
|
14867
|
+
}
|
|
14868
|
+
/** Row display text resolved via widget textField and expose targets (not column dataPath alone). */
|
|
14869
|
+
getRowDisplayTextFromTextField() {
|
|
14870
|
+
const textField = resolveLookupDisplayField(this.entityDef(), this.lookupDisplayOptions());
|
|
14871
|
+
const exposeTargets = this.getExposeTargets();
|
|
14872
|
+
for (const entry of exposeTargets) {
|
|
14873
|
+
if (entry.source === this.valueField || entry.source === 'id') {
|
|
14874
|
+
continue;
|
|
14875
|
+
}
|
|
14876
|
+
if (entry.source === textField || entry.target.endsWith(`.${textField}`)) {
|
|
14877
|
+
const value = get(this.rowData, entry.target);
|
|
14878
|
+
if (!isNil(value) && value !== '') {
|
|
14879
|
+
return value;
|
|
14880
|
+
}
|
|
14881
|
+
}
|
|
14609
14882
|
}
|
|
14610
|
-
const
|
|
14611
|
-
|
|
14612
|
-
|
|
14883
|
+
for (const entry of exposeTargets) {
|
|
14884
|
+
if (entry.source === 'title') {
|
|
14885
|
+
const value = get(this.rowData, entry.target);
|
|
14886
|
+
if (!isNil(value) && value !== '') {
|
|
14887
|
+
return value;
|
|
14888
|
+
}
|
|
14889
|
+
}
|
|
14613
14890
|
}
|
|
14614
|
-
if (this.
|
|
14615
|
-
|
|
14891
|
+
if (this.path && this.path !== this.columnName) {
|
|
14892
|
+
const atPath = get(this.rowData, this.path);
|
|
14893
|
+
if (typeof atPath === 'string' && atPath !== '' && !this.isLikelyEntityId(atPath)) {
|
|
14894
|
+
return atPath;
|
|
14895
|
+
}
|
|
14896
|
+
if (atPath != null && typeof atPath === 'object') {
|
|
14897
|
+
const nested = get(atPath, textField);
|
|
14898
|
+
if (!isNil(nested) && nested !== '') {
|
|
14899
|
+
return nested;
|
|
14900
|
+
}
|
|
14901
|
+
}
|
|
14902
|
+
const combined = get(this.rowData, `${this.path}.${textField}`);
|
|
14903
|
+
if (!isNil(combined) && combined !== '') {
|
|
14904
|
+
return combined;
|
|
14905
|
+
}
|
|
14906
|
+
}
|
|
14907
|
+
if (this.columnName.endsWith('Id')) {
|
|
14908
|
+
const parentKey = this.columnName.slice(0, -2);
|
|
14909
|
+
const nestedObject = get(this.rowData, parentKey);
|
|
14910
|
+
if (nestedObject != null && typeof nestedObject === 'object') {
|
|
14911
|
+
const nested = get(nestedObject, textField);
|
|
14912
|
+
if (!isNil(nested) && nested !== '') {
|
|
14913
|
+
return nested;
|
|
14914
|
+
}
|
|
14915
|
+
}
|
|
14916
|
+
const direct = get(this.rowData, `${parentKey}.${textField}`);
|
|
14917
|
+
if (!isNil(direct) && direct !== '') {
|
|
14918
|
+
return direct;
|
|
14919
|
+
}
|
|
14920
|
+
}
|
|
14921
|
+
if (this.columnName.includes('.')) {
|
|
14922
|
+
const parts = this.columnName.split('.');
|
|
14923
|
+
const leaf = parts[parts.length - 1];
|
|
14924
|
+
if (leaf === 'id' || leaf.endsWith('Id')) {
|
|
14925
|
+
const parent = parts.slice(0, -1).join('.');
|
|
14926
|
+
const direct = get(this.rowData, `${parent}.${textField}`);
|
|
14927
|
+
if (!isNil(direct) && direct !== '') {
|
|
14928
|
+
return direct;
|
|
14929
|
+
}
|
|
14930
|
+
}
|
|
14931
|
+
}
|
|
14932
|
+
return undefined;
|
|
14933
|
+
}
|
|
14934
|
+
getExposeTargets() {
|
|
14935
|
+
const expose = this.options['expose'];
|
|
14936
|
+
if (!Array.isArray(expose)) {
|
|
14937
|
+
return [];
|
|
14938
|
+
}
|
|
14939
|
+
return expose.filter((entry) => entry != null &&
|
|
14940
|
+
typeof entry === 'object' &&
|
|
14941
|
+
typeof entry.source === 'string' &&
|
|
14942
|
+
typeof entry.target === 'string');
|
|
14943
|
+
}
|
|
14944
|
+
hasDisplayTextOnLookupValue(value) {
|
|
14945
|
+
if (isNil(value) || value === '') {
|
|
14946
|
+
return false;
|
|
14947
|
+
}
|
|
14948
|
+
if (typeof value === 'string') {
|
|
14949
|
+
return !this.isLikelyEntityId(value);
|
|
14950
|
+
}
|
|
14951
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
14952
|
+
return true;
|
|
14953
|
+
}
|
|
14954
|
+
if (typeof value !== 'object') {
|
|
14955
|
+
return false;
|
|
14956
|
+
}
|
|
14957
|
+
if (this.translation.isValidMultiLanguageObject(value)) {
|
|
14958
|
+
return true;
|
|
14959
|
+
}
|
|
14960
|
+
const textField = resolveLookupDisplayField(this.entityDef(), this.lookupDisplayOptions());
|
|
14961
|
+
const text = get(value, textField);
|
|
14962
|
+
if (!isNil(text) && text !== '' && !this.isLikelyEntityId(text)) {
|
|
14963
|
+
return true;
|
|
14964
|
+
}
|
|
14965
|
+
return ['title', 'name', 'code', 'description'].some((field) => {
|
|
14966
|
+
const candidate = get(value, field);
|
|
14967
|
+
return !isNil(candidate) && candidate !== '' && !this.isLikelyEntityId(candidate);
|
|
14968
|
+
});
|
|
14969
|
+
}
|
|
14970
|
+
renderLookupLabel(value) {
|
|
14971
|
+
const label = formatLookupItemDisplay(value, this.entityDef(), this.lookupDisplayOptions(), this.formatService, (item) => this.translation.resolve(item));
|
|
14972
|
+
return typeof label === 'string' ? label : this.translation.resolve(label);
|
|
14973
|
+
}
|
|
14974
|
+
formatDisplayValue(value) {
|
|
14975
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
14976
|
+
return String(value);
|
|
14977
|
+
}
|
|
14978
|
+
if (value != null && typeof value === 'object' && this.translation.isValidMultiLanguageObject(value)) {
|
|
14979
|
+
return this.translation.resolve(value);
|
|
14616
14980
|
}
|
|
14617
14981
|
return '';
|
|
14618
14982
|
}
|
|
14983
|
+
/** True when a scalar cell value is a stored entity key (uuid/numeric), not pre-resolved display text. */
|
|
14984
|
+
isLikelyEntityId(value) {
|
|
14985
|
+
if (typeof value === 'number') {
|
|
14986
|
+
return true;
|
|
14987
|
+
}
|
|
14988
|
+
if (typeof value !== 'string') {
|
|
14989
|
+
return false;
|
|
14990
|
+
}
|
|
14991
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value) || /^\d+$/.test(value);
|
|
14992
|
+
}
|
|
14619
14993
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetColumnComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
14620
14994
|
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: i1$2.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", "closeOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
14621
14995
|
}
|
|
@@ -21426,5 +21800,5 @@ var getEntityDetails_query = /*#__PURE__*/Object.freeze({
|
|
|
21426
21800
|
* Generated bundle index. Do not edit.
|
|
21427
21801
|
*/
|
|
21428
21802
|
|
|
21429
|
-
export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCategoryTreeService, AXPCreateEntityCommand, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntitiesListDataSourceDefinition, AXPEntityApplyUpdatesAction, AXPEntityCategoryTreeSelectorComponent, AXPEntityCategoryWidget, AXPEntityCategoryWidgetColumnComponent, AXPEntityCategoryWidgetEditComponent, AXPEntityCategoryWidgetViewComponent, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDataSelectorService, AXPEntityDefinitionProviderWidget, AXPEntityDefinitionProviderWidgetEditComponent, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailPopoverComponent, AXPEntityDetailPopoverService, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityEventsKeys, AXPEntityFormBuilderService, AXPEntityListPersistenceModeDefault, AXPEntityListTableService, AXPEntityListToolbarService, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityListWidget, AXPEntityListWidgetViewComponent, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityPreloadFiltersContainerComponent, AXPEntityPreloadFiltersViewModel, AXPEntityPreloadFiltersViewModelResolver, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPEntityUpdateViewSectionViewModel, AXPGetEntityDetailsQuery, AXPLayoutOrderingConfigService, AXPLookupWidget, AXPLookupWidgetColumnComponent, AXPLookupWidgetEditComponent, AXPLookupWidgetViewComponent, AXPMiddlewareAbortError, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPMultiSourceDefinitionProviderContext, AXPMultiSourceDefinitionProviderService, AXPMultiSourceFederatedSearchService, AXPMultiSourceSelectorComponent, AXPMultiSourceSelectorService, AXPMultiSourceSelectorWidget, AXPMultiSourceSelectorWidgetColumnComponent, AXPMultiSourceSelectorWidgetEditComponent, AXPMultiSourceSelectorWidgetViewComponent, AXPMultiSourceType, AXPOpenEntityDetailsCommand, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPRelatedColumnEnrichmentService, AXPRelatedColumnMetadataResolver, AXPSelectorStructureWidget, AXPSelectorStructureWidgetColumnComponent, AXPSelectorStructureWidgetEditComponent, AXPSelectorStructureWidgetViewComponent, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXPTruncatedBreadcrumbComponent, AXPUpdateEntityCommand, AXPViewEntityDetailsCommand, AXP_CATEGORY_TREE_ROOT_TITLE_I18N_KEY, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, AXP_MULTI_SOURCE_DEFINITION_PROVIDER, 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, axpCreateEntityAiToolInputDefaults, axpCreateEntityCommandDefinition, buildAXPRecordWorkflowInfo, canPersistEntityListState, cloneLayoutArrays, collectEntityQuickSearchFieldPaths, collectNestedCreateHiddenProperties, collectNestedFieldPathsFromEntityColumns, collectQuickSearchPathsFromSingleEntityDefinition, columnOrderingMiddleware, columnOrderingMiddlewareProvider, columnWidthMiddleware, columnWidthMiddlewareProvider, computeEntityAggregates, createColumnOrderingMiddlewareProvider, createLayoutOrderingMiddlewareProvider, createModifierContext, 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, getDataSourcePageIndex, getEntityListRowId, getMasterInterfacePropertySortKey, getRecordWorkflowCorrelationId, getRecordWorkflowInstanceId, isAXPMiddlewareAbortError, isCategoryEntity, isCategoryFilter, layoutOrderingMiddlewareFactory, layoutOrderingMiddlewareProvider, mergeForeignKeyFieldIntoCreateActions, normalizeEntityListPersistenceMode, normalizeListPaging, provideEntity, resolveEntityPluginDetailPageOrder, restoreEntityListExpandedRows, runEntityQuery, searchResultDescriptionMiddleware, searchResultDescriptionMiddlewareProvider, shouldLoadEntityListStateFromStorage, shouldResetEntityListStateOnRouteEntry };
|
|
21803
|
+
export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCategoryTreeService, AXPCreateEntityCommand, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntitiesListDataSourceDefinition, AXPEntityApplyUpdatesAction, AXPEntityCategoryTreeSelectorComponent, AXPEntityCategoryWidget, AXPEntityCategoryWidgetColumnComponent, AXPEntityCategoryWidgetEditComponent, AXPEntityCategoryWidgetViewComponent, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDataSelectorService, AXPEntityDefinitionProviderWidget, AXPEntityDefinitionProviderWidgetEditComponent, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailPopoverComponent, AXPEntityDetailPopoverService, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityEventsKeys, AXPEntityFormBuilderService, AXPEntityListPersistenceModeDefault, AXPEntityListTableService, AXPEntityListToolbarService, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityListWidget, AXPEntityListWidgetViewComponent, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityPreloadFiltersContainerComponent, AXPEntityPreloadFiltersViewModel, AXPEntityPreloadFiltersViewModelResolver, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPEntityUpdateViewSectionViewModel, AXPGetEntityDetailsQuery, AXPLayoutOrderingConfigService, AXPLookupWidget, AXPLookupWidgetColumnComponent, AXPLookupWidgetEditComponent, AXPLookupWidgetViewComponent, AXPMiddlewareAbortError, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPMultiSourceDefinitionProviderContext, AXPMultiSourceDefinitionProviderService, AXPMultiSourceFederatedSearchService, AXPMultiSourceSelectorComponent, AXPMultiSourceSelectorService, AXPMultiSourceSelectorWidget, AXPMultiSourceSelectorWidgetColumnComponent, AXPMultiSourceSelectorWidgetEditComponent, AXPMultiSourceSelectorWidgetViewComponent, AXPMultiSourceType, AXPOpenEntityDetailsCommand, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPRelatedColumnEnrichmentService, AXPRelatedColumnMetadataResolver, AXPSelectorStructureWidget, AXPSelectorStructureWidgetColumnComponent, AXPSelectorStructureWidgetEditComponent, AXPSelectorStructureWidgetViewComponent, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXPTruncatedBreadcrumbComponent, AXPUpdateEntityCommand, AXPViewEntityDetailsCommand, AXP_CATEGORY_TREE_ROOT_TITLE_I18N_KEY, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, AXP_MULTI_SOURCE_DEFINITION_PROVIDER, 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, axpCreateEntityAiToolInputDefaults, axpCreateEntityCommandDefinition, buildAXPRecordWorkflowInfo, canPersistEntityListState, cloneLayoutArrays, collectEntityQuickSearchFieldPaths, collectNestedCreateHiddenProperties, collectNestedFieldPathsFromEntityColumns, collectQuickSearchPathsFromSingleEntityDefinition, columnOrderingMiddleware, columnOrderingMiddlewareProvider, columnWidthMiddleware, columnWidthMiddlewareProvider, computeEntityAggregates, createColumnOrderingMiddlewareProvider, createLayoutOrderingMiddlewareProvider, createModifierContext, 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, formatLookupItemDisplay, getDataSourcePageIndex, getEntityListRowId, getMasterInterfacePropertySortKey, getRecordWorkflowCorrelationId, getRecordWorkflowInstanceId, isAXPMiddlewareAbortError, isCategoryEntity, isCategoryFilter, isUnresolvedLookupDisplayTemplate, layoutOrderingMiddlewareFactory, layoutOrderingMiddlewareProvider, mergeForeignKeyFieldIntoCreateActions, normalizeEntityListPersistenceMode, normalizeListPaging, normalizeLookupDisplayTemplate, provideEntity, resolveEntityPluginDetailPageOrder, resolveLookupDisplayField, resolveLookupDisplayTemplate, restoreEntityListExpandedRows, runEntityQuery, searchResultDescriptionMiddleware, searchResultDescriptionMiddlewareProvider, shouldLoadEntityListStateFromStorage, shouldResetEntityListStateOnRouteEntry };
|
|
21430
21804
|
//# sourceMappingURL=acorex-platform-layout-entity.mjs.map
|