@acorex/platform 20.8.5 → 21.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/acorex-platform-auth.mjs +121 -27
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/{acorex-platform-common-common-settings.provider-41RhWqb4.mjs → acorex-platform-common-common-settings.provider-G9XcXXOG.mjs} +4 -4
- package/fesm2022/acorex-platform-common-common-settings.provider-G9XcXXOG.mjs.map +1 -0
- package/fesm2022/acorex-platform-common.mjs +669 -268
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +333 -140
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-domain.mjs +557 -826
- package/fesm2022/acorex-platform-domain.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +539 -110
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-components-binding-expression-editor-popup.component-CSxCnzwU.mjs → acorex-platform-layout-components-binding-expression-editor-popup.component-CWV4XD36.mjs} +15 -15
- package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CWV4XD36.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-components.mjs +3285 -1035
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +488 -284
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +15955 -11978
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +410 -170
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +548 -474
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-widgets-button-widget-designer.component-CPBzE96V.mjs → acorex-platform-layout-widgets-button-widget-designer.component-fLjWiSFE.mjs} +11 -11
- package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-fLjWiSFE.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-file-list-popup.component-Dtv6U3df.mjs → acorex-platform-layout-widgets-file-list-popup.component-3oRAKxTo.mjs} +22 -77
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-3oRAKxTo.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-image-preview.popup-QxJfswhK.mjs → acorex-platform-layout-widgets-image-preview.popup-CazpERbX.mjs} +8 -9
- package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-CazpERbX.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-page-widget-designer.component-CVdssZBD.mjs → acorex-platform-layout-widgets-page-widget-designer.component-BQ4G6aYf.mjs} +17 -17
- package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-BQ4G6aYf.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-DWuWxUF_.mjs +116 -0
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-DWuWxUF_.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-DVaZN9QN.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-fV94u3t2.mjs} +25 -19
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-fV94u3t2.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-DPGHgXa6.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-DyuvQhgN.mjs} +9 -9
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-DyuvQhgN.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-text-block-widget-designer.component-CdiNW691.mjs → acorex-platform-layout-widgets-text-block-widget-designer.component-EJMMdpIs.mjs} +7 -7
- package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-EJMMdpIs.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-widgets.mjs +6396 -4058
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-native.mjs +8 -7
- package/fesm2022/acorex-platform-native.mjs.map +1 -1
- package/fesm2022/acorex-platform-runtime.mjs +328 -166
- package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-CkptOSO3.mjs +160 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-CkptOSO3.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-DXC2qtvK.mjs +120 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-DXC2qtvK.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-rGsMVAZj.mjs → acorex-platform-themes-default-entity-master-single-view.component-DYyunzKZ.mjs} +16 -23
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-DYyunzKZ.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-error-401.component-C5lQECDP.mjs +31 -0
- package/fesm2022/acorex-platform-themes-default-error-401.component-C5lQECDP.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-error-404.component-D5wBXAB-.mjs +25 -0
- package/fesm2022/acorex-platform-themes-default-error-404.component-D5wBXAB-.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-error-offline.component-AhDiY3DI.mjs +19 -0
- package/fesm2022/acorex-platform-themes-default-error-offline.component-AhDiY3DI.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +1687 -69
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-shared-icon-chooser-column.component-TJ9PWHMY.mjs → acorex-platform-themes-shared-icon-chooser-column.component-QL2-ZUVg.mjs} +8 -8
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-QL2-ZUVg.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-shared-icon-chooser-view.component-BHcKkIx0.mjs → acorex-platform-themes-shared-icon-chooser-view.component-BXydqPt_.mjs} +8 -8
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-BXydqPt_.mjs.map +1 -0
- 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-Cb9iY6k9.mjs +88 -0
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-Cb9iY6k9.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-KP4-BND5.mjs +80 -0
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-KP4-BND5.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared.mjs +572 -465
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/fesm2022/acorex-platform-workflow.mjs +276 -98
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/fesm2022/acorex-platform.mjs.map +1 -1
- package/package.json +33 -33
- package/{auth/index.d.ts → types/acorex-platform-auth.d.ts} +14 -2
- package/{common/index.d.ts → types/acorex-platform-common.d.ts} +261 -24
- package/{core/index.d.ts → types/acorex-platform-core.d.ts} +163 -42
- package/{domain/index.d.ts → types/acorex-platform-domain.d.ts} +744 -412
- package/{layout/builder/index.d.ts → types/acorex-platform-layout-builder.d.ts} +137 -38
- package/{layout/components/index.d.ts → types/acorex-platform-layout-components.d.ts} +808 -131
- package/{layout/designer/index.d.ts → types/acorex-platform-layout-designer.d.ts} +96 -18
- package/{layout/entity/index.d.ts → types/acorex-platform-layout-entity.d.ts} +686 -61
- package/{layout/views/index.d.ts → types/acorex-platform-layout-views.d.ts} +80 -47
- package/{layout/widget-core/index.d.ts → types/acorex-platform-layout-widget-core.d.ts} +274 -197
- package/{layout/widgets/index.d.ts → types/acorex-platform-layout-widgets.d.ts} +583 -104
- package/{native/index.d.ts → types/acorex-platform-native.d.ts} +0 -7
- package/types/acorex-platform-runtime.d.ts +565 -0
- package/{themes/default/index.d.ts → types/acorex-platform-themes-default.d.ts} +105 -4
- package/{themes/shared/index.d.ts → types/acorex-platform-themes-shared.d.ts} +14 -5
- package/{workflow/index.d.ts → types/acorex-platform-workflow.d.ts} +96 -81
- package/fesm2022/acorex-platform-common-common-settings.provider-41RhWqb4.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CSxCnzwU.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-CPBzE96V.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-Dtv6U3df.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-QxJfswhK.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-CVdssZBD.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-BCxE0RTB.mjs +0 -111
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-BCxE0RTB.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-DVaZN9QN.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-DPGHgXa6.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-CdiNW691.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-D4hU2SCE.mjs +0 -160
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-D4hU2SCE.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-CLDoygoI.mjs +0 -1610
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-CLDoygoI.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-BVTklnzs.mjs +0 -120
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-BVTklnzs.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-rGsMVAZj.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-401.component-53VB-PS_.mjs +0 -31
- package/fesm2022/acorex-platform-themes-default-error-401.component-53VB-PS_.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-404.component-DVF9soT5.mjs +0 -25
- package/fesm2022/acorex-platform-themes-default-error-404.component-DVF9soT5.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-offline.component-CwNNHzZn.mjs +0 -19
- package/fesm2022/acorex-platform-themes-default-error-offline.component-CwNNHzZn.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-TJ9PWHMY.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-BHcKkIx0.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-BUPs84MI.mjs +0 -65
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-BUPs84MI.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-BotknoHn.mjs +0 -64
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-BotknoHn.mjs.map +0 -1
- package/runtime/index.d.ts +0 -307
- /package/{index.d.ts → types/acorex-platform.d.ts} +0 -0
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import * as i5 from '@angular/common';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { Injectable, inject, input, model, signal, effect, output, viewChild, ChangeDetectionStrategy, Component, NgModule, EventEmitter, Output } from '@angular/core';
|
|
4
|
+
import { Injectable, inject, input, model, signal, computed, effect, output, viewChild, ChangeDetectionStrategy, Component, NgModule, EventEmitter, Output } from '@angular/core';
|
|
5
|
+
import { provideCommandSetups } from '@acorex/platform/runtime';
|
|
5
6
|
import { AXPopupService } from '@acorex/components/popup';
|
|
7
|
+
import * as i4 from '@acorex/platform/core';
|
|
8
|
+
import { AXPHookService, AXPExpressionEvaluatorService, AXPComponentSlotModule, AXPContextStore } from '@acorex/platform/core';
|
|
6
9
|
import * as i1 from '@acorex/platform/layout/widget-core';
|
|
7
|
-
import { AXPWidgetSerializationHelper, AXPWidgetContainerComponent, AXPPageStatus, AXPWidgetCoreModule } from '@acorex/platform/layout/widget-core';
|
|
8
|
-
import { cloneDeep, isNil, set, isEqual } from 'lodash-es';
|
|
10
|
+
import { AXPWidgetSerializationHelper, AXPWidgetContainerComponent, AXPPageStatus, AXPWidgetCoreModule, AXPWidgetRegistryService } from '@acorex/platform/layout/widget-core';
|
|
11
|
+
import { cloneDeep, isNil, set, isEqual, merge } from 'lodash-es';
|
|
9
12
|
import * as i2 from '@acorex/components/form';
|
|
10
13
|
import { AXFormComponent, AXFormModule } from '@acorex/components/form';
|
|
11
14
|
import { Subject, debounceTime, distinctUntilChanged, startWith } from 'rxjs';
|
|
@@ -17,9 +20,26 @@ import * as i3 from '@acorex/components/loading';
|
|
|
17
20
|
import { AXLoadingModule } from '@acorex/components/loading';
|
|
18
21
|
import { AXBasePageComponent } from '@acorex/components/page';
|
|
19
22
|
import * as i6 from '@acorex/core/translation';
|
|
20
|
-
import { AXTranslationModule } from '@acorex/core/translation';
|
|
21
|
-
import
|
|
22
|
-
|
|
23
|
+
import { AXTranslationModule, AXTranslationService } from '@acorex/core/translation';
|
|
24
|
+
import { AXP_ENTITY_DEFINITION_CRUD_SERVICE } from '@acorex/platform/domain';
|
|
25
|
+
|
|
26
|
+
//#region ---- Imports ----
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region ---- Before open ----
|
|
29
|
+
/**
|
|
30
|
+
* Runs after dialog options and context are prepared and **before** footer customization and popup open.
|
|
31
|
+
* Listeners may mutate {@link AXPLayoutBuilderDialogBeforeOpenPayload.context} by reference.
|
|
32
|
+
*/
|
|
33
|
+
const AXP_LAYOUT_BUILDER_DIALOG_BEFORE_OPEN_HOOK_KEY = 'layout-builder.dialog.before-open';
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region ---- Footer actions ----
|
|
36
|
+
/**
|
|
37
|
+
* Runs after builder-defined footer actions exist and **before** the dialog opens.
|
|
38
|
+
* Listeners receive the live `actions.footer.prefix` / `suffix` arrays (same references as the dialog)
|
|
39
|
+
* so they may push, splice, filter, or replace items. They may also mutate {@link AXPLayoutBuilderDialogFooterPayload.context} by reference.
|
|
40
|
+
*/
|
|
41
|
+
const AXP_LAYOUT_BUILDER_DIALOG_CONFIG_HOOK_KEY = 'layout-builder.dialog.config';
|
|
42
|
+
//#endregion
|
|
23
43
|
|
|
24
44
|
class AXPLayoutConversionService {
|
|
25
45
|
constructor() {
|
|
@@ -159,6 +179,10 @@ class AXPLayoutConversionService {
|
|
|
159
179
|
if (!editorWidget.mode) {
|
|
160
180
|
editorWidget.mode = fieldMode;
|
|
161
181
|
}
|
|
182
|
+
const hintOpts = field.description != null &&
|
|
183
|
+
(typeof field.description !== 'string' || field.description.trim().length > 0)
|
|
184
|
+
? { hint: field.description, hintDisplayMode: 'note' }
|
|
185
|
+
: {};
|
|
162
186
|
return {
|
|
163
187
|
type: 'form-field',
|
|
164
188
|
name: field.path,
|
|
@@ -166,8 +190,8 @@ class AXPLayoutConversionService {
|
|
|
166
190
|
options: {
|
|
167
191
|
label: field.title,
|
|
168
192
|
badge: field.badge,
|
|
169
|
-
description: field.description,
|
|
170
193
|
showLabel: true,
|
|
194
|
+
...hintOpts,
|
|
171
195
|
},
|
|
172
196
|
children: [editorWidget], // The editor widget becomes a child of form-field
|
|
173
197
|
};
|
|
@@ -210,7 +234,7 @@ class AXPLayoutConversionService {
|
|
|
210
234
|
path: formFieldNode.name || editorWidget.name || `field-${Date.now()}`,
|
|
211
235
|
title: formFieldNode.options?.['label'],
|
|
212
236
|
badge: formFieldNode.options?.['badge'],
|
|
213
|
-
description: formFieldNode.options?.['
|
|
237
|
+
description: formFieldNode.options?.['hint'],
|
|
214
238
|
widget: editorWidget,
|
|
215
239
|
mode: formFieldNode.mode,
|
|
216
240
|
};
|
|
@@ -223,9 +247,16 @@ class AXPLayoutConversionService {
|
|
|
223
247
|
const keyParts = [];
|
|
224
248
|
keyParts.push(`groups:${formDefinition.groups.length}`);
|
|
225
249
|
formDefinition.groups.forEach((group, groupIndex) => {
|
|
226
|
-
|
|
250
|
+
// Include group.mode so view vs edit (or mixed) layouts do not share a cached widget tree.
|
|
251
|
+
const groupModePart = group.mode ?? '_';
|
|
252
|
+
keyParts.push(`g${groupIndex}:${group.name}:${group.parameters.length}:${groupModePart}`);
|
|
253
|
+
keyParts.push(`gL${groupIndex}:${JSON.stringify(group.title ?? null)}:${JSON.stringify(group.description ?? null)}`);
|
|
227
254
|
group.parameters.forEach((param, paramIndex) => {
|
|
228
|
-
|
|
255
|
+
// Field mode must be part of the key; otherwise metadata forms that only differ by
|
|
256
|
+
// view/edit (same paths and widget types) incorrectly reuse the first cached tree.
|
|
257
|
+
const fieldModePart = param.mode ?? '_';
|
|
258
|
+
keyParts.push(`p${groupIndex}.${paramIndex}:${param.path}:${param.widget.type}:${fieldModePart}`);
|
|
259
|
+
keyParts.push(`pL${groupIndex}.${paramIndex}:${JSON.stringify(param.title ?? null)}:${JSON.stringify(param.description ?? null)}:${JSON.stringify(param.badge ?? null)}`);
|
|
229
260
|
});
|
|
230
261
|
});
|
|
231
262
|
if (formDefinition.mode) {
|
|
@@ -286,10 +317,10 @@ class AXPLayoutConversionService {
|
|
|
286
317
|
}
|
|
287
318
|
return Math.abs(hash).toString(36); // Convert to base36 for shorter string
|
|
288
319
|
}
|
|
289
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
290
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
320
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutConversionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
321
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutConversionService, providedIn: 'root' }); }
|
|
291
322
|
}
|
|
292
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
323
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutConversionService, decorators: [{
|
|
293
324
|
type: Injectable,
|
|
294
325
|
args: [{
|
|
295
326
|
providedIn: 'root',
|
|
@@ -399,17 +430,18 @@ function getNestedValue(obj, path) {
|
|
|
399
430
|
class AXPLayoutBuilderService {
|
|
400
431
|
constructor() {
|
|
401
432
|
this.popupService = inject(AXPopupService);
|
|
433
|
+
this.hookService = inject(AXPHookService, { optional: true }) ?? undefined;
|
|
402
434
|
}
|
|
403
435
|
/**
|
|
404
436
|
* Create a new layout builder
|
|
405
437
|
*/
|
|
406
438
|
create() {
|
|
407
|
-
return new LayoutBuilder(this.popupService);
|
|
439
|
+
return new LayoutBuilder(this.popupService, this.hookService);
|
|
408
440
|
}
|
|
409
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
410
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
441
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutBuilderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
442
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutBuilderService, providedIn: 'root' }); }
|
|
411
443
|
}
|
|
412
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
444
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutBuilderService, decorators: [{
|
|
413
445
|
type: Injectable,
|
|
414
446
|
args: [{
|
|
415
447
|
providedIn: 'root',
|
|
@@ -422,8 +454,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
422
454
|
* Open/Closed: Extensible through container delegates
|
|
423
455
|
*/
|
|
424
456
|
class LayoutBuilder {
|
|
425
|
-
constructor(popupService) {
|
|
457
|
+
constructor(popupService, hookService) {
|
|
426
458
|
this.popupService = popupService;
|
|
459
|
+
this.hookService = hookService;
|
|
427
460
|
this.root = {
|
|
428
461
|
children: [],
|
|
429
462
|
mode: 'edit',
|
|
@@ -493,7 +526,7 @@ class LayoutBuilder {
|
|
|
493
526
|
if (!this.popupService) {
|
|
494
527
|
throw new Error('LayoutBuilder requires AXPopupService to create dialogs. Please inject it in the service constructor.');
|
|
495
528
|
}
|
|
496
|
-
const container = new DialogContainerBuilder(this.popupService);
|
|
529
|
+
const container = new DialogContainerBuilder(this.popupService, this.hookService);
|
|
497
530
|
if (delegate) {
|
|
498
531
|
delegate(container);
|
|
499
532
|
}
|
|
@@ -518,11 +551,21 @@ class LayoutBuilder {
|
|
|
518
551
|
return this;
|
|
519
552
|
}
|
|
520
553
|
build() {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
mode:
|
|
554
|
+
const r = this.root;
|
|
555
|
+
const node = {
|
|
556
|
+
type: r.type,
|
|
557
|
+
...(r.mode !== undefined ? { mode: r.mode } : {}),
|
|
558
|
+
...(r.children !== undefined ? { children: r.children } : {}),
|
|
559
|
+
...(r.options !== undefined ? { options: r.options } : {}),
|
|
560
|
+
...(r.name !== undefined ? { name: r.name } : {}),
|
|
561
|
+
...(r.path !== undefined ? { path: r.path } : {}),
|
|
562
|
+
...(r.visible !== undefined ? { visible: r.visible } : {}),
|
|
563
|
+
...(r.defaultValue !== undefined ? { defaultValue: r.defaultValue } : {}),
|
|
564
|
+
...(r.triggers !== undefined ? { triggers: r.triggers } : {}),
|
|
565
|
+
...(r.meta !== undefined ? { meta: r.meta } : {}),
|
|
566
|
+
...(r.valueTransforms !== undefined ? { valueTransforms: r.valueTransforms } : {}),
|
|
525
567
|
};
|
|
568
|
+
return node;
|
|
526
569
|
}
|
|
527
570
|
/**
|
|
528
571
|
* Converts the built widget node to JSON string
|
|
@@ -591,6 +634,7 @@ class BaseContainerBuilder {
|
|
|
591
634
|
'number-editor',
|
|
592
635
|
'select-editor',
|
|
593
636
|
'lookup-editor',
|
|
637
|
+
'entity-definition-provider-editor',
|
|
594
638
|
'selection-list-editor',
|
|
595
639
|
'date-time-editor',
|
|
596
640
|
'toggle-editor',
|
|
@@ -693,32 +737,30 @@ class BaseContainerMixin extends BaseContainerBuilder {
|
|
|
693
737
|
class LayoutContainerMixin extends BaseContainerMixin {
|
|
694
738
|
layout(value) {
|
|
695
739
|
// Map layout intent to grid item sizing so containers like `form-field`
|
|
696
|
-
// can span multiple columns inside grid/fieldset layouts.
|
|
740
|
+
// can span multiple columns/rows inside grid/fieldset layouts.
|
|
697
741
|
if (!this.containerState.options)
|
|
698
742
|
this.containerState.options = {};
|
|
699
743
|
if (typeof value === 'number') {
|
|
700
|
-
// Direct numeric shorthand → colSpan
|
|
701
744
|
this.containerState.options.colSpan = value;
|
|
702
745
|
}
|
|
703
746
|
else if (value) {
|
|
704
|
-
// Try to extract grid positioning from breakpoint positions
|
|
705
747
|
const positions = value.positions;
|
|
706
748
|
if (positions) {
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
if (
|
|
711
|
-
|
|
712
|
-
if (
|
|
713
|
-
|
|
714
|
-
if (
|
|
715
|
-
|
|
716
|
-
if (
|
|
717
|
-
|
|
718
|
-
if (
|
|
719
|
-
|
|
720
|
-
if (
|
|
721
|
-
|
|
749
|
+
const placement = positions?.lg ?? positions?.xl ?? positions?.xxl ?? positions?.md ?? positions?.sm;
|
|
750
|
+
if (placement) {
|
|
751
|
+
const opts = this.containerState.options;
|
|
752
|
+
if (placement.colSpan != null)
|
|
753
|
+
opts.colSpan = placement.colSpan;
|
|
754
|
+
if (placement.colStart != null)
|
|
755
|
+
opts.colStart = placement.colStart;
|
|
756
|
+
if (placement.colEnd != null)
|
|
757
|
+
opts.colEnd = placement.colEnd;
|
|
758
|
+
if (placement.rowSpan != null)
|
|
759
|
+
opts.rowSpan = placement.rowSpan;
|
|
760
|
+
if (placement.rowStart != null)
|
|
761
|
+
opts.rowStart = placement.rowStart;
|
|
762
|
+
if (placement.rowEnd != null)
|
|
763
|
+
opts.rowEnd = placement.rowEnd;
|
|
722
764
|
}
|
|
723
765
|
}
|
|
724
766
|
}
|
|
@@ -937,6 +979,7 @@ class WidgetContainerMixin extends ChildContainerMixin {
|
|
|
937
979
|
'number-editor',
|
|
938
980
|
'select-editor',
|
|
939
981
|
'lookup-editor',
|
|
982
|
+
'entity-definition-provider-editor',
|
|
940
983
|
'selection-list-editor',
|
|
941
984
|
'date-time-editor',
|
|
942
985
|
'toggle-editor',
|
|
@@ -992,12 +1035,73 @@ class FlexContainerBuilder extends WidgetContainerMixin {
|
|
|
992
1035
|
* Grid Container Builder - Liskov Substitution Principle
|
|
993
1036
|
* Extends WidgetContainerMixin to inherit all common functionality
|
|
994
1037
|
*/
|
|
1038
|
+
/**
|
|
1039
|
+
* Extracts flat grid-item options from AXPGridLayoutOptions for grid-item-layout widget.
|
|
1040
|
+
* Uses first available breakpoint (lg, xl, md, sm).
|
|
1041
|
+
*/
|
|
1042
|
+
/**
|
|
1043
|
+
* Deep-merges grid breakpoint buckets so sequential fluent calls (e.g. setColumns then setGap)
|
|
1044
|
+
* do not wipe sibling keys under options.grid.default.
|
|
1045
|
+
*/
|
|
1046
|
+
function mergeAXPGridContainerOptions(prev, patch) {
|
|
1047
|
+
const next = { ...(prev ?? {}), ...patch };
|
|
1048
|
+
if (prev?.grid?.default || patch.grid?.default) {
|
|
1049
|
+
next.grid = {
|
|
1050
|
+
...(prev?.grid ?? {}),
|
|
1051
|
+
...(patch.grid ?? {}),
|
|
1052
|
+
default: {
|
|
1053
|
+
...(prev?.grid?.default ?? {}),
|
|
1054
|
+
...(patch.grid?.default ?? {}),
|
|
1055
|
+
},
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
return next;
|
|
1059
|
+
}
|
|
1060
|
+
function toGridItemOptions(layoutOptions) {
|
|
1061
|
+
if (!layoutOptions?.positions)
|
|
1062
|
+
return { colSpan: 12 };
|
|
1063
|
+
const positions = layoutOptions.positions;
|
|
1064
|
+
const placement = positions['lg'] ?? positions['xl'] ?? positions['xxl'] ?? positions['md'] ?? positions['sm'];
|
|
1065
|
+
if (!placement)
|
|
1066
|
+
return { colSpan: 12 };
|
|
1067
|
+
const opts = {};
|
|
1068
|
+
if (placement['colSpan'] != null)
|
|
1069
|
+
opts['colSpan'] = placement['colSpan'];
|
|
1070
|
+
if (placement['colStart'] != null)
|
|
1071
|
+
opts['colStart'] = placement['colStart'];
|
|
1072
|
+
if (placement['colEnd'] != null)
|
|
1073
|
+
opts['colEnd'] = placement['colEnd'];
|
|
1074
|
+
if (placement['rowSpan'] != null)
|
|
1075
|
+
opts['rowSpan'] = placement['rowSpan'];
|
|
1076
|
+
if (placement['rowStart'] != null)
|
|
1077
|
+
opts['rowStart'] = placement['rowStart'];
|
|
1078
|
+
if (placement['rowEnd'] != null)
|
|
1079
|
+
opts['rowEnd'] = placement['rowEnd'];
|
|
1080
|
+
if (Object.keys(opts).length === 0)
|
|
1081
|
+
opts['colSpan'] = 12;
|
|
1082
|
+
return opts;
|
|
1083
|
+
}
|
|
995
1084
|
class GridContainerBuilder extends WidgetContainerMixin {
|
|
996
1085
|
constructor() {
|
|
997
1086
|
super('grid-layout');
|
|
998
1087
|
}
|
|
999
1088
|
setOptions(options) {
|
|
1000
|
-
this.containerState.options =
|
|
1089
|
+
this.containerState.options = mergeAXPGridContainerOptions(this.containerState.options, options);
|
|
1090
|
+
return this;
|
|
1091
|
+
}
|
|
1092
|
+
item(layoutOptions, delegate) {
|
|
1093
|
+
const fieldset = new FieldsetContainerBuilder();
|
|
1094
|
+
fieldset.withInheritanceContext(this.inheritanceContext);
|
|
1095
|
+
delegate(fieldset);
|
|
1096
|
+
const fieldsetNode = fieldset.build();
|
|
1097
|
+
const gridItemOptions = toGridItemOptions(layoutOptions);
|
|
1098
|
+
const gridItemNode = {
|
|
1099
|
+
type: 'grid-item-layout',
|
|
1100
|
+
options: gridItemOptions,
|
|
1101
|
+
children: [fieldsetNode],
|
|
1102
|
+
};
|
|
1103
|
+
this.ensureChildren();
|
|
1104
|
+
this.containerState.children.push(gridItemNode);
|
|
1001
1105
|
return this;
|
|
1002
1106
|
}
|
|
1003
1107
|
// Individual fluent methods for Grid
|
|
@@ -1428,7 +1532,7 @@ class ListWidgetBuilder extends WidgetContainerMixin {
|
|
|
1428
1532
|
* Uses composition instead of inheritance for cleaner separation
|
|
1429
1533
|
*/
|
|
1430
1534
|
class DialogContainerBuilder {
|
|
1431
|
-
constructor(popupService) {
|
|
1535
|
+
constructor(popupService, hookService) {
|
|
1432
1536
|
this.dialogState = {
|
|
1433
1537
|
type: 'flex-layout', // This will be overridden when content layout exists
|
|
1434
1538
|
children: [],
|
|
@@ -1451,6 +1555,7 @@ class DialogContainerBuilder {
|
|
|
1451
1555
|
else {
|
|
1452
1556
|
this.popupService = inject(AXPopupService);
|
|
1453
1557
|
}
|
|
1558
|
+
this.hookService = hookService ?? inject(AXPHookService, { optional: true }) ?? undefined;
|
|
1454
1559
|
}
|
|
1455
1560
|
setOptions(options) {
|
|
1456
1561
|
this.dialogState.dialogOptions = { ...this.dialogState.dialogOptions, ...options };
|
|
@@ -1491,7 +1596,12 @@ class DialogContainerBuilder {
|
|
|
1491
1596
|
return this;
|
|
1492
1597
|
}
|
|
1493
1598
|
onAction(handler) {
|
|
1494
|
-
|
|
1599
|
+
this.dialogState.dialogOptions ??= {
|
|
1600
|
+
title: '',
|
|
1601
|
+
size: 'md',
|
|
1602
|
+
closeButton: false,
|
|
1603
|
+
};
|
|
1604
|
+
this.dialogState.dialogOptions.onAction = handler;
|
|
1495
1605
|
return this;
|
|
1496
1606
|
}
|
|
1497
1607
|
addCustomAction(action) {
|
|
@@ -1540,21 +1650,40 @@ class DialogContainerBuilder {
|
|
|
1540
1650
|
const dialogNode = this.build();
|
|
1541
1651
|
// Import the dialog renderer component dynamically
|
|
1542
1652
|
const { AXPDialogRendererComponent } = await Promise.resolve().then(function () { return dialogRenderer_component; });
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1653
|
+
this.dialogState.dialogOptions ??= {};
|
|
1654
|
+
if (this.dialogState.dialogOptions.context == null || typeof this.dialogState.dialogOptions.context !== 'object') {
|
|
1655
|
+
this.dialogState.dialogOptions.context = {};
|
|
1656
|
+
}
|
|
1657
|
+
const initialContext = this.dialogState.dialogOptions.context;
|
|
1658
|
+
this.dialogState.actions ??= { footer: { prefix: [], suffix: [] } };
|
|
1659
|
+
this.dialogState.actions.footer ??= { prefix: [], suffix: [] };
|
|
1660
|
+
this.dialogState.actions.footer.prefix ??= [];
|
|
1661
|
+
this.dialogState.actions.footer.suffix ??= [];
|
|
1662
|
+
const hookService = this.hookService;
|
|
1663
|
+
if (hookService) {
|
|
1664
|
+
const beforePayload = {
|
|
1665
|
+
context: initialContext,
|
|
1666
|
+
dialogOptions: this.dialogState.dialogOptions,
|
|
1667
|
+
};
|
|
1668
|
+
await hookService.runAsync(AXP_LAYOUT_BUILDER_DIALOG_BEFORE_OPEN_HOOK_KEY, beforePayload);
|
|
1669
|
+
}
|
|
1547
1670
|
// Create dialog configuration
|
|
1548
1671
|
const dialogConfig = {
|
|
1549
1672
|
title: this.dialogState.dialogOptions?.title || '',
|
|
1550
1673
|
message: this.dialogState.dialogOptions?.message,
|
|
1551
1674
|
context: initialContext,
|
|
1552
1675
|
definition: dialogNode,
|
|
1676
|
+
metadata: this.dialogState.dialogOptions.metadata,
|
|
1553
1677
|
actions: this.dialogState.actions,
|
|
1554
1678
|
onAction: this.dialogState.dialogOptions?.onAction,
|
|
1555
1679
|
};
|
|
1680
|
+
//
|
|
1681
|
+
if (hookService) {
|
|
1682
|
+
await hookService.runAsync(AXP_LAYOUT_BUILDER_DIALOG_CONFIG_HOOK_KEY, dialogConfig);
|
|
1683
|
+
}
|
|
1556
1684
|
// The Promise resolves when user clicks an action button
|
|
1557
1685
|
return new Promise(async (resolve) => {
|
|
1686
|
+
let flag = false;
|
|
1558
1687
|
this.popupService.open(AXPDialogRendererComponent, {
|
|
1559
1688
|
title: dialogConfig.title,
|
|
1560
1689
|
size: this.dialogState.dialogOptions?.size || 'md',
|
|
@@ -1564,10 +1693,14 @@ class DialogContainerBuilder {
|
|
|
1564
1693
|
data: {
|
|
1565
1694
|
config: dialogConfig,
|
|
1566
1695
|
callBack: (result) => {
|
|
1696
|
+
flag = true;
|
|
1567
1697
|
resolve(result);
|
|
1568
1698
|
},
|
|
1569
1699
|
},
|
|
1570
1700
|
});
|
|
1701
|
+
if (!flag) {
|
|
1702
|
+
resolve({ success: false });
|
|
1703
|
+
}
|
|
1571
1704
|
});
|
|
1572
1705
|
}
|
|
1573
1706
|
}
|
|
@@ -1769,10 +1902,19 @@ class ActionBuilder {
|
|
|
1769
1902
|
return this;
|
|
1770
1903
|
}
|
|
1771
1904
|
custom(action) {
|
|
1772
|
-
|
|
1773
|
-
|
|
1905
|
+
const position = action.position ?? 'suffix';
|
|
1906
|
+
if (position === 'prefix') {
|
|
1907
|
+
if (!this.dialogBuilder['dialogState'].actions.footer.prefix) {
|
|
1908
|
+
this.dialogBuilder['dialogState'].actions.footer.prefix = [];
|
|
1909
|
+
}
|
|
1910
|
+
this.dialogBuilder['dialogState'].actions.footer.prefix.push(action);
|
|
1911
|
+
}
|
|
1912
|
+
else {
|
|
1913
|
+
if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
|
|
1914
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix = [];
|
|
1915
|
+
}
|
|
1916
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix.push(action);
|
|
1774
1917
|
}
|
|
1775
|
-
this.dialogBuilder['dialogState'].actions.footer.suffix.push(action);
|
|
1776
1918
|
return this;
|
|
1777
1919
|
}
|
|
1778
1920
|
}
|
|
@@ -1921,22 +2063,27 @@ class AXPLayoutRendererComponent {
|
|
|
1921
2063
|
/**
|
|
1922
2064
|
* Form definition containing groups and fields OR widget tree
|
|
1923
2065
|
*/
|
|
1924
|
-
this.layout = input.required(...(ngDevMode ? [{ debugName: "layout" }] : []));
|
|
2066
|
+
this.layout = input.required(...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
|
|
1925
2067
|
/**
|
|
1926
2068
|
* Form context/model data
|
|
1927
2069
|
*/
|
|
1928
|
-
this.context = model({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
2070
|
+
this.context = model({}, ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
|
|
1929
2071
|
/**
|
|
1930
2072
|
* Form appearance and density styling (normal, compact, spacious)
|
|
1931
2073
|
*/
|
|
1932
|
-
this.look = input('fieldset', ...(ngDevMode ? [{ debugName: "look" }] : []));
|
|
2074
|
+
this.look = input('fieldset', ...(ngDevMode ? [{ debugName: "look" }] : /* istanbul ignore next */ []));
|
|
1933
2075
|
/**
|
|
1934
2076
|
* Default form mode. Can be overridden by section/group and field.
|
|
1935
2077
|
*/
|
|
1936
|
-
this.mode = input('edit', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
2078
|
+
this.mode = input('edit', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
1937
2079
|
//#endregion
|
|
1938
2080
|
//#region ---- Widget Tree Conversion ----
|
|
1939
|
-
this.widgetTree = signal(null, ...(ngDevMode ? [{ debugName: "widgetTree" }] : []));
|
|
2081
|
+
this.widgetTree = signal(null, ...(ngDevMode ? [{ debugName: "widgetTree" }] : /* istanbul ignore next */ []));
|
|
2082
|
+
/**
|
|
2083
|
+
* Prefer explicit {@link AXPWidgetNode.mode} on the root node (e.g. dialog flex `mode('view')`)
|
|
2084
|
+
* so nested widgets resolve view vs edit correctly; fall back to the layout `mode` input.
|
|
2085
|
+
*/
|
|
2086
|
+
this.effectiveRenderMode = computed(() => this.widgetTree()?.mode ?? this.mode(), ...(ngDevMode ? [{ debugName: "effectiveRenderMode" }] : /* istanbul ignore next */ []));
|
|
1940
2087
|
/**
|
|
1941
2088
|
* Convert layout data to widget tree when inputs change
|
|
1942
2089
|
*/
|
|
@@ -1961,7 +2108,7 @@ class AXPLayoutRendererComponent {
|
|
|
1961
2108
|
if (!isEqual(prev, tree)) {
|
|
1962
2109
|
this.widgetTree.set(tree);
|
|
1963
2110
|
}
|
|
1964
|
-
}, ...(ngDevMode ? [{ debugName: "conversionEffect" }] : []));
|
|
2111
|
+
}, ...(ngDevMode ? [{ debugName: "conversionEffect" }] : /* istanbul ignore next */ []));
|
|
1965
2112
|
//#endregion
|
|
1966
2113
|
//#region ---- Outputs ----
|
|
1967
2114
|
/**
|
|
@@ -1974,12 +2121,12 @@ class AXPLayoutRendererComponent {
|
|
|
1974
2121
|
this.validityChange = output();
|
|
1975
2122
|
//#endregion
|
|
1976
2123
|
//#region ---- Properties ----
|
|
1977
|
-
this.form = viewChild(AXFormComponent, ...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
1978
|
-
this.container = viewChild(AXPWidgetContainerComponent, ...(ngDevMode ? [{ debugName: "container" }] : []));
|
|
2124
|
+
this.form = viewChild(AXFormComponent, ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
|
|
2125
|
+
this.container = viewChild(AXPWidgetContainerComponent, ...(ngDevMode ? [{ debugName: "container" }] : /* istanbul ignore next */ []));
|
|
1979
2126
|
/**
|
|
1980
2127
|
* Internal context signal for reactivity
|
|
1981
2128
|
*/
|
|
1982
|
-
this.internalContext = signal({}, ...(ngDevMode ? [{ debugName: "internalContext" }] : []));
|
|
2129
|
+
this.internalContext = signal({}, ...(ngDevMode ? [{ debugName: "internalContext" }] : /* istanbul ignore next */ []));
|
|
1983
2130
|
/**
|
|
1984
2131
|
* Initial context for reset functionality
|
|
1985
2132
|
*/
|
|
@@ -1992,7 +2139,7 @@ class AXPLayoutRendererComponent {
|
|
|
1992
2139
|
this.#contextSyncEffect = effect(() => {
|
|
1993
2140
|
const ctx = this.context() ?? {};
|
|
1994
2141
|
this.contextUpdateSubject.next(ctx);
|
|
1995
|
-
}, ...(ngDevMode ? [{ debugName: "#contextSyncEffect" }] : []));
|
|
2142
|
+
}, ...(ngDevMode ? [{ debugName: "#contextSyncEffect" }] : /* istanbul ignore next */ []));
|
|
1996
2143
|
/**
|
|
1997
2144
|
* Effect to handle widget tree status changes
|
|
1998
2145
|
*/
|
|
@@ -2001,7 +2148,7 @@ class AXPLayoutRendererComponent {
|
|
|
2001
2148
|
if (widgetTree) {
|
|
2002
2149
|
this.container()?.builderService.setStatus(AXPPageStatus.Rendered);
|
|
2003
2150
|
}
|
|
2004
|
-
}, ...(ngDevMode ? [{ debugName: "#widgetStatusEffect" }] : []));
|
|
2151
|
+
}, ...(ngDevMode ? [{ debugName: "#widgetStatusEffect" }] : /* istanbul ignore next */ []));
|
|
2005
2152
|
}
|
|
2006
2153
|
//#endregion
|
|
2007
2154
|
//#region ---- Lifecycle Methods ----
|
|
@@ -2141,40 +2288,67 @@ class AXPLayoutRendererComponent {
|
|
|
2141
2288
|
isWidgetNode(data) {
|
|
2142
2289
|
return data && typeof data === 'object' && 'type' in data && typeof data.type === 'string';
|
|
2143
2290
|
}
|
|
2144
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2145
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
2291
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2292
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLayoutRendererComponent, isStandalone: true, selector: "axp-layout-renderer", inputs: { layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { context: "contextChange", contextInitiated: "contextInitiated", validityChange: "validityChange" }, viewQueries: [{ propertyName: "form", first: true, predicate: AXFormComponent, descendants: true, isSignal: true }, { propertyName: "container", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
2146
2293
|
<ax-form>
|
|
2147
2294
|
<axp-widgets-container [context]="internalContext()" (onContextChanged)="handleContextChanged($event)">
|
|
2148
2295
|
@if (widgetTree()) {
|
|
2149
|
-
<ng-container
|
|
2296
|
+
<ng-container
|
|
2297
|
+
axp-widget-renderer
|
|
2298
|
+
[node]="widgetTree()!"
|
|
2299
|
+
[mode]="effectiveRenderMode()"
|
|
2300
|
+
></ng-container>
|
|
2150
2301
|
}
|
|
2151
2302
|
</axp-widgets-container>
|
|
2152
2303
|
</ax-form>
|
|
2153
|
-
`, isInline: true, styles: [":host{display:block;width:100%}\n"], dependencies: [{ kind: "ngmodule", type:
|
|
2304
|
+
`, isInline: true, styles: [":host{display:block;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i2.AXFormComponent, selector: "ax-form", inputs: ["disabled", "readonly", "labelMode", "look", "messageStyle", "updateOn", "inUserInteractionActive"], outputs: ["onValidate", "updateOnChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2154
2305
|
}
|
|
2155
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2306
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutRendererComponent, decorators: [{
|
|
2156
2307
|
type: Component,
|
|
2157
|
-
args: [{ selector: 'axp-layout-renderer', standalone: true, imports: [
|
|
2308
|
+
args: [{ selector: 'axp-layout-renderer', standalone: true, imports: [AXPWidgetCoreModule, AXFormModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
2158
2309
|
<ax-form>
|
|
2159
2310
|
<axp-widgets-container [context]="internalContext()" (onContextChanged)="handleContextChanged($event)">
|
|
2160
2311
|
@if (widgetTree()) {
|
|
2161
|
-
<ng-container
|
|
2312
|
+
<ng-container
|
|
2313
|
+
axp-widget-renderer
|
|
2314
|
+
[node]="widgetTree()!"
|
|
2315
|
+
[mode]="effectiveRenderMode()"
|
|
2316
|
+
></ng-container>
|
|
2162
2317
|
}
|
|
2163
2318
|
</axp-widgets-container>
|
|
2164
2319
|
</ax-form>
|
|
2165
2320
|
`, styles: [":host{display:block;width:100%}\n"] }]
|
|
2166
2321
|
}], propDecorators: { layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: true }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }, { type: i0.Output, args: ["contextChange"] }], look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], contextInitiated: [{ type: i0.Output, args: ["contextInitiated"] }], validityChange: [{ type: i0.Output, args: ["validityChange"] }], form: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXFormComponent), { isSignal: true }] }], container: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPWidgetContainerComponent), { isSignal: true }] }] } });
|
|
2167
2322
|
|
|
2323
|
+
/** Registration key for {@link AXPPreviewWidgetFieldCommand}; lives alone so `LayoutBuilderModule` can reference it without static-importing the command implementation. */
|
|
2324
|
+
const AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY = 'Widget:Preview';
|
|
2325
|
+
|
|
2168
2326
|
class LayoutBuilderModule {
|
|
2169
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2170
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "
|
|
2171
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "
|
|
2327
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: LayoutBuilderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
2328
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: LayoutBuilderModule, imports: [CommonModule, AXPLayoutRendererComponent], exports: [AXPLayoutRendererComponent] }); }
|
|
2329
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: LayoutBuilderModule, providers: [
|
|
2330
|
+
AXPLayoutBuilderService,
|
|
2331
|
+
provideCommandSetups([
|
|
2332
|
+
{
|
|
2333
|
+
key: AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY,
|
|
2334
|
+
command: () => Promise.resolve().then(function () { return previewWidgetField_command; }).then((c) => c.AXPPreviewWidgetFieldCommand),
|
|
2335
|
+
},
|
|
2336
|
+
]),
|
|
2337
|
+
], imports: [CommonModule, AXPLayoutRendererComponent] }); }
|
|
2172
2338
|
}
|
|
2173
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2339
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: LayoutBuilderModule, decorators: [{
|
|
2174
2340
|
type: NgModule,
|
|
2175
2341
|
args: [{
|
|
2176
2342
|
imports: [CommonModule, AXPLayoutRendererComponent],
|
|
2177
|
-
providers: [
|
|
2343
|
+
providers: [
|
|
2344
|
+
AXPLayoutBuilderService,
|
|
2345
|
+
provideCommandSetups([
|
|
2346
|
+
{
|
|
2347
|
+
key: AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY,
|
|
2348
|
+
command: () => Promise.resolve().then(function () { return previewWidgetField_command; }).then((c) => c.AXPPreviewWidgetFieldCommand),
|
|
2349
|
+
},
|
|
2350
|
+
]),
|
|
2351
|
+
],
|
|
2178
2352
|
exports: [AXPLayoutRendererComponent],
|
|
2179
2353
|
}]
|
|
2180
2354
|
}] });
|
|
@@ -2186,17 +2360,17 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2186
2360
|
super(...arguments);
|
|
2187
2361
|
this.result = new EventEmitter();
|
|
2188
2362
|
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
2189
|
-
this.context = signal({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
2363
|
+
this.context = signal({}, ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
|
|
2190
2364
|
// This will be set by the popup service automatically - same as dynamic-dialog
|
|
2191
2365
|
this.callBack = () => { };
|
|
2192
|
-
this.isDialogLoading = signal(false, ...(ngDevMode ? [{ debugName: "isDialogLoading" }] : []));
|
|
2366
|
+
this.isDialogLoading = signal(false, ...(ngDevMode ? [{ debugName: "isDialogLoading" }] : /* istanbul ignore next */ []));
|
|
2193
2367
|
// Aggregated actions for footer rendering
|
|
2194
|
-
this.footerPrefix = signal([], ...(ngDevMode ? [{ debugName: "footerPrefix" }] : []));
|
|
2195
|
-
this.footerSuffix = signal([], ...(ngDevMode ? [{ debugName: "footerSuffix" }] : []));
|
|
2368
|
+
this.footerPrefix = signal([], ...(ngDevMode ? [{ debugName: "footerPrefix" }] : /* istanbul ignore next */ []));
|
|
2369
|
+
this.footerSuffix = signal([], ...(ngDevMode ? [{ debugName: "footerSuffix" }] : /* istanbul ignore next */ []));
|
|
2196
2370
|
//#endregion
|
|
2197
2371
|
//#region ---- View Accessors ----
|
|
2198
2372
|
// Access the internal layout renderer to reach the widgets container injector
|
|
2199
|
-
this.layoutRenderer = viewChild(AXPLayoutRendererComponent, ...(ngDevMode ? [{ debugName: "layoutRenderer" }] : []));
|
|
2373
|
+
this.layoutRenderer = viewChild(AXPLayoutRendererComponent, ...(ngDevMode ? [{ debugName: "layoutRenderer" }] : /* istanbul ignore next */ []));
|
|
2200
2374
|
this.#eff = effect(() => {
|
|
2201
2375
|
let count = 0;
|
|
2202
2376
|
this.aggregateAndEvaluateActions();
|
|
@@ -2217,7 +2391,7 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2217
2391
|
this.aggregateAndEvaluateActions();
|
|
2218
2392
|
}, 200);
|
|
2219
2393
|
}
|
|
2220
|
-
}, ...(ngDevMode ? [{ debugName: "#eff" }] : []));
|
|
2394
|
+
}, ...(ngDevMode ? [{ debugName: "#eff" }] : /* istanbul ignore next */ []));
|
|
2221
2395
|
}
|
|
2222
2396
|
//#endregion
|
|
2223
2397
|
//#region ---- Lifecycle ----
|
|
@@ -2247,17 +2421,17 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2247
2421
|
return this.isDialogLoading();
|
|
2248
2422
|
}
|
|
2249
2423
|
async executeAction(action) {
|
|
2250
|
-
const cmd = action.command;
|
|
2251
|
-
if (cmd
|
|
2424
|
+
const cmd = this.resolveActionCommandName(action.command);
|
|
2425
|
+
if (this.shouldValidateBeforeAction(cmd)) {
|
|
2252
2426
|
const isValid = await this.layoutRenderer()?.validate();
|
|
2253
2427
|
if (!isValid?.result) {
|
|
2254
2428
|
return;
|
|
2255
2429
|
}
|
|
2256
2430
|
}
|
|
2257
|
-
if (
|
|
2431
|
+
if (cmd?.startsWith('widget:')) {
|
|
2258
2432
|
const parsed = this.parseWidgetCommand(cmd);
|
|
2259
2433
|
if (parsed.widgetName && parsed.action) {
|
|
2260
|
-
await this.
|
|
2434
|
+
await this.invokeWidget(parsed.widgetName, parsed.action, {});
|
|
2261
2435
|
await this.aggregateAndEvaluateActions();
|
|
2262
2436
|
return;
|
|
2263
2437
|
}
|
|
@@ -2265,17 +2439,15 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2265
2439
|
const context = this.context();
|
|
2266
2440
|
const onAction = this.config?.onAction;
|
|
2267
2441
|
if (onAction) {
|
|
2268
|
-
const dialogRef =
|
|
2269
|
-
close: (res) => this.close(res),
|
|
2270
|
-
context: () => this.context(),
|
|
2271
|
-
action: () => cmd ?? undefined,
|
|
2272
|
-
setLoading: (loading) => this.isDialogLoading.set(loading),
|
|
2273
|
-
};
|
|
2442
|
+
const dialogRef = this.createDialogRef(cmd);
|
|
2274
2443
|
try {
|
|
2275
2444
|
this.isDialogLoading.set(true);
|
|
2276
2445
|
const result = await Promise.resolve(onAction(dialogRef));
|
|
2446
|
+
if (result && typeof result === 'object' && result.keepDialogOpen) {
|
|
2447
|
+
return;
|
|
2448
|
+
}
|
|
2277
2449
|
this.callBack(result);
|
|
2278
|
-
this.
|
|
2450
|
+
await this.closeWithOptionalSkipValidate(result);
|
|
2279
2451
|
}
|
|
2280
2452
|
catch {
|
|
2281
2453
|
// Handler threw: stay open for retry, actions remain clickable
|
|
@@ -2293,15 +2465,57 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2293
2465
|
this.data.action = result.action;
|
|
2294
2466
|
}
|
|
2295
2467
|
this.callBack({
|
|
2468
|
+
...this.createDialogRef(cmd),
|
|
2469
|
+
action: () => result.action,
|
|
2470
|
+
});
|
|
2471
|
+
// Without `onAction`, only the configured cancel action dismisses the dialog (not submit/custom).
|
|
2472
|
+
if (cmd === 'cancel') {
|
|
2473
|
+
await this.close(result);
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
/** Whether the layout form should be validated before running this footer command. */
|
|
2477
|
+
shouldValidateBeforeAction(cmd) {
|
|
2478
|
+
if (!cmd || cmd === 'cancel' || cmd === 'entity-form-done') {
|
|
2479
|
+
return false;
|
|
2480
|
+
}
|
|
2481
|
+
if (cmd.startsWith('widget:')) {
|
|
2482
|
+
return false;
|
|
2483
|
+
}
|
|
2484
|
+
return true;
|
|
2485
|
+
}
|
|
2486
|
+
createDialogRef(actionCmd) {
|
|
2487
|
+
return {
|
|
2296
2488
|
close: (res) => {
|
|
2297
|
-
this.
|
|
2489
|
+
void this.closeWithOptionalSkipValidate(res);
|
|
2298
2490
|
},
|
|
2299
2491
|
context: () => this.context(),
|
|
2300
|
-
action: () =>
|
|
2301
|
-
setLoading: (loading) =>
|
|
2302
|
-
|
|
2492
|
+
action: () => actionCmd,
|
|
2493
|
+
setLoading: (loading) => this.isDialogLoading.set(loading),
|
|
2494
|
+
patchContext: (partial) => {
|
|
2495
|
+
const merged = merge({}, this.context(), partial);
|
|
2496
|
+
this.context.set(merged);
|
|
2497
|
+
this.layoutRenderer()?.updateContext(merged);
|
|
2303
2498
|
},
|
|
2304
|
-
|
|
2499
|
+
invokeWidget: (widgetName, method, opts) => this.invokeWidget(widgetName, method, opts ?? {}),
|
|
2500
|
+
};
|
|
2501
|
+
}
|
|
2502
|
+
async closeWithOptionalSkipValidate(result) {
|
|
2503
|
+
if (result && typeof result === 'object' && result.skipValidate) {
|
|
2504
|
+
this.result.emit(result);
|
|
2505
|
+
await super.close(result);
|
|
2506
|
+
return;
|
|
2507
|
+
}
|
|
2508
|
+
await this.close(result);
|
|
2509
|
+
}
|
|
2510
|
+
/** Resolves footer/widget action command to a string (e.g. `cancel`, `submit`, `widget:...`). */
|
|
2511
|
+
resolveActionCommandName(command) {
|
|
2512
|
+
if (typeof command === 'string') {
|
|
2513
|
+
return command;
|
|
2514
|
+
}
|
|
2515
|
+
if (command && typeof command === 'object' && 'name' in command) {
|
|
2516
|
+
return command.name;
|
|
2517
|
+
}
|
|
2518
|
+
return undefined;
|
|
2305
2519
|
}
|
|
2306
2520
|
parseWidgetCommand(cmd) {
|
|
2307
2521
|
// Expected 'widget:<widgetName>.<action>'
|
|
@@ -2313,7 +2527,7 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2313
2527
|
return {};
|
|
2314
2528
|
return { widgetName: rest.slice(0, dot), action: rest.slice(dot + 1) };
|
|
2315
2529
|
}
|
|
2316
|
-
async
|
|
2530
|
+
async invokeWidget(widgetName, apiMethod, opts) {
|
|
2317
2531
|
if (!this.widgetCoreService)
|
|
2318
2532
|
return;
|
|
2319
2533
|
try {
|
|
@@ -2323,16 +2537,20 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2323
2537
|
if (typeof fn === 'function') {
|
|
2324
2538
|
await Promise.resolve(fn({
|
|
2325
2539
|
close: (result) => {
|
|
2326
|
-
this.
|
|
2540
|
+
void this.closeWithOptionalSkipValidate(result);
|
|
2327
2541
|
},
|
|
2328
2542
|
context: () => this.context(),
|
|
2329
2543
|
setLoading: (loading) => {
|
|
2330
|
-
this.isDialogLoading.set(loading);
|
|
2544
|
+
(opts.setLoading ?? ((v) => this.isDialogLoading.set(v)))(loading);
|
|
2331
2545
|
},
|
|
2332
2546
|
}));
|
|
2547
|
+
// Footer predicates (e.g. wizard step) must refresh when the widget advances outside executeAction (e.g. dialogRef.invokeWidget after entity-form continue).
|
|
2548
|
+
await this.aggregateAndEvaluateActions();
|
|
2333
2549
|
}
|
|
2334
2550
|
}
|
|
2335
|
-
catch {
|
|
2551
|
+
catch {
|
|
2552
|
+
//
|
|
2553
|
+
}
|
|
2336
2554
|
}
|
|
2337
2555
|
async close(result) {
|
|
2338
2556
|
if (result) {
|
|
@@ -2382,6 +2600,7 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2382
2600
|
zone: 'footer',
|
|
2383
2601
|
placement,
|
|
2384
2602
|
scope: a.scope,
|
|
2603
|
+
predicateApiWidgetName: a.predicateApiWidgetName,
|
|
2385
2604
|
});
|
|
2386
2605
|
const prefix = (footer?.prefix || []).map((a) => mapOne(a, 'prefix'));
|
|
2387
2606
|
const suffix = (footer?.suffix || []).map((a) => mapOne(a, 'suffix'));
|
|
@@ -2391,16 +2610,18 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2391
2610
|
const out = [];
|
|
2392
2611
|
for (const a of actions) {
|
|
2393
2612
|
const parsed = typeof a.command === 'string' ? this.parseWidgetCommand(a.command) : {};
|
|
2394
|
-
const
|
|
2613
|
+
const widgetNameForApi = parsed.widgetName ?? a.predicateApiWidgetName;
|
|
2614
|
+
const api = widgetNameForApi ? await this.resolveApi(widgetNameForApi) : undefined;
|
|
2395
2615
|
const scope = {
|
|
2396
2616
|
api,
|
|
2397
|
-
widget: { name:
|
|
2617
|
+
widget: { name: widgetNameForApi },
|
|
2398
2618
|
dialog: { context: this.context() },
|
|
2399
2619
|
context: this.context(),
|
|
2400
2620
|
};
|
|
2401
2621
|
const disabled = await this.evalBool(a.disabled, scope);
|
|
2402
2622
|
const hidden = await this.evalBool(a.hidden, scope);
|
|
2403
|
-
|
|
2623
|
+
const resolvedTitle = (await this.evalActionTitle(a.title, scope)) ?? a.title;
|
|
2624
|
+
out.push({ ...a, disabled, hidden, title: resolvedTitle });
|
|
2404
2625
|
}
|
|
2405
2626
|
return out;
|
|
2406
2627
|
}
|
|
@@ -2418,6 +2639,25 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2418
2639
|
}
|
|
2419
2640
|
return value;
|
|
2420
2641
|
}
|
|
2642
|
+
/** Resolves footer action title when it contains {{ ... }} (e.g. wizard labels from dialog context). */
|
|
2643
|
+
async evalActionTitle(value, scope) {
|
|
2644
|
+
if (value == null || typeof value !== 'string' || !value.includes('{{')) {
|
|
2645
|
+
return value;
|
|
2646
|
+
}
|
|
2647
|
+
try {
|
|
2648
|
+
const result = await this.expressionEvaluator.evaluate(value, scope);
|
|
2649
|
+
if (typeof result === 'string' && result.length > 0) {
|
|
2650
|
+
return result;
|
|
2651
|
+
}
|
|
2652
|
+
if (result != null && result !== false) {
|
|
2653
|
+
return String(result);
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
catch {
|
|
2657
|
+
//
|
|
2658
|
+
}
|
|
2659
|
+
return value;
|
|
2660
|
+
}
|
|
2421
2661
|
async resolveApi(widgetName) {
|
|
2422
2662
|
try {
|
|
2423
2663
|
await this.widgetCoreService?.waitForWidget(widgetName, 2000);
|
|
@@ -2428,10 +2668,13 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2428
2668
|
return undefined;
|
|
2429
2669
|
}
|
|
2430
2670
|
}
|
|
2431
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2432
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
2671
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDialogRendererComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
2672
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPDialogRendererComponent, isStandalone: true, selector: "axp-dialog-renderer", outputs: { result: "result" }, providers: [AXPContextStore], viewQueries: [{ propertyName: "layoutRenderer", first: true, predicate: AXPLayoutRendererComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
2433
2673
|
<axp-component-slot name="dialog-header" [context]="context()"></axp-component-slot>
|
|
2434
|
-
<div class="
|
|
2674
|
+
<div class="p-4">
|
|
2675
|
+
@if (config.message) {
|
|
2676
|
+
<p class="mb-4 leading-relaxed">{{ config.message | translate | async }}</p>
|
|
2677
|
+
}
|
|
2435
2678
|
<axp-layout-renderer
|
|
2436
2679
|
[layout]="config.definition"
|
|
2437
2680
|
[context]="context()"
|
|
@@ -2484,9 +2727,9 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2484
2727
|
</ax-suffix>
|
|
2485
2728
|
</ax-footer>
|
|
2486
2729
|
}
|
|
2487
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AXPLayoutRendererComponent, selector: "axp-layout-renderer", inputs: ["layout", "context", "look", "mode"], outputs: ["contextChange", "contextInitiated", "validityChange"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i3.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXPComponentSlotModule }, { kind: "directive", type: i4.AXPComponentSlotDirective, selector: "axp-component-slot", inputs: ["name", "host", "context"], exportAs: ["slot"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }] }); }
|
|
2730
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AXPLayoutRendererComponent, selector: "axp-layout-renderer", inputs: ["layout", "context", "look", "mode"], outputs: ["contextChange", "contextInitiated", "validityChange"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i3.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXPComponentSlotModule }, { kind: "directive", type: i4.AXPComponentSlotDirective, selector: "axp-component-slot", inputs: ["name", "host", "context"], exportAs: ["slot"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2488
2731
|
}
|
|
2489
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2732
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDialogRendererComponent, decorators: [{
|
|
2490
2733
|
type: Component,
|
|
2491
2734
|
args: [{
|
|
2492
2735
|
selector: 'axp-dialog-renderer',
|
|
@@ -2500,9 +2743,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
2500
2743
|
AXTranslationModule,
|
|
2501
2744
|
AXPComponentSlotModule,
|
|
2502
2745
|
],
|
|
2746
|
+
providers: [AXPContextStore],
|
|
2747
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2503
2748
|
template: `
|
|
2504
2749
|
<axp-component-slot name="dialog-header" [context]="context()"></axp-component-slot>
|
|
2505
|
-
<div class="
|
|
2750
|
+
<div class="p-4">
|
|
2751
|
+
@if (config.message) {
|
|
2752
|
+
<p class="mb-4 leading-relaxed">{{ config.message | translate | async }}</p>
|
|
2753
|
+
}
|
|
2506
2754
|
<axp-layout-renderer
|
|
2507
2755
|
[layout]="config.definition"
|
|
2508
2756
|
[context]="context()"
|
|
@@ -2566,9 +2814,190 @@ var dialogRenderer_component = /*#__PURE__*/Object.freeze({
|
|
|
2566
2814
|
AXPDialogRendererComponent: AXPDialogRendererComponent
|
|
2567
2815
|
});
|
|
2568
2816
|
|
|
2817
|
+
//#region ---- Imports ----
|
|
2818
|
+
/**
|
|
2819
|
+
* `customWidget` only forwards keys from its options bag into the built node via `addSingleWidget`.
|
|
2820
|
+
* Designer / configurator persist `defaultValue` (and other extended fields) on the widget node root;
|
|
2821
|
+
* spreading `options` alone drops them, so preview never applied defaults.
|
|
2822
|
+
*/
|
|
2823
|
+
/**
|
|
2824
|
+
* Widget options are sometimes persisted with an extra nesting (`options.options`) when context
|
|
2825
|
+
* was merged incorrectly. Flatten so list/data-source resolution sees `dataSource` at the top level.
|
|
2826
|
+
*/
|
|
2827
|
+
function optionsBagForPreview(node) {
|
|
2828
|
+
const raw = (node.options ?? {});
|
|
2829
|
+
const inner = raw['options'];
|
|
2830
|
+
if (inner !== undefined && typeof inner === 'object' && !Array.isArray(inner)) {
|
|
2831
|
+
const { options: _nested, ...rest } = raw;
|
|
2832
|
+
return { ...rest, ...inner };
|
|
2833
|
+
}
|
|
2834
|
+
return { ...raw };
|
|
2835
|
+
}
|
|
2836
|
+
function extendedNodePropsForPreview(node) {
|
|
2837
|
+
const out = {};
|
|
2838
|
+
if (node.defaultValue !== undefined) {
|
|
2839
|
+
out['defaultValue'] = node.defaultValue;
|
|
2840
|
+
}
|
|
2841
|
+
if (node.triggers !== undefined) {
|
|
2842
|
+
out['triggers'] = node.triggers;
|
|
2843
|
+
}
|
|
2844
|
+
if (node.meta !== undefined) {
|
|
2845
|
+
out['meta'] = node.meta;
|
|
2846
|
+
}
|
|
2847
|
+
if (node.valueTransforms !== undefined) {
|
|
2848
|
+
out['valueTransforms'] = node.valueTransforms;
|
|
2849
|
+
}
|
|
2850
|
+
if (node.visible !== undefined) {
|
|
2851
|
+
out['visible'] = node.visible;
|
|
2852
|
+
}
|
|
2853
|
+
if (node.mode !== undefined) {
|
|
2854
|
+
out['mode'] = node.mode;
|
|
2855
|
+
}
|
|
2856
|
+
if (node.children !== undefined) {
|
|
2857
|
+
out['children'] = node.children;
|
|
2858
|
+
}
|
|
2859
|
+
return out;
|
|
2860
|
+
}
|
|
2861
|
+
//#endregion
|
|
2862
|
+
//#region ---- Command ----
|
|
2863
|
+
/**
|
|
2864
|
+
* Opens a dialog that previews a widget configuration (same behavior as the preview button on
|
|
2865
|
+
* `axp-widget-field-configurator`). Invoked from that component and from entity list actions.
|
|
2866
|
+
*/
|
|
2867
|
+
class AXPPreviewWidgetFieldCommand {
|
|
2868
|
+
constructor() {
|
|
2869
|
+
this.formBuilderService = inject(AXPLayoutBuilderService);
|
|
2870
|
+
this.widgetRegistry = inject(AXPWidgetRegistryService);
|
|
2871
|
+
this.translationService = inject(AXTranslationService);
|
|
2872
|
+
this.crudService = inject(AXP_ENTITY_DEFINITION_CRUD_SERVICE, { optional: true });
|
|
2873
|
+
}
|
|
2874
|
+
async execute(input) {
|
|
2875
|
+
try {
|
|
2876
|
+
const merged = this.mergeInvocation(input);
|
|
2877
|
+
const currentWidget = this.normalizeWidget(merged['widget'] ?? merged['interface']);
|
|
2878
|
+
if (!currentWidget?.type) {
|
|
2879
|
+
return {
|
|
2880
|
+
success: false,
|
|
2881
|
+
message: {
|
|
2882
|
+
text: (await this.translationService.translateAsync('@general:messages.invalid-data')) || 'Invalid data',
|
|
2883
|
+
},
|
|
2884
|
+
};
|
|
2885
|
+
}
|
|
2886
|
+
const fieldName = String(merged['fieldName'] ?? merged['name'] ?? 'Field');
|
|
2887
|
+
const rawTitle = (merged['fieldTitle'] ?? merged['title']);
|
|
2888
|
+
const fieldTitleLabel = this.resolveFieldTitleLabel(rawTitle, fieldName);
|
|
2889
|
+
const dialogTitle = (await this.resolveWidgetDisplayTitle(currentWidget.type)) || currentWidget.type || fieldTitleLabel;
|
|
2890
|
+
const previewWidgetOptions = {
|
|
2891
|
+
...optionsBagForPreview(currentWidget),
|
|
2892
|
+
name: fieldName,
|
|
2893
|
+
...extendedNodePropsForPreview(currentWidget),
|
|
2894
|
+
};
|
|
2895
|
+
const dialogOutcome = await this.formBuilderService
|
|
2896
|
+
.create()
|
|
2897
|
+
.dialog((dialog) => {
|
|
2898
|
+
dialog
|
|
2899
|
+
.setTitle(dialogTitle)
|
|
2900
|
+
.setSize('md')
|
|
2901
|
+
.setCloseButton(true)
|
|
2902
|
+
.setContext({})
|
|
2903
|
+
.content((layoutBuilder) => {
|
|
2904
|
+
layoutBuilder.formField(fieldTitleLabel, (formField) => {
|
|
2905
|
+
formField.customWidget(currentWidget.type, previewWidgetOptions);
|
|
2906
|
+
});
|
|
2907
|
+
})
|
|
2908
|
+
.setActions((actions) => actions.cancel('@general:actions.close.title'));
|
|
2909
|
+
})
|
|
2910
|
+
.show();
|
|
2911
|
+
const cancelled = this.isCancelDialogOutcome(dialogOutcome);
|
|
2912
|
+
return {
|
|
2913
|
+
success: !cancelled,
|
|
2914
|
+
message: { text: '' },
|
|
2915
|
+
};
|
|
2916
|
+
}
|
|
2917
|
+
catch (error) {
|
|
2918
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
2919
|
+
return {
|
|
2920
|
+
success: false,
|
|
2921
|
+
message: { text: message },
|
|
2922
|
+
};
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
mergeInvocation(input) {
|
|
2926
|
+
const contextOptions = input.__context__?.options;
|
|
2927
|
+
const ctxData = input.__context__?.data;
|
|
2928
|
+
const { __context__: _ctx, ...rest } = input;
|
|
2929
|
+
return {
|
|
2930
|
+
...(ctxData ?? {}),
|
|
2931
|
+
...(contextOptions ?? {}),
|
|
2932
|
+
...rest,
|
|
2933
|
+
};
|
|
2934
|
+
}
|
|
2935
|
+
normalizeWidget(raw) {
|
|
2936
|
+
if (raw == null)
|
|
2937
|
+
return null;
|
|
2938
|
+
if (typeof raw === 'string') {
|
|
2939
|
+
const t = raw.trim();
|
|
2940
|
+
return t ? { type: t, options: {} } : null;
|
|
2941
|
+
}
|
|
2942
|
+
if (typeof raw === 'object' && !Array.isArray(raw) && 'type' in raw) {
|
|
2943
|
+
const w = raw;
|
|
2944
|
+
return w.type ? cloneDeep(w) : null;
|
|
2945
|
+
}
|
|
2946
|
+
return null;
|
|
2947
|
+
}
|
|
2948
|
+
resolveFieldTitleLabel(raw, fallback) {
|
|
2949
|
+
let source = fallback;
|
|
2950
|
+
if (raw !== undefined && raw !== null) {
|
|
2951
|
+
if (typeof raw === 'string') {
|
|
2952
|
+
if (raw.trim() !== '') {
|
|
2953
|
+
source = raw;
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
else if (typeof raw === 'object' && !Array.isArray(raw) && Object.keys(raw).length > 0) {
|
|
2957
|
+
source = raw;
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
return this.translationService.resolve(source);
|
|
2961
|
+
}
|
|
2962
|
+
isCancelDialogOutcome(outcome) {
|
|
2963
|
+
if (outcome == null) {
|
|
2964
|
+
return false;
|
|
2965
|
+
}
|
|
2966
|
+
const ref = outcome;
|
|
2967
|
+
if (typeof ref.action !== 'function') {
|
|
2968
|
+
return false;
|
|
2969
|
+
}
|
|
2970
|
+
return ref.action() === 'cancel';
|
|
2971
|
+
}
|
|
2972
|
+
async resolveWidgetDisplayTitle(widgetType) {
|
|
2973
|
+
const crud = this.crudService;
|
|
2974
|
+
if (crud) {
|
|
2975
|
+
const interfaces = await crud.listInterfaces();
|
|
2976
|
+
const iface = interfaces.find((d) => d.name === widgetType);
|
|
2977
|
+
return iface?.title ?? iface?.name;
|
|
2978
|
+
}
|
|
2979
|
+
const config = this.widgetRegistry.getOptional(widgetType);
|
|
2980
|
+
if (!config) {
|
|
2981
|
+
return undefined;
|
|
2982
|
+
}
|
|
2983
|
+
const resolved = this.translationService.resolve(config.title);
|
|
2984
|
+
return resolved || undefined;
|
|
2985
|
+
}
|
|
2986
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPreviewWidgetFieldCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2987
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPreviewWidgetFieldCommand }); }
|
|
2988
|
+
}
|
|
2989
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPreviewWidgetFieldCommand, decorators: [{
|
|
2990
|
+
type: Injectable
|
|
2991
|
+
}] });
|
|
2992
|
+
|
|
2993
|
+
var previewWidgetField_command = /*#__PURE__*/Object.freeze({
|
|
2994
|
+
__proto__: null,
|
|
2995
|
+
AXPPreviewWidgetFieldCommand: AXPPreviewWidgetFieldCommand
|
|
2996
|
+
});
|
|
2997
|
+
|
|
2569
2998
|
/**
|
|
2570
2999
|
* Generated bundle index. Do not edit.
|
|
2571
3000
|
*/
|
|
2572
3001
|
|
|
2573
|
-
export { AXPDialogRendererComponent, AXPLayoutBuilderService, AXPLayoutConversionService, AXPLayoutRendererComponent, LayoutBuilderModule };
|
|
3002
|
+
export { AXPDialogRendererComponent, AXPLayoutBuilderService, AXPLayoutConversionService, AXPLayoutRendererComponent, AXPPreviewWidgetFieldCommand, AXP_LAYOUT_BUILDER_DIALOG_BEFORE_OPEN_HOOK_KEY, AXP_LAYOUT_BUILDER_DIALOG_CONFIG_HOOK_KEY, AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY, LayoutBuilderModule };
|
|
2574
3003
|
//# sourceMappingURL=acorex-platform-layout-builder.mjs.map
|