@acorex/platform 21.0.0-next.85 → 21.0.0-next.89
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 +9 -3
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/{acorex-platform-common-common-settings.provider-Ytey9uhY.mjs → acorex-platform-common-common-settings.provider-DilV4dql.mjs} +16 -3
- package/fesm2022/acorex-platform-common-common-settings.provider-DilV4dql.mjs.map +1 -0
- package/fesm2022/acorex-platform-common.mjs +3426 -2488
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-contracts.mjs +1160 -9
- package/fesm2022/acorex-platform-contracts.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +826 -152
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-domain-contracts.mjs +58 -0
- package/fesm2022/acorex-platform-domain-contracts.mjs.map +1 -0
- package/fesm2022/acorex-platform-domain.mjs +2 -50
- package/fesm2022/acorex-platform-domain.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +98 -189
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs → acorex-platform-layout-components-binding-expression-editor-popup.component-RttFwaw9.mjs} +17 -4
- package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-RttFwaw9.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-components.mjs +181 -46
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +7 -6
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity-attachments-page.component-CwG6n_Yb.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity-contracts.mjs +1208 -0
- package/fesm2022/acorex-platform-layout-entity-contracts.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-entity-file-list-popup.component--IeMZLIr.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +1080 -889
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +1150 -247
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +388 -207
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs +513 -0
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-CZc2zFlg.mjs} +4 -4
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-CZc2zFlg.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-XWRUVoL4.mjs} +2 -2
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs.map → acorex-platform-layout-widgets-tabular-data-view-popup.component-XWRUVoL4.mjs.map} +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs +1541 -394
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs → acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs} +2 -3
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +956 -115
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs → acorex-platform-themes-shared-settings.provider-UyKdkeyk.mjs} +50 -3
- package/fesm2022/acorex-platform-themes-shared-settings.provider-UyKdkeyk.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared.mjs +104 -24
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/fesm2022/acorex-platform-workflow.mjs +6 -8
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/package.json +9 -5
- package/types/acorex-platform-auth.d.ts +3 -1
- package/types/acorex-platform-common.d.ts +655 -1268
- package/types/acorex-platform-contracts.d.ts +1791 -260
- package/types/acorex-platform-core.d.ts +2302 -2800
- package/types/acorex-platform-domain-contracts.d.ts +416 -0
- package/types/acorex-platform-domain.d.ts +4 -415
- package/types/acorex-platform-layout-builder.d.ts +11 -20
- package/types/acorex-platform-layout-components.d.ts +29 -5
- package/types/acorex-platform-layout-designer.d.ts +2 -1
- package/types/acorex-platform-layout-entity-contracts.d.ts +889 -0
- package/types/acorex-platform-layout-entity.d.ts +143 -275
- package/types/acorex-platform-layout-views.d.ts +147 -31
- package/types/acorex-platform-layout-widget-core.d.ts +74 -14
- package/types/acorex-platform-layout-widgets.d.ts +136 -38
- package/types/acorex-platform-runtime.d.ts +1 -1
- package/types/acorex-platform-themes-default.d.ts +227 -73
- package/types/acorex-platform-themes-shared.d.ts +4 -0
- package/types/acorex-platform-workflow.d.ts +5 -18
- package/fesm2022/acorex-platform-common-common-settings.provider-Ytey9uhY.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs +0 -116
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs.map +0 -1
- package/fesm2022/acorex-platform-native.mjs +0 -155
- package/fesm2022/acorex-platform-native.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs.map +0 -1
- package/native/README.md +0 -4
- package/types/acorex-platform-native.d.ts +0 -28
|
@@ -0,0 +1,1208 @@
|
|
|
1
|
+
import { AXPSystemActionType } from '@acorex/platform/contracts';
|
|
2
|
+
import { omit } from 'lodash-es';
|
|
3
|
+
|
|
4
|
+
//#region ---- Entity actions ----
|
|
5
|
+
var AXPEntityCommandScope;
|
|
6
|
+
(function (AXPEntityCommandScope) {
|
|
7
|
+
AXPEntityCommandScope["TypeLevel"] = "typeLevel";
|
|
8
|
+
AXPEntityCommandScope["Selected"] = "selected";
|
|
9
|
+
AXPEntityCommandScope["Individual"] = "individual";
|
|
10
|
+
AXPEntityCommandScope["Section"] = "section";
|
|
11
|
+
})(AXPEntityCommandScope || (AXPEntityCommandScope = {}));
|
|
12
|
+
var AXPEntityQueryType;
|
|
13
|
+
(function (AXPEntityQueryType) {
|
|
14
|
+
AXPEntityQueryType["Single"] = "single";
|
|
15
|
+
AXPEntityQueryType["List"] = "list";
|
|
16
|
+
})(AXPEntityQueryType || (AXPEntityQueryType = {}));
|
|
17
|
+
//#endregion
|
|
18
|
+
|
|
19
|
+
//#region ---- Entity properties ----
|
|
20
|
+
//#endregion
|
|
21
|
+
|
|
22
|
+
//#region ---- Entity definition ----
|
|
23
|
+
var AXPRelationshipKind;
|
|
24
|
+
(function (AXPRelationshipKind) {
|
|
25
|
+
AXPRelationshipKind[AXPRelationshipKind["Association"] = 0] = "Association";
|
|
26
|
+
AXPRelationshipKind[AXPRelationshipKind["Composition"] = 1] = "Composition";
|
|
27
|
+
AXPRelationshipKind[AXPRelationshipKind["Aggregation"] = 2] = "Aggregation";
|
|
28
|
+
})(AXPRelationshipKind || (AXPRelationshipKind = {}));
|
|
29
|
+
var AXPRelationshipCardinality;
|
|
30
|
+
(function (AXPRelationshipCardinality) {
|
|
31
|
+
AXPRelationshipCardinality[AXPRelationshipCardinality["OneToOne"] = 0] = "OneToOne";
|
|
32
|
+
AXPRelationshipCardinality[AXPRelationshipCardinality["OneToMany"] = 1] = "OneToMany";
|
|
33
|
+
AXPRelationshipCardinality[AXPRelationshipCardinality["ManyToMany"] = 2] = "ManyToMany";
|
|
34
|
+
})(AXPRelationshipCardinality || (AXPRelationshipCardinality = {}));
|
|
35
|
+
function kebabCase(value) {
|
|
36
|
+
return value
|
|
37
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
38
|
+
.replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
|
|
39
|
+
.replace(/[\s_]+/g, '-')
|
|
40
|
+
.replace(/-+/g, '-')
|
|
41
|
+
.toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
function getEntityInfo(entity) {
|
|
44
|
+
return {
|
|
45
|
+
source: `${entity.module}.${entity.name}`,
|
|
46
|
+
module: {
|
|
47
|
+
route: kebabCase(entity.module),
|
|
48
|
+
},
|
|
49
|
+
entity: {
|
|
50
|
+
route: kebabCase(entity.name),
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
var AXPEntityType;
|
|
55
|
+
(function (AXPEntityType) {
|
|
56
|
+
AXPEntityType[AXPEntityType["Entity"] = 0] = "Entity";
|
|
57
|
+
AXPEntityType[AXPEntityType["AggregateRoot"] = 1] = "AggregateRoot";
|
|
58
|
+
AXPEntityType[AXPEntityType["ValueObject"] = 2] = "ValueObject";
|
|
59
|
+
})(AXPEntityType || (AXPEntityType = {}));
|
|
60
|
+
//#endregion
|
|
61
|
+
|
|
62
|
+
//#region ---- Entity model & DTO types ----
|
|
63
|
+
//#endregion
|
|
64
|
+
|
|
65
|
+
//#endregion
|
|
66
|
+
|
|
67
|
+
//#region ---- Entity formats ----
|
|
68
|
+
//#endregion
|
|
69
|
+
|
|
70
|
+
//#region ---- Entity property list options ----
|
|
71
|
+
//#endregion
|
|
72
|
+
|
|
73
|
+
//#region ---- Entity display fields ----
|
|
74
|
+
//#endregion
|
|
75
|
+
|
|
76
|
+
//#region ---- Entity card fields ----
|
|
77
|
+
/** Whether the card field is shown as a header badge (not in the card body). */
|
|
78
|
+
function isCardFieldBadgeDisplay(display) {
|
|
79
|
+
if (display === 'badge') {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
return typeof display === 'object' && display !== null && display.type === 'badge';
|
|
83
|
+
}
|
|
84
|
+
/** Resolves static badge color config from {@link AXPCardField.display} and legacy {@link AXPCardField.badgeColor}. */
|
|
85
|
+
function resolveCardFieldBadgeColor(field) {
|
|
86
|
+
if (typeof field.display === 'object' && field.display.type === 'badge') {
|
|
87
|
+
return field.display.options?.color ?? field.badgeColor;
|
|
88
|
+
}
|
|
89
|
+
if (field.display === 'badge') {
|
|
90
|
+
return field.badgeColor;
|
|
91
|
+
}
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
|
|
96
|
+
//#region ---- Entity query views ----
|
|
97
|
+
function createQueryView(name, title, fixed, params = {
|
|
98
|
+
columns: [],
|
|
99
|
+
conditions: [],
|
|
100
|
+
sorts: [],
|
|
101
|
+
}) {
|
|
102
|
+
params = Object.assign({ columns: [], sorts: [], conditions: [] }, params);
|
|
103
|
+
return {
|
|
104
|
+
name,
|
|
105
|
+
title,
|
|
106
|
+
fixed,
|
|
107
|
+
columns: params.columns ?? [],
|
|
108
|
+
conditions: params.conditions ?? [],
|
|
109
|
+
sorts: params.sorts ?? [],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function createAllQueryView(params = {
|
|
113
|
+
columns: [],
|
|
114
|
+
sorts: [],
|
|
115
|
+
conditions: [],
|
|
116
|
+
}) {
|
|
117
|
+
params = Object.assign({ columns: [], sorts: [], conditions: [] }, params);
|
|
118
|
+
return createQueryView('all', '@general:terms.interface.selection.all-items', true, {
|
|
119
|
+
columns: params.columns ?? [],
|
|
120
|
+
conditions: params.conditions ?? [],
|
|
121
|
+
sorts: params.sorts ?? [],
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
|
|
126
|
+
//#region ---- Entity master list views ----
|
|
127
|
+
/** Resolves master list layouts that are currently enabled. */
|
|
128
|
+
function resolveEnabledMasterListLayouts(layouts) {
|
|
129
|
+
if (!layouts) {
|
|
130
|
+
return ['table'];
|
|
131
|
+
}
|
|
132
|
+
const enabled = [];
|
|
133
|
+
if (layouts.table?.enabled !== false) {
|
|
134
|
+
enabled.push('table');
|
|
135
|
+
}
|
|
136
|
+
if (layouts.card && layouts.card.enabled !== false) {
|
|
137
|
+
enabled.push('card');
|
|
138
|
+
}
|
|
139
|
+
return enabled.length > 0 ? enabled : ['table'];
|
|
140
|
+
}
|
|
141
|
+
/** First enabled layout; used as the default when no user preference is stored. */
|
|
142
|
+
function resolveDefaultMasterListLayout(layouts) {
|
|
143
|
+
return resolveEnabledMasterListLayouts(layouts)[0];
|
|
144
|
+
}
|
|
145
|
+
//#endregion
|
|
146
|
+
|
|
147
|
+
//#region ---- Entity detail list views ----
|
|
148
|
+
//#endregion
|
|
149
|
+
|
|
150
|
+
//#region ---- Entity layout views ----
|
|
151
|
+
//#endregion
|
|
152
|
+
|
|
153
|
+
//#region ---- Related entity layout ----
|
|
154
|
+
//#endregion
|
|
155
|
+
|
|
156
|
+
//#region ---- Entity list filters ----
|
|
157
|
+
/** Encodes a dotted storage path as a flat filter context key (e.g. `person.lastName` → `person__lastName`). */
|
|
158
|
+
function encodeEntityListFilterContextField(queryField) {
|
|
159
|
+
return queryField.replace(/\./g, '__');
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Resolves the flat context key used by query-filters / widget binding for a filter definition.
|
|
163
|
+
*/
|
|
164
|
+
function resolveEntityListFilterContextField(filter) {
|
|
165
|
+
const explicit = filter.contextField?.trim();
|
|
166
|
+
if (explicit) {
|
|
167
|
+
return explicit;
|
|
168
|
+
}
|
|
169
|
+
const field = filter.field?.trim();
|
|
170
|
+
if (!field) {
|
|
171
|
+
return '';
|
|
172
|
+
}
|
|
173
|
+
return field.includes('.') ? encodeEntityListFilterContextField(field) : field;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Maps an entity list filter definition to the storage query field.
|
|
177
|
+
* Inline `contains` filters on lookup/select use `inlineQueryField` (display text path).
|
|
178
|
+
*/
|
|
179
|
+
function resolveEntityListFilterQueryField(filter, operator) {
|
|
180
|
+
const operatorType = operator?.type ?? filter.operator?.type;
|
|
181
|
+
if (operatorType === 'contains' && filter.inlineQueryField) {
|
|
182
|
+
return filter.inlineQueryField;
|
|
183
|
+
}
|
|
184
|
+
return filter.field;
|
|
185
|
+
}
|
|
186
|
+
//#endregion
|
|
187
|
+
|
|
188
|
+
//#region ---- Types barrel ----
|
|
189
|
+
//#endregion
|
|
190
|
+
|
|
191
|
+
//#region ---- Entity action helpers (pure data, no Angular) ----
|
|
192
|
+
//#region Master
|
|
193
|
+
function entityMasterCreateAction() {
|
|
194
|
+
return {
|
|
195
|
+
title: '@general:actions.create.title',
|
|
196
|
+
command: {
|
|
197
|
+
name: 'Entity:Create',
|
|
198
|
+
},
|
|
199
|
+
priority: 'primary',
|
|
200
|
+
type: AXPSystemActionType.Create,
|
|
201
|
+
scope: AXPEntityCommandScope.TypeLevel,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function entityMasterEditAction() {
|
|
205
|
+
return {
|
|
206
|
+
title: '@general:actions.edit.title',
|
|
207
|
+
command: 'Entity:Update',
|
|
208
|
+
priority: 'secondary',
|
|
209
|
+
type: AXPSystemActionType.Update,
|
|
210
|
+
scope: AXPEntityCommandScope.Individual,
|
|
211
|
+
default: true,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function entityMasterBulkDeleteAction() {
|
|
215
|
+
return {
|
|
216
|
+
title: '@general:actions.delete-items.title',
|
|
217
|
+
command: 'delete-entity',
|
|
218
|
+
priority: 'primary',
|
|
219
|
+
type: AXPSystemActionType.Delete,
|
|
220
|
+
scope: AXPEntityCommandScope.Selected,
|
|
221
|
+
order: 100,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function entityMasterViewAction() {
|
|
225
|
+
return {
|
|
226
|
+
title: '@general:actions.view.title',
|
|
227
|
+
command: 'open-entity',
|
|
228
|
+
priority: 'secondary',
|
|
229
|
+
type: AXPSystemActionType.View,
|
|
230
|
+
scope: AXPEntityCommandScope.Individual,
|
|
231
|
+
default: true,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function entityMasterDeleteAction() {
|
|
235
|
+
return {
|
|
236
|
+
title: '@general:actions.delete.title',
|
|
237
|
+
command: 'delete-entity',
|
|
238
|
+
priority: 'secondary',
|
|
239
|
+
type: AXPSystemActionType.Delete,
|
|
240
|
+
scope: AXPEntityCommandScope.Individual,
|
|
241
|
+
order: 100,
|
|
242
|
+
shortcuts: ['ctrl+shift+delete'],
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function entityMasterCrudActions(options) {
|
|
246
|
+
const opts = {
|
|
247
|
+
create: true,
|
|
248
|
+
delete: true,
|
|
249
|
+
view: true,
|
|
250
|
+
edit: false,
|
|
251
|
+
...options,
|
|
252
|
+
};
|
|
253
|
+
const actions = [];
|
|
254
|
+
if (opts.create) {
|
|
255
|
+
actions.push(entityMasterCreateAction());
|
|
256
|
+
}
|
|
257
|
+
if (opts.delete) {
|
|
258
|
+
actions.push(entityMasterBulkDeleteAction());
|
|
259
|
+
actions.push(entityMasterDeleteAction());
|
|
260
|
+
}
|
|
261
|
+
if (opts.view) {
|
|
262
|
+
actions.push(entityMasterViewAction());
|
|
263
|
+
}
|
|
264
|
+
if (opts.edit) {
|
|
265
|
+
actions.push(entityMasterEditAction());
|
|
266
|
+
}
|
|
267
|
+
return actions;
|
|
268
|
+
}
|
|
269
|
+
function entityMasterRecordActions() {
|
|
270
|
+
return [entityMasterDeleteAction()];
|
|
271
|
+
}
|
|
272
|
+
//#endregion
|
|
273
|
+
//#region Details
|
|
274
|
+
function entityDetailsCreateActions(parentId) {
|
|
275
|
+
return {
|
|
276
|
+
title: '@general:actions.create.title',
|
|
277
|
+
command: {
|
|
278
|
+
name: 'Entity:Create',
|
|
279
|
+
options: {
|
|
280
|
+
process: {
|
|
281
|
+
redirect: false,
|
|
282
|
+
canCreateNewOne: true,
|
|
283
|
+
data: {
|
|
284
|
+
[parentId]: '{{context.eval("id")}}',
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
priority: 'primary',
|
|
290
|
+
type: AXPSystemActionType.Create,
|
|
291
|
+
scope: AXPEntityCommandScope.TypeLevel,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function entityDetailsCreateActionsDeferredParent() {
|
|
295
|
+
return {
|
|
296
|
+
title: '@general:actions.create.title',
|
|
297
|
+
command: {
|
|
298
|
+
name: 'Entity:Create',
|
|
299
|
+
options: {
|
|
300
|
+
process: {
|
|
301
|
+
redirect: false,
|
|
302
|
+
canCreateNewOne: true,
|
|
303
|
+
data: {},
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
priority: 'primary',
|
|
308
|
+
type: AXPSystemActionType.Create,
|
|
309
|
+
scope: AXPEntityCommandScope.TypeLevel,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function mergeForeignKeyFieldIntoCreateActions(foreignKeyField, actions) {
|
|
313
|
+
if (!foreignKeyField || !actions?.length) {
|
|
314
|
+
return actions ?? [];
|
|
315
|
+
}
|
|
316
|
+
return actions.map((a) => {
|
|
317
|
+
const cmd = a.command;
|
|
318
|
+
if (typeof cmd !== 'object' ||
|
|
319
|
+
!cmd ||
|
|
320
|
+
cmd.name !== 'Entity:Create' ||
|
|
321
|
+
a.scope !== AXPEntityCommandScope.TypeLevel) {
|
|
322
|
+
return a;
|
|
323
|
+
}
|
|
324
|
+
const opts = (cmd.options ?? {});
|
|
325
|
+
const proc = (opts['process'] ?? {});
|
|
326
|
+
const data = { ...(proc['data'] ?? {}) };
|
|
327
|
+
if (data[foreignKeyField] === undefined || data[foreignKeyField] === null || data[foreignKeyField] === '') {
|
|
328
|
+
data[foreignKeyField] = '{{ context.eval("id") }}';
|
|
329
|
+
}
|
|
330
|
+
return {
|
|
331
|
+
...a,
|
|
332
|
+
command: {
|
|
333
|
+
...cmd,
|
|
334
|
+
options: { ...opts, process: { ...proc, data } },
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
function collectNestedCreateHiddenProperties(relatedEntity) {
|
|
340
|
+
const fk = relatedEntity.persistence?.foreignKeyField;
|
|
341
|
+
const merged = [...(relatedEntity.excludeProperties ?? [])];
|
|
342
|
+
if (fk) {
|
|
343
|
+
merged.push(fk);
|
|
344
|
+
}
|
|
345
|
+
const unique = [...new Set(merged)];
|
|
346
|
+
return unique.length ? unique : undefined;
|
|
347
|
+
}
|
|
348
|
+
function entityDetailsSimpleCondition(fk) {
|
|
349
|
+
return {
|
|
350
|
+
name: fk,
|
|
351
|
+
operator: { type: 'equal' },
|
|
352
|
+
value: '{{context.eval("id")}}',
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
function entityDetailsReferenceCondition(type) {
|
|
356
|
+
return [
|
|
357
|
+
{
|
|
358
|
+
name: 'reference.id',
|
|
359
|
+
operator: { type: 'equal' },
|
|
360
|
+
value: '{{context.eval("id")}}',
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
name: 'reference.type',
|
|
364
|
+
operator: { type: 'equal' },
|
|
365
|
+
value: type,
|
|
366
|
+
},
|
|
367
|
+
];
|
|
368
|
+
}
|
|
369
|
+
function entityDetailsEditAction() {
|
|
370
|
+
return {
|
|
371
|
+
title: '@general:actions.edit.title',
|
|
372
|
+
command: 'Entity:Update',
|
|
373
|
+
priority: 'secondary',
|
|
374
|
+
type: AXPSystemActionType.Update,
|
|
375
|
+
default: true,
|
|
376
|
+
scope: AXPEntityCommandScope.Individual,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
function entityDetailsNewEditAction() {
|
|
380
|
+
return {
|
|
381
|
+
title: 'New Edit',
|
|
382
|
+
command: {
|
|
383
|
+
name: 'Entity:Update',
|
|
384
|
+
},
|
|
385
|
+
priority: 'secondary',
|
|
386
|
+
type: AXPSystemActionType.Update,
|
|
387
|
+
default: true,
|
|
388
|
+
scope: AXPEntityCommandScope.Individual,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
function entityOverrideDetailsViewAction() {
|
|
392
|
+
return {
|
|
393
|
+
title: '@general:actions.view.title',
|
|
394
|
+
command: 'open-entity',
|
|
395
|
+
priority: 'secondary',
|
|
396
|
+
hidden: true,
|
|
397
|
+
type: AXPSystemActionType.View,
|
|
398
|
+
scope: AXPEntityCommandScope.Individual,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
function entityDetailsCrudActions(parentId, options) {
|
|
402
|
+
const opts = {
|
|
403
|
+
create: true,
|
|
404
|
+
delete: true,
|
|
405
|
+
view: true,
|
|
406
|
+
edit: true,
|
|
407
|
+
...options,
|
|
408
|
+
};
|
|
409
|
+
const actions = [];
|
|
410
|
+
if (opts.create) {
|
|
411
|
+
if (parentId) {
|
|
412
|
+
actions.push(entityDetailsCreateActions(parentId));
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
actions.push(entityDetailsCreateActionsDeferredParent());
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (opts.edit) {
|
|
419
|
+
actions.push(entityDetailsEditAction());
|
|
420
|
+
}
|
|
421
|
+
if (opts.view) {
|
|
422
|
+
actions.push(entityOverrideDetailsViewAction());
|
|
423
|
+
}
|
|
424
|
+
return actions;
|
|
425
|
+
}
|
|
426
|
+
function entityDetailsReferenceCreateActions(type) {
|
|
427
|
+
return [
|
|
428
|
+
{
|
|
429
|
+
title: '@general:actions.create.title',
|
|
430
|
+
command: {
|
|
431
|
+
name: 'Entity:Create',
|
|
432
|
+
options: {
|
|
433
|
+
process: {
|
|
434
|
+
redirect: false,
|
|
435
|
+
canCreateNewOne: true,
|
|
436
|
+
data: {
|
|
437
|
+
reference: {
|
|
438
|
+
id: '{{context.eval("id")}}',
|
|
439
|
+
type: type,
|
|
440
|
+
},
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
priority: 'primary',
|
|
446
|
+
type: AXPSystemActionType.Create,
|
|
447
|
+
scope: AXPEntityCommandScope.TypeLevel,
|
|
448
|
+
},
|
|
449
|
+
entityDetailsEditAction(),
|
|
450
|
+
entityOverrideDetailsViewAction(),
|
|
451
|
+
];
|
|
452
|
+
}
|
|
453
|
+
//#endregion
|
|
454
|
+
|
|
455
|
+
//#region ---- Helpers barrel ----
|
|
456
|
+
//#endregion
|
|
457
|
+
|
|
458
|
+
//#region ---- Template normalization ----
|
|
459
|
+
/**
|
|
460
|
+
* Normalizes display templates before expression evaluation.
|
|
461
|
+
* Converts simple dot paths (e.g. `{{ position.title }}`) to `context.eval("position.title")`.
|
|
462
|
+
*/
|
|
463
|
+
function normalizeExpressionTemplate(template) {
|
|
464
|
+
let normalized = template.replace(/\{\{\s*context\.eval\(['"]([^'"]+)['"]\)\s*\}\}/g, '{{ context.eval("$1") }}');
|
|
465
|
+
if (!normalized.includes('{{')) {
|
|
466
|
+
normalized = normalized.replace(/\{/g, '{{').replace(/\}/g, '}}');
|
|
467
|
+
}
|
|
468
|
+
return normalized.replace(/\{\{\s*(?!context\.)([\w]+(?:\.[\w]+)*)\s*\}\}/g, '{{ context.eval("$1") }}');
|
|
469
|
+
}
|
|
470
|
+
/** @see normalizeExpressionTemplate */
|
|
471
|
+
const normalizeEntityDisplayTemplate = normalizeExpressionTemplate;
|
|
472
|
+
/** True when formatted text still contains unresolved template markers. */
|
|
473
|
+
function isUnresolvedEntityDisplayTemplate(value) {
|
|
474
|
+
return /\{\{/.test(value) || /context\.eval\s*\(/.test(value) || value === '[object Object]';
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Strips literal `undefined` / `null` tokens produced when expression segments are missing.
|
|
478
|
+
*/
|
|
479
|
+
function sanitizeResolvedEntityDisplayTitle(value) {
|
|
480
|
+
const trimmed = value.trim();
|
|
481
|
+
if (!trimmed) {
|
|
482
|
+
return '';
|
|
483
|
+
}
|
|
484
|
+
const withoutLiterals = trimmed
|
|
485
|
+
.replace(/\bundefined\b/gi, ' ')
|
|
486
|
+
.replace(/\bnull\b/gi, ' ')
|
|
487
|
+
.replace(/\s+/g, ' ')
|
|
488
|
+
.trim();
|
|
489
|
+
return withoutLiterals
|
|
490
|
+
.replace(/^[\s\-–—·|/,()+]+|[\s\-–—·|/,()+]+$/g, '')
|
|
491
|
+
.trim();
|
|
492
|
+
}
|
|
493
|
+
/** True when a resolved title is non-empty and safe to show in search or entity chrome. */
|
|
494
|
+
function isMeaningfulEntityDisplayTitle(value) {
|
|
495
|
+
const sanitized = sanitizeResolvedEntityDisplayTitle(value);
|
|
496
|
+
return sanitized.length > 0 && !isUnresolvedEntityDisplayTemplate(sanitized);
|
|
497
|
+
}
|
|
498
|
+
function isRowBoundEntityDisplayTemplate(template) {
|
|
499
|
+
const trimmed = template.trim();
|
|
500
|
+
if (!trimmed || trimmed.startsWith('@')) {
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
return trimmed.includes('{{') || trimmed.includes('{');
|
|
504
|
+
}
|
|
505
|
+
//#endregion
|
|
506
|
+
|
|
507
|
+
//#endregion
|
|
508
|
+
//#region ---- Expose parsing ----
|
|
509
|
+
/**
|
|
510
|
+
* Parses lookup/select `expose` entries from a property interface options object.
|
|
511
|
+
*/
|
|
512
|
+
function parsePropertyExposeEntries(options) {
|
|
513
|
+
const expose = options?.['expose'];
|
|
514
|
+
if (!Array.isArray(expose)) {
|
|
515
|
+
return [];
|
|
516
|
+
}
|
|
517
|
+
return expose.filter((row) => row != null &&
|
|
518
|
+
typeof row === 'object' &&
|
|
519
|
+
typeof row.source === 'string' &&
|
|
520
|
+
typeof row.target === 'string');
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Collects all non-empty `expose[].target` paths from a property.
|
|
524
|
+
*/
|
|
525
|
+
function collectPropertyExposeTargetPaths(property) {
|
|
526
|
+
const opts = property.schema?.interface?.options;
|
|
527
|
+
if (!opts || typeof opts !== 'object') {
|
|
528
|
+
return [];
|
|
529
|
+
}
|
|
530
|
+
const paths = new Set();
|
|
531
|
+
for (const entry of parsePropertyExposeEntries(opts)) {
|
|
532
|
+
const target = entry.target.trim();
|
|
533
|
+
if (target) {
|
|
534
|
+
paths.add(target);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return [...paths];
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Resolves list column `options.dataPath` for a property when explicitly set.
|
|
541
|
+
*/
|
|
542
|
+
function resolveEntityColumnDataPath(entity, propertyName) {
|
|
543
|
+
const column = entity?.columns?.find((c) => c.name === propertyName);
|
|
544
|
+
const rawDataPath = column?.options?.['dataPath'];
|
|
545
|
+
if (typeof rawDataPath !== 'string') {
|
|
546
|
+
return undefined;
|
|
547
|
+
}
|
|
548
|
+
const dataPath = rawDataPath.trim();
|
|
549
|
+
if (!dataPath || dataPath === propertyName) {
|
|
550
|
+
return undefined;
|
|
551
|
+
}
|
|
552
|
+
return dataPath;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Resolves the lodash-get path for lookup/select display text from expose metadata.
|
|
556
|
+
*/
|
|
557
|
+
function resolvePropertyExposeDisplayTarget(options) {
|
|
558
|
+
if (!options) {
|
|
559
|
+
return undefined;
|
|
560
|
+
}
|
|
561
|
+
const textField = typeof options['textField'] === 'string' ? options['textField'].trim() : '';
|
|
562
|
+
const valueField = typeof options['valueField'] === 'string' ? options['valueField'].trim() : 'id';
|
|
563
|
+
const entries = parsePropertyExposeEntries(options);
|
|
564
|
+
if (textField) {
|
|
565
|
+
const match = entries.find((entry) => entry.source === textField);
|
|
566
|
+
if (match?.target.trim()) {
|
|
567
|
+
return match.target.trim();
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
const displayEntry = entries.find((entry) => entry.source !== valueField && entry.source !== 'id' && entry.target.trim());
|
|
571
|
+
return displayEntry?.target.trim();
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Resolves the lodash-get path used for inline `contains` filters on lookup/select properties.
|
|
575
|
+
* Prefers list column `dataPath`, then lookup `expose` target for `textField` (or first non-id expose).
|
|
576
|
+
* Returns `undefined` when the property name should be used as-is (e.g. plain text fields).
|
|
577
|
+
*/
|
|
578
|
+
function resolveEntityPropertyInlineFilterField(entity, property) {
|
|
579
|
+
if (!entity || !property?.name) {
|
|
580
|
+
return undefined;
|
|
581
|
+
}
|
|
582
|
+
const dataPath = resolveEntityColumnDataPath(entity, property.name);
|
|
583
|
+
if (dataPath) {
|
|
584
|
+
return dataPath;
|
|
585
|
+
}
|
|
586
|
+
const opts = property.schema?.interface?.options;
|
|
587
|
+
if (!opts || typeof opts !== 'object') {
|
|
588
|
+
return undefined;
|
|
589
|
+
}
|
|
590
|
+
return resolvePropertyExposeDisplayTarget(opts);
|
|
591
|
+
}
|
|
592
|
+
//#endregion
|
|
593
|
+
|
|
594
|
+
//#endregion
|
|
595
|
+
//#region ---- Entity metadata ----
|
|
596
|
+
const DEFAULT_DISPLAY_FIELD_CANDIDATES = [
|
|
597
|
+
'title',
|
|
598
|
+
'name',
|
|
599
|
+
'code',
|
|
600
|
+
'fullName',
|
|
601
|
+
'displayName',
|
|
602
|
+
'subject',
|
|
603
|
+
'description',
|
|
604
|
+
];
|
|
605
|
+
function entityHasProperty(entity, path) {
|
|
606
|
+
const root = path.split('.')[0];
|
|
607
|
+
return entity.properties?.some((property) => property.name === root) ?? false;
|
|
608
|
+
}
|
|
609
|
+
function resolveEntityDisplayPropertyPaths(entity) {
|
|
610
|
+
const paths = [];
|
|
611
|
+
const add = (path) => {
|
|
612
|
+
const trimmed = path?.trim();
|
|
613
|
+
if (!trimmed || trimmed.includes('{') || paths.includes(trimmed)) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
if (entityHasProperty(entity, trimmed)) {
|
|
617
|
+
paths.push(trimmed);
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
const lookupFormat = entity.formats?.lookup?.trim();
|
|
621
|
+
if (lookupFormat && !lookupFormat.includes('{')) {
|
|
622
|
+
add(lookupFormat);
|
|
623
|
+
}
|
|
624
|
+
for (const candidate of DEFAULT_DISPLAY_FIELD_CANDIDATES) {
|
|
625
|
+
add(candidate);
|
|
626
|
+
}
|
|
627
|
+
const identifierPlugin = entity.plugins?.find((plugin) => plugin.name === 'identifier');
|
|
628
|
+
const identifierField = identifierPlugin?.options?.['field'];
|
|
629
|
+
if (typeof identifierField === 'string') {
|
|
630
|
+
add(identifierField);
|
|
631
|
+
}
|
|
632
|
+
if (paths.length === 0) {
|
|
633
|
+
const firstStringProperty = entity.properties?.find((property) => property.schema?.dataType === 'string' && property.name !== 'id');
|
|
634
|
+
add(firstStringProperty?.name);
|
|
635
|
+
}
|
|
636
|
+
return paths;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Builds entity-scoped fallback metadata for global search (registered on each entity search definition).
|
|
640
|
+
*/
|
|
641
|
+
function buildEntitySearchTitleContext(entity, primaryTemplate) {
|
|
642
|
+
const fallbackTemplates = [];
|
|
643
|
+
const normalizedPrimary = primaryTemplate?.trim()
|
|
644
|
+
? normalizeEntityDisplayTemplate(primaryTemplate.trim())
|
|
645
|
+
: undefined;
|
|
646
|
+
const addTemplate = (raw) => {
|
|
647
|
+
const trimmed = raw?.trim();
|
|
648
|
+
if (!trimmed || !isRowBoundEntityDisplayTemplate(trimmed)) {
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
const normalized = normalizeEntityDisplayTemplate(trimmed);
|
|
652
|
+
if (!normalized || normalized === normalizedPrimary || fallbackTemplates.includes(normalized)) {
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
fallbackTemplates.push(normalized);
|
|
656
|
+
};
|
|
657
|
+
addTemplate(entity.interfaces?.master?.single?.title);
|
|
658
|
+
addTemplate(entity.formats?.lookup);
|
|
659
|
+
addTemplate(entity.formats?.individual);
|
|
660
|
+
return {
|
|
661
|
+
fallbackTemplates,
|
|
662
|
+
fallbackFields: resolveEntityDisplayPropertyPaths(entity),
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Row title template chain aligned with entity layouts.
|
|
667
|
+
* Priority: `interfaces.master.single.title` → `formats.searchResult.title` → `formats.individual`.
|
|
668
|
+
*/
|
|
669
|
+
function resolveEntityRowTitleTemplate(entity) {
|
|
670
|
+
if (!entity) {
|
|
671
|
+
return undefined;
|
|
672
|
+
}
|
|
673
|
+
const singleTitle = entity.interfaces?.master?.single?.title?.trim();
|
|
674
|
+
if (singleTitle && isRowBoundEntityDisplayTemplate(singleTitle)) {
|
|
675
|
+
return normalizeEntityDisplayTemplate(singleTitle);
|
|
676
|
+
}
|
|
677
|
+
const searchTitle = entity.formats?.searchResult?.title?.trim();
|
|
678
|
+
if (searchTitle && isRowBoundEntityDisplayTemplate(searchTitle)) {
|
|
679
|
+
return normalizeEntityDisplayTemplate(searchTitle);
|
|
680
|
+
}
|
|
681
|
+
const lookupFormat = entity.formats?.lookup?.trim();
|
|
682
|
+
if (lookupFormat && isRowBoundEntityDisplayTemplate(lookupFormat)) {
|
|
683
|
+
return normalizeEntityDisplayTemplate(lookupFormat);
|
|
684
|
+
}
|
|
685
|
+
const individual = entity.formats?.individual?.trim();
|
|
686
|
+
if (individual && isRowBoundEntityDisplayTemplate(individual)) {
|
|
687
|
+
return normalizeEntityDisplayTemplate(individual);
|
|
688
|
+
}
|
|
689
|
+
return undefined;
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* Record title template for modify popups: `interfaces.master.update.title` → `single.title`.
|
|
693
|
+
*/
|
|
694
|
+
function resolveEntityModifyRecordTitleTemplate(entity) {
|
|
695
|
+
if (!entity) {
|
|
696
|
+
return undefined;
|
|
697
|
+
}
|
|
698
|
+
const updateTitle = entity.interfaces?.master?.update?.title?.trim();
|
|
699
|
+
if (updateTitle && isRowBoundEntityDisplayTemplate(updateTitle)) {
|
|
700
|
+
return normalizeEntityDisplayTemplate(updateTitle);
|
|
701
|
+
}
|
|
702
|
+
const singleTitle = entity.interfaces?.master?.single?.title?.trim();
|
|
703
|
+
if (singleTitle && isRowBoundEntityDisplayTemplate(singleTitle)) {
|
|
704
|
+
return normalizeEntityDisplayTemplate(singleTitle);
|
|
705
|
+
}
|
|
706
|
+
return undefined;
|
|
707
|
+
}
|
|
708
|
+
//#endregion
|
|
709
|
+
|
|
710
|
+
//#endregion
|
|
711
|
+
//#region ---- Quick search: schema-driven field paths ----
|
|
712
|
+
const NON_TEXT_DATATYPES = new Set([
|
|
713
|
+
'number',
|
|
714
|
+
'integer',
|
|
715
|
+
'int',
|
|
716
|
+
'long',
|
|
717
|
+
'float',
|
|
718
|
+
'double',
|
|
719
|
+
'decimal',
|
|
720
|
+
'money',
|
|
721
|
+
'currency',
|
|
722
|
+
'boolean',
|
|
723
|
+
'bool',
|
|
724
|
+
'date',
|
|
725
|
+
'datetime',
|
|
726
|
+
'time',
|
|
727
|
+
'object',
|
|
728
|
+
'array',
|
|
729
|
+
'json',
|
|
730
|
+
'image',
|
|
731
|
+
'file',
|
|
732
|
+
'binary',
|
|
733
|
+
]);
|
|
734
|
+
/**
|
|
735
|
+
* Whether an entity property likely stores free text worth a `contains` quick-search clause.
|
|
736
|
+
*/
|
|
737
|
+
function isTextLikeDataType(dataType) {
|
|
738
|
+
const dt = (dataType ?? 'string').toLowerCase().trim();
|
|
739
|
+
if (!dt || NON_TEXT_DATATYPES.has(dt)) {
|
|
740
|
+
return false;
|
|
741
|
+
}
|
|
742
|
+
return true;
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Lodash-get paths for quick search from a single entity definition: string-like property names
|
|
746
|
+
* plus lookup `expose[].target` paths (e.g. `brand.title`).
|
|
747
|
+
*/
|
|
748
|
+
function collectQuickSearchPathsFromSingleEntityDefinition(entity) {
|
|
749
|
+
if (!entity?.properties?.length) {
|
|
750
|
+
return [];
|
|
751
|
+
}
|
|
752
|
+
const paths = new Set();
|
|
753
|
+
for (const property of entity.properties) {
|
|
754
|
+
if (isTextLikeDataType(property.schema?.dataType)) {
|
|
755
|
+
paths.add(property.name);
|
|
756
|
+
}
|
|
757
|
+
for (const target of collectPropertyExposeTargetPaths(property)) {
|
|
758
|
+
paths.add(target);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
return [...paths];
|
|
762
|
+
}
|
|
763
|
+
//#endregion
|
|
764
|
+
//#region ---- Column-derived nested paths ----
|
|
765
|
+
/**
|
|
766
|
+
* Adds dotted paths from master columns (`name` or `options.dataPath`), e.g. `person.fullName`, `jobDefinition.title`.
|
|
767
|
+
*/
|
|
768
|
+
function collectNestedFieldPathsFromEntityColumns(entity) {
|
|
769
|
+
if (!entity?.columns?.length) {
|
|
770
|
+
return [];
|
|
771
|
+
}
|
|
772
|
+
const paths = new Set();
|
|
773
|
+
for (const col of entity.columns) {
|
|
774
|
+
const name = col.name.trim();
|
|
775
|
+
if (name.includes('.')) {
|
|
776
|
+
paths.add(name);
|
|
777
|
+
}
|
|
778
|
+
const rawDp = col.options?.['dataPath'];
|
|
779
|
+
if (typeof rawDp === 'string') {
|
|
780
|
+
const dp = rawDp.trim();
|
|
781
|
+
if (dp.includes('.')) {
|
|
782
|
+
paths.add(dp);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
return [...paths];
|
|
787
|
+
}
|
|
788
|
+
//#endregion
|
|
789
|
+
//#region ---- Related merge-detail paths ----
|
|
790
|
+
function parseRelatedEntityFullName$1(fullName) {
|
|
791
|
+
const t = fullName.trim();
|
|
792
|
+
const idx = t.indexOf('.');
|
|
793
|
+
if (idx <= 0 || idx >= t.length - 1) {
|
|
794
|
+
return null;
|
|
795
|
+
}
|
|
796
|
+
return {
|
|
797
|
+
moduleName: t.slice(0, idx),
|
|
798
|
+
entityName: t.slice(idx + 1),
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
//#endregion
|
|
802
|
+
//#region ---- Public API ----
|
|
803
|
+
/**
|
|
804
|
+
* Collects lodash-get field paths used for mock/API quick search (`contains` / OR filters):
|
|
805
|
+
* host properties and lookup expose targets, dotted column paths, and merge-detail related entities
|
|
806
|
+
* prefixed with the related entity merge `persistence.dataPath` (e.g. `person.firstName`).
|
|
807
|
+
*/
|
|
808
|
+
async function collectEntityQuickSearchFieldPaths(entity, resolveRelatedDefinition) {
|
|
809
|
+
if (!entity) {
|
|
810
|
+
return [];
|
|
811
|
+
}
|
|
812
|
+
const paths = new Set();
|
|
813
|
+
for (const p of collectQuickSearchPathsFromSingleEntityDefinition(entity)) {
|
|
814
|
+
paths.add(p);
|
|
815
|
+
}
|
|
816
|
+
for (const p of collectNestedFieldPathsFromEntityColumns(entity)) {
|
|
817
|
+
paths.add(p);
|
|
818
|
+
}
|
|
819
|
+
const related = entity.relatedEntities ?? [];
|
|
820
|
+
for (const rel of related) {
|
|
821
|
+
const dataPath = rel.persistence?.dataPath?.trim();
|
|
822
|
+
if (!dataPath || rel.layout?.type !== 'merge-detail') {
|
|
823
|
+
continue;
|
|
824
|
+
}
|
|
825
|
+
const parsed = rel.entity ? parseRelatedEntityFullName$1(rel.entity) : null;
|
|
826
|
+
if (!parsed) {
|
|
827
|
+
continue;
|
|
828
|
+
}
|
|
829
|
+
const relatedDef = await resolveRelatedDefinition(parsed.moduleName, parsed.entityName);
|
|
830
|
+
if (!relatedDef) {
|
|
831
|
+
continue;
|
|
832
|
+
}
|
|
833
|
+
for (const p of collectQuickSearchPathsFromSingleEntityDefinition(relatedDef)) {
|
|
834
|
+
paths.add(`${dataPath}.${p}`);
|
|
835
|
+
}
|
|
836
|
+
for (const p of collectNestedFieldPathsFromEntityColumns(relatedDef)) {
|
|
837
|
+
paths.add(`${dataPath}.${p}`);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
return [...paths];
|
|
841
|
+
}
|
|
842
|
+
//#endregion
|
|
843
|
+
|
|
844
|
+
//#region ---- Related entity helpers ----
|
|
845
|
+
function parseRelatedEntityFullName(fullName) {
|
|
846
|
+
const trimmed = fullName.trim();
|
|
847
|
+
const idx = trimmed.indexOf('.');
|
|
848
|
+
if (idx <= 0 || idx >= trimmed.length - 1) {
|
|
849
|
+
return null;
|
|
850
|
+
}
|
|
851
|
+
return {
|
|
852
|
+
moduleName: trimmed.slice(0, idx),
|
|
853
|
+
entityName: trimmed.slice(idx + 1),
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
function parseDottedFieldPath(fieldPath) {
|
|
857
|
+
const trimmed = fieldPath.trim();
|
|
858
|
+
const dotIndex = trimmed.indexOf('.');
|
|
859
|
+
if (dotIndex <= 0 || dotIndex >= trimmed.length - 1) {
|
|
860
|
+
return null;
|
|
861
|
+
}
|
|
862
|
+
return {
|
|
863
|
+
dataPath: trimmed.slice(0, dotIndex),
|
|
864
|
+
propertyName: trimmed.slice(dotIndex + 1),
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
//#endregion
|
|
868
|
+
//#region ---- Merge-detail property discovery ----
|
|
869
|
+
/**
|
|
870
|
+
* Resolves related property names eligible for host list columns/filters/sorts:
|
|
871
|
+
* host columns under `dataPath`, optional `related.properties` allowlist, minus `excludeProperties`.
|
|
872
|
+
*/
|
|
873
|
+
function collectMergeDetailListPropertyNames(hostEntity, dataPath, relatedEntity) {
|
|
874
|
+
const names = new Set();
|
|
875
|
+
const prefix = `${dataPath}.`;
|
|
876
|
+
if (relatedEntity.properties?.length) {
|
|
877
|
+
for (const name of relatedEntity.properties) {
|
|
878
|
+
const trimmed = name.trim();
|
|
879
|
+
if (trimmed) {
|
|
880
|
+
names.add(trimmed);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
for (const column of hostEntity.columns ?? []) {
|
|
885
|
+
const columnName = column.name.trim();
|
|
886
|
+
if (columnName.startsWith(prefix)) {
|
|
887
|
+
const tail = columnName.slice(prefix.length);
|
|
888
|
+
const leaf = tail.split('.')[0]?.trim();
|
|
889
|
+
if (leaf) {
|
|
890
|
+
names.add(leaf);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
const rawDataPath = column.options?.['dataPath'];
|
|
894
|
+
if (typeof rawDataPath === 'string') {
|
|
895
|
+
const dp = rawDataPath.trim();
|
|
896
|
+
if (dp.startsWith(prefix)) {
|
|
897
|
+
const tail = dp.slice(prefix.length);
|
|
898
|
+
const leaf = tail.split('.')[0]?.trim();
|
|
899
|
+
if (leaf) {
|
|
900
|
+
names.add(leaf);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
const excluded = new Set((relatedEntity.excludeProperties ?? []).map((n) => n.trim()).filter(Boolean));
|
|
906
|
+
for (const name of excluded) {
|
|
907
|
+
names.delete(name);
|
|
908
|
+
}
|
|
909
|
+
return names;
|
|
910
|
+
}
|
|
911
|
+
//#endregion
|
|
912
|
+
|
|
913
|
+
//#endregion
|
|
914
|
+
//#region ---- Property filter helpers ----
|
|
915
|
+
function isPropertyFilterEnabled(property) {
|
|
916
|
+
const filter = property.options?.filter;
|
|
917
|
+
return !!(filter?.advance?.enabled ||
|
|
918
|
+
filter?.inline?.enabled ||
|
|
919
|
+
filter?.preload?.enabled);
|
|
920
|
+
}
|
|
921
|
+
//#endregion
|
|
922
|
+
//#region ---- Merge-detail property discovery ----
|
|
923
|
+
function resolveMergedRelatedInlineFilterField(dataPath, relatedEntityDef, property) {
|
|
924
|
+
const columnDataPath = resolveEntityColumnDataPath(relatedEntityDef, property.name);
|
|
925
|
+
if (columnDataPath) {
|
|
926
|
+
return `${dataPath}.${columnDataPath}`;
|
|
927
|
+
}
|
|
928
|
+
const exposeTarget = resolvePropertyExposeDisplayTarget(property.schema?.interface?.options);
|
|
929
|
+
if (exposeTarget) {
|
|
930
|
+
return `${dataPath}.${exposeTarget}`;
|
|
931
|
+
}
|
|
932
|
+
return undefined;
|
|
933
|
+
}
|
|
934
|
+
//#endregion
|
|
935
|
+
//#region ---- Filter definition builder ----
|
|
936
|
+
function buildFilterDefinitionFromProperty(hostEntity, property, options, deps) {
|
|
937
|
+
if (!isPropertyFilterEnabled(property)) {
|
|
938
|
+
return null;
|
|
939
|
+
}
|
|
940
|
+
const iface = property.schema.interface ?? {};
|
|
941
|
+
const interfaceType = iface.type;
|
|
942
|
+
const widgetConfig = interfaceType ? deps?.resolveWidget?.(interfaceType) : undefined;
|
|
943
|
+
const type = (property.options?.filter?.advance?.widgetType ||
|
|
944
|
+
widgetConfig?.defaultFilterWidgetName ||
|
|
945
|
+
interfaceType);
|
|
946
|
+
const inlineQueryField = options.inlineQueryField ??
|
|
947
|
+
resolveEntityPropertyInlineFilterField(hostEntity, property);
|
|
948
|
+
const preloadRequired = property.options?.filter?.preload?.required;
|
|
949
|
+
const validations = preloadRequired
|
|
950
|
+
? [
|
|
951
|
+
{
|
|
952
|
+
rule: 'required',
|
|
953
|
+
message: 'This field is required',
|
|
954
|
+
options: {},
|
|
955
|
+
},
|
|
956
|
+
]
|
|
957
|
+
: [];
|
|
958
|
+
const widgetOptions = {
|
|
959
|
+
...(iface.options ?? {}),
|
|
960
|
+
...(validations.length ? { validations } : {}),
|
|
961
|
+
};
|
|
962
|
+
const contextField = options.field.includes('.')
|
|
963
|
+
? encodeEntityListFilterContextField(options.field)
|
|
964
|
+
: undefined;
|
|
965
|
+
return {
|
|
966
|
+
title: property.title,
|
|
967
|
+
field: options.field,
|
|
968
|
+
...(contextField ? { contextField } : {}),
|
|
969
|
+
...(inlineQueryField && inlineQueryField !== options.field ? { inlineQueryField } : {}),
|
|
970
|
+
operator: {
|
|
971
|
+
type: 'contains',
|
|
972
|
+
},
|
|
973
|
+
widget: {
|
|
974
|
+
...omit(iface, 'triggers'),
|
|
975
|
+
path: contextField ?? options.field,
|
|
976
|
+
type,
|
|
977
|
+
options: widgetOptions,
|
|
978
|
+
},
|
|
979
|
+
filters: [],
|
|
980
|
+
isParametric: false,
|
|
981
|
+
icon: widgetConfig?.icon,
|
|
982
|
+
filterType: {
|
|
983
|
+
advance: property.options?.filter?.advance?.enabled ?? false,
|
|
984
|
+
inline: property.options?.filter?.inline?.enabled ?? false,
|
|
985
|
+
preload: property.options?.filter?.preload,
|
|
986
|
+
},
|
|
987
|
+
triggers: iface.triggers,
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
async function collectHostPropertyFilterDefinitions(entity, deps) {
|
|
991
|
+
const definitions = [];
|
|
992
|
+
for (const property of entity.properties ?? []) {
|
|
993
|
+
const definition = buildFilterDefinitionFromProperty(entity, property, { field: property.name }, deps);
|
|
994
|
+
if (definition) {
|
|
995
|
+
definitions.push(definition);
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
return definitions;
|
|
999
|
+
}
|
|
1000
|
+
async function collectMergeDetailFilterDefinitions(hostEntity, resolveRelatedDefinition, deps) {
|
|
1001
|
+
const definitions = [];
|
|
1002
|
+
for (const related of hostEntity.relatedEntities ?? []) {
|
|
1003
|
+
if (related.layout?.type !== 'merge-detail') {
|
|
1004
|
+
continue;
|
|
1005
|
+
}
|
|
1006
|
+
if (related.filter?.enabled === false) {
|
|
1007
|
+
continue;
|
|
1008
|
+
}
|
|
1009
|
+
const dataPath = related.persistence?.dataPath?.trim();
|
|
1010
|
+
if (!dataPath) {
|
|
1011
|
+
continue;
|
|
1012
|
+
}
|
|
1013
|
+
const parsed = related.entity ? parseRelatedEntityFullName(related.entity) : null;
|
|
1014
|
+
if (!parsed) {
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
const relatedDef = await resolveRelatedDefinition(parsed.moduleName, parsed.entityName);
|
|
1018
|
+
if (!relatedDef) {
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
const propertyNames = collectMergeDetailListPropertyNames(hostEntity, dataPath, related);
|
|
1022
|
+
if (propertyNames.size === 0) {
|
|
1023
|
+
continue;
|
|
1024
|
+
}
|
|
1025
|
+
for (const propertyName of propertyNames) {
|
|
1026
|
+
const property = relatedDef.properties?.find((p) => p.name === propertyName);
|
|
1027
|
+
if (!property) {
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
const queryField = `${dataPath}.${propertyName}`;
|
|
1031
|
+
const inlineQueryField = resolveMergedRelatedInlineFilterField(dataPath, relatedDef, property);
|
|
1032
|
+
const definition = buildFilterDefinitionFromProperty(hostEntity, property, {
|
|
1033
|
+
field: queryField,
|
|
1034
|
+
inlineQueryField,
|
|
1035
|
+
}, deps);
|
|
1036
|
+
if (definition) {
|
|
1037
|
+
definitions.push(definition);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
return definitions;
|
|
1042
|
+
}
|
|
1043
|
+
//#endregion
|
|
1044
|
+
//#region ---- Public API ----
|
|
1045
|
+
/**
|
|
1046
|
+
* Builds master-list filter definitions from host properties and merge-detail related entities.
|
|
1047
|
+
* Related filters use `{dataPath}.{property}` query fields (e.g. `person.firstName`).
|
|
1048
|
+
*/
|
|
1049
|
+
async function collectEntityListFilterDefinitions(entity, resolveRelatedDefinition, deps) {
|
|
1050
|
+
if (!entity) {
|
|
1051
|
+
return [];
|
|
1052
|
+
}
|
|
1053
|
+
const hostDefinitions = await collectHostPropertyFilterDefinitions(entity, deps);
|
|
1054
|
+
const relatedDefinitions = await collectMergeDetailFilterDefinitions(entity, resolveRelatedDefinition, deps);
|
|
1055
|
+
return [...hostDefinitions, ...relatedDefinitions];
|
|
1056
|
+
}
|
|
1057
|
+
//#endregion
|
|
1058
|
+
|
|
1059
|
+
//#endregion
|
|
1060
|
+
//#region ---- Property sort helpers ----
|
|
1061
|
+
function isPropertySortEnabled(property) {
|
|
1062
|
+
return !!property.options?.sort?.enabled;
|
|
1063
|
+
}
|
|
1064
|
+
function resolveHostColumnTitle(hostEntity, fieldName) {
|
|
1065
|
+
const column = hostEntity.columns?.find((c) => c.name === fieldName);
|
|
1066
|
+
return column?.title;
|
|
1067
|
+
}
|
|
1068
|
+
function collectHostSortableFields(entity) {
|
|
1069
|
+
return (entity.properties ?? [])
|
|
1070
|
+
.filter(isPropertySortEnabled)
|
|
1071
|
+
.map((property) => ({
|
|
1072
|
+
name: property.name,
|
|
1073
|
+
title: resolveHostColumnTitle(entity, property.name) ?? property.title,
|
|
1074
|
+
}));
|
|
1075
|
+
}
|
|
1076
|
+
async function collectMergeDetailSortableFields(hostEntity, resolveRelatedDefinition) {
|
|
1077
|
+
const fields = [];
|
|
1078
|
+
for (const related of hostEntity.relatedEntities ?? []) {
|
|
1079
|
+
if (related.layout?.type !== 'merge-detail') {
|
|
1080
|
+
continue;
|
|
1081
|
+
}
|
|
1082
|
+
const dataPath = related.persistence?.dataPath?.trim();
|
|
1083
|
+
if (!dataPath) {
|
|
1084
|
+
continue;
|
|
1085
|
+
}
|
|
1086
|
+
const parsed = related.entity ? parseRelatedEntityFullName(related.entity) : null;
|
|
1087
|
+
if (!parsed) {
|
|
1088
|
+
continue;
|
|
1089
|
+
}
|
|
1090
|
+
const relatedDef = await resolveRelatedDefinition(parsed.moduleName, parsed.entityName);
|
|
1091
|
+
if (!relatedDef) {
|
|
1092
|
+
continue;
|
|
1093
|
+
}
|
|
1094
|
+
const propertyNames = collectMergeDetailListPropertyNames(hostEntity, dataPath, related);
|
|
1095
|
+
for (const propertyName of propertyNames) {
|
|
1096
|
+
const property = relatedDef.properties?.find((p) => p.name === propertyName);
|
|
1097
|
+
if (!property || !isPropertySortEnabled(property)) {
|
|
1098
|
+
continue;
|
|
1099
|
+
}
|
|
1100
|
+
const queryField = `${dataPath}.${propertyName}`;
|
|
1101
|
+
fields.push({
|
|
1102
|
+
name: queryField,
|
|
1103
|
+
title: resolveHostColumnTitle(hostEntity, queryField) ?? property.title,
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
return fields;
|
|
1108
|
+
}
|
|
1109
|
+
//#endregion
|
|
1110
|
+
//#region ---- Public API ----
|
|
1111
|
+
/**
|
|
1112
|
+
* Builds master-list sortable fields from host properties and merge-detail related entities.
|
|
1113
|
+
* Related sorts use `{dataPath}.{property}` query fields (e.g. `person.firstName`).
|
|
1114
|
+
*/
|
|
1115
|
+
async function collectEntityListSortableFields(entity, resolveRelatedDefinition) {
|
|
1116
|
+
if (!entity) {
|
|
1117
|
+
return [];
|
|
1118
|
+
}
|
|
1119
|
+
const hostFields = collectHostSortableFields(entity);
|
|
1120
|
+
const relatedFields = await collectMergeDetailSortableFields(entity, resolveRelatedDefinition);
|
|
1121
|
+
const seen = new Set();
|
|
1122
|
+
const result = [];
|
|
1123
|
+
for (const field of [...hostFields, ...relatedFields]) {
|
|
1124
|
+
if (seen.has(field.name)) {
|
|
1125
|
+
continue;
|
|
1126
|
+
}
|
|
1127
|
+
seen.add(field.name);
|
|
1128
|
+
result.push(field);
|
|
1129
|
+
}
|
|
1130
|
+
return result;
|
|
1131
|
+
}
|
|
1132
|
+
function isEntityPropertySortEnabled(property) {
|
|
1133
|
+
return property != null && isPropertySortEnabled(property);
|
|
1134
|
+
}
|
|
1135
|
+
//#endregion
|
|
1136
|
+
|
|
1137
|
+
//#region ---- Workflow record helpers ----
|
|
1138
|
+
/** Entity query filter field for {@link AXPRecordWorkflowInfo.instanceId}. */
|
|
1139
|
+
const AXP_RECORD_WORKFLOW_INFO_INSTANCE_ID_FIELD = 'workflowInfo.instanceId';
|
|
1140
|
+
/** Entity query filter field for {@link AXPRecordWorkflowInfo.correlationId}. */
|
|
1141
|
+
const AXP_RECORD_WORKFLOW_INFO_CORRELATION_ID_FIELD = 'workflowInfo.correlationId';
|
|
1142
|
+
/** Entity query filter field for {@link AXPRecordWorkflowInfo.definitionId}. */
|
|
1143
|
+
const AXP_RECORD_WORKFLOW_INFO_DEFINITION_ID_FIELD = 'workflowInfo.definitionId';
|
|
1144
|
+
/** Returns a trimmed workflow instance id from a record, if present. */
|
|
1145
|
+
function getRecordWorkflowInstanceId(record) {
|
|
1146
|
+
const id = record?.workflowInfo?.instanceId?.trim();
|
|
1147
|
+
return id && id.length > 0 ? id : null;
|
|
1148
|
+
}
|
|
1149
|
+
/** Returns a trimmed workflow correlation id from a record, if present. */
|
|
1150
|
+
function getRecordWorkflowCorrelationId(record) {
|
|
1151
|
+
const id = record?.workflowInfo?.correlationId?.trim();
|
|
1152
|
+
return id && id.length > 0 ? id : null;
|
|
1153
|
+
}
|
|
1154
|
+
/** Builds canonical workflow metadata for a domain record (engine / middleware). */
|
|
1155
|
+
function buildAXPRecordWorkflowInfo(params) {
|
|
1156
|
+
const instanceId = params.instanceId?.trim();
|
|
1157
|
+
if (!instanceId) {
|
|
1158
|
+
return {};
|
|
1159
|
+
}
|
|
1160
|
+
const definitionId = params.definitionId?.trim();
|
|
1161
|
+
const correlationId = params.correlationId?.trim();
|
|
1162
|
+
return {
|
|
1163
|
+
instanceId,
|
|
1164
|
+
...(definitionId ? { definitionId } : { definitionId: null }),
|
|
1165
|
+
...(correlationId ? { correlationId } : { correlationId: null }),
|
|
1166
|
+
...(params.pinnedVersion != null ? { pinnedVersion: params.pinnedVersion } : {}),
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
//#endregion
|
|
1170
|
+
|
|
1171
|
+
//#region ---- Utils barrel ----
|
|
1172
|
+
//#endregion
|
|
1173
|
+
|
|
1174
|
+
//#region ---- Entity display constants ----
|
|
1175
|
+
/** Row path used when context carries a nested entity layout title. */
|
|
1176
|
+
const ENTITY_LAYOUT_SINGLE_TITLE_PATH = 'entity.layout.single.title';
|
|
1177
|
+
/** Widget option for a pre-evaluated or template entity row title (entity list column mappers). */
|
|
1178
|
+
const ENTITY_ROW_POPUP_TITLE_OPTION = 'popupTitle';
|
|
1179
|
+
/** Widget option alias for entity row title templates in view/edit forms. */
|
|
1180
|
+
const ENTITY_ROW_TITLE_TEMPLATE_OPTION = 'titleTemplate';
|
|
1181
|
+
//#endregion
|
|
1182
|
+
|
|
1183
|
+
//#region ---- Entity datasource keys ----
|
|
1184
|
+
/** Platform entity layout datasource registry names. */
|
|
1185
|
+
const AXPEntityDataSourceKeys = {
|
|
1186
|
+
Entities: 'entities',
|
|
1187
|
+
};
|
|
1188
|
+
//#endregion
|
|
1189
|
+
|
|
1190
|
+
//#region ---- Entity events ----
|
|
1191
|
+
const AXPEntityEventsKeys = {
|
|
1192
|
+
REFRESH_LAYOUT: 'entity:refresh-layout',
|
|
1193
|
+
REFRESH_DATA: 'entity:refresh-data',
|
|
1194
|
+
};
|
|
1195
|
+
//#endregion
|
|
1196
|
+
|
|
1197
|
+
//#region ---- Constants barrel ----
|
|
1198
|
+
//#endregion
|
|
1199
|
+
|
|
1200
|
+
//#region ---- Barrel ----
|
|
1201
|
+
//#endregion
|
|
1202
|
+
|
|
1203
|
+
/**
|
|
1204
|
+
* Generated bundle index. Do not edit.
|
|
1205
|
+
*/
|
|
1206
|
+
|
|
1207
|
+
export { AXPEntityCommandScope, AXPEntityDataSourceKeys, AXPEntityEventsKeys, AXPEntityQueryType, AXPEntityType, AXPRelationshipCardinality, AXPRelationshipKind, AXP_RECORD_WORKFLOW_INFO_CORRELATION_ID_FIELD, AXP_RECORD_WORKFLOW_INFO_DEFINITION_ID_FIELD, AXP_RECORD_WORKFLOW_INFO_INSTANCE_ID_FIELD, ENTITY_LAYOUT_SINGLE_TITLE_PATH, ENTITY_ROW_POPUP_TITLE_OPTION, ENTITY_ROW_TITLE_TEMPLATE_OPTION, buildAXPRecordWorkflowInfo, buildEntitySearchTitleContext, collectEntityListFilterDefinitions, collectEntityListSortableFields, collectEntityQuickSearchFieldPaths, collectMergeDetailListPropertyNames, collectNestedCreateHiddenProperties, collectNestedFieldPathsFromEntityColumns, collectPropertyExposeTargetPaths, collectQuickSearchPathsFromSingleEntityDefinition, createAllQueryView, createQueryView, encodeEntityListFilterContextField, entityDetailsCreateActions, entityDetailsCreateActionsDeferredParent, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsNewEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterEditAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, getEntityInfo, getRecordWorkflowCorrelationId, getRecordWorkflowInstanceId, isCardFieldBadgeDisplay, isEntityPropertySortEnabled, isMeaningfulEntityDisplayTitle, isRowBoundEntityDisplayTemplate, isUnresolvedEntityDisplayTemplate, mergeForeignKeyFieldIntoCreateActions, normalizeEntityDisplayTemplate, normalizeExpressionTemplate, parseDottedFieldPath, parsePropertyExposeEntries, parseRelatedEntityFullName, resolveCardFieldBadgeColor, resolveDefaultMasterListLayout, resolveEnabledMasterListLayouts, resolveEntityColumnDataPath, resolveEntityListFilterContextField, resolveEntityListFilterQueryField, resolveEntityModifyRecordTitleTemplate, resolveEntityPropertyInlineFilterField, resolveEntityRowTitleTemplate, resolvePropertyExposeDisplayTarget, sanitizeResolvedEntityDisplayTitle };
|
|
1208
|
+
//# sourceMappingURL=acorex-platform-layout-entity-contracts.mjs.map
|