@acorex/platform 21.0.0-beta.1 → 21.0.0-beta.10
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 +4 -0
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/{acorex-platform-common-common-settings.provider-G9XcXXOG.mjs → acorex-platform-common-common-settings.provider-Bi1RYif5.mjs} +58 -22
- package/fesm2022/acorex-platform-common-common-settings.provider-Bi1RYif5.mjs.map +1 -0
- package/fesm2022/acorex-platform-common.mjs +275 -130
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +106 -5
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +104 -13
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +224 -6
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +37 -2
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +1107 -72
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +7 -5
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +72 -6
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs +181 -158
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-runtime.mjs +65 -2
- package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-default.mjs +121 -15
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-shared-settings.provider-D13QB3Hr.mjs → acorex-platform-themes-shared-settings.provider-DK6R87Lf.mjs} +23 -24
- package/fesm2022/acorex-platform-themes-shared-settings.provider-DK6R87Lf.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared.mjs +2 -2
- package/fesm2022/acorex-platform-workflow.mjs +85 -4
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/package.json +7 -9
- package/types/acorex-platform-common.d.ts +105 -52
- package/types/acorex-platform-core.d.ts +26 -3
- package/types/acorex-platform-layout-builder.d.ts +26 -3
- package/types/acorex-platform-layout-components.d.ts +52 -1
- package/types/acorex-platform-layout-entity.d.ts +262 -8
- package/types/acorex-platform-layout-widget-core.d.ts +15 -0
- package/types/acorex-platform-layout-widgets.d.ts +33 -23
- package/types/acorex-platform-runtime.d.ts +6 -0
- package/types/acorex-platform-themes-default.d.ts +8 -0
- package/types/acorex-platform-workflow.d.ts +68 -2
- package/fesm2022/acorex-platform-common-common-settings.provider-G9XcXXOG.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-settings.provider-D13QB3Hr.mjs.map +0 -1
|
@@ -357,65 +357,78 @@ class AXPEntityMiddleware {
|
|
|
357
357
|
this.providedModifiers = inject(AXP_ENTITY_MODIFIER, { optional: true }) || [];
|
|
358
358
|
this.providedActionPlugins = inject(AXP_ENTITY_ACTION_PLUGIN, { optional: true }) || [];
|
|
359
359
|
this.injector = inject(Injector);
|
|
360
|
-
for (const { entityName, modifier } of this.providedModifiers) {
|
|
361
|
-
this.register(entityName, modifier);
|
|
360
|
+
for (const { entityName, modifier, order } of this.providedModifiers) {
|
|
361
|
+
this.register(entityName, modifier, order);
|
|
362
362
|
}
|
|
363
363
|
}
|
|
364
364
|
//#endregion
|
|
365
365
|
//#region ---- Registration Methods ----
|
|
366
|
-
register(entityName, modifier) {
|
|
366
|
+
register(entityName, modifier, order) {
|
|
367
|
+
const resolvedOrder = order ?? 0;
|
|
367
368
|
if (entityName instanceof RegExp) {
|
|
368
|
-
this.patternModifiers.push({ pattern: this.normalizeRegExp(entityName), modifier });
|
|
369
|
+
this.patternModifiers.push({ pattern: this.normalizeRegExp(entityName), modifier, order: resolvedOrder });
|
|
369
370
|
return;
|
|
370
371
|
}
|
|
371
372
|
if (entityName.includes('*')) {
|
|
372
373
|
const pattern = this.wildcardToRegExp(entityName);
|
|
373
|
-
this.patternModifiers.push({ pattern, modifier });
|
|
374
|
+
this.patternModifiers.push({ pattern, modifier, order: resolvedOrder });
|
|
374
375
|
return;
|
|
375
376
|
}
|
|
376
|
-
this.exactModifiers.set(entityName, modifier);
|
|
377
|
+
this.exactModifiers.set(entityName, { modifier, order: resolvedOrder });
|
|
377
378
|
}
|
|
378
379
|
//#endregion
|
|
379
380
|
//#region ---- Processing ----
|
|
380
381
|
async process(entity) {
|
|
381
|
-
// First, expand action plugins if entity.plugins exists
|
|
382
382
|
const context = createModifierContext(entity);
|
|
383
|
-
const
|
|
384
|
-
if (plugins && plugins.length) {
|
|
385
|
-
const sorted = [...this.providedActionPlugins].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
386
|
-
for (const p of plugins) {
|
|
387
|
-
const contrib = sorted.find((x) => x.name === p.name);
|
|
388
|
-
if (contrib) {
|
|
389
|
-
try {
|
|
390
|
-
await runInInjectionContext(this.injector, () => contrib.apply(context, p.options));
|
|
391
|
-
}
|
|
392
|
-
catch (err) {
|
|
393
|
-
console.error('[AXPEntityMiddleware] action plugin failed:', p.name, err);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
// Then apply entity-specific modifiers
|
|
399
|
-
// Collect all matching modifiers
|
|
400
|
-
const modifiers = [];
|
|
401
|
-
// Exact match first
|
|
383
|
+
const steps = [];
|
|
402
384
|
const exact = this.exactModifiers.get(entity.name);
|
|
403
385
|
if (exact) {
|
|
404
|
-
|
|
386
|
+
steps.push(this.createModifierStep(exact, context));
|
|
405
387
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
modifiers.push(modifier);
|
|
388
|
+
for (const entry of this.patternModifiers) {
|
|
389
|
+
if (entry.pattern.test(entity.name)) {
|
|
390
|
+
steps.push(this.createModifierStep(entry, context));
|
|
410
391
|
}
|
|
411
392
|
}
|
|
412
|
-
|
|
413
|
-
for (const
|
|
414
|
-
|
|
393
|
+
const entityPlugins = entity.plugins ?? [];
|
|
394
|
+
for (const pluginRef of entityPlugins) {
|
|
395
|
+
const contrib = this.providedActionPlugins.find((x) => x.name === pluginRef.name);
|
|
396
|
+
if (contrib) {
|
|
397
|
+
steps.push(this.createPluginStep(contrib, pluginRef.name, context));
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
const sorted = steps.sort((a, b) => a.order - b.order);
|
|
401
|
+
for (const step of sorted) {
|
|
402
|
+
try {
|
|
403
|
+
await runInInjectionContext(this.injector, step.run);
|
|
404
|
+
}
|
|
405
|
+
catch (err) {
|
|
406
|
+
console.error('[AXPEntityMiddleware] entity processing step failed:', err);
|
|
407
|
+
}
|
|
415
408
|
}
|
|
416
409
|
return context.toEntity();
|
|
417
410
|
}
|
|
418
411
|
//#endregion
|
|
412
|
+
//#region ---- Step Factories ----
|
|
413
|
+
createModifierStep(entry, context) {
|
|
414
|
+
return {
|
|
415
|
+
order: entry.order,
|
|
416
|
+
run: () => entry.modifier(context),
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
createPluginStep(contrib, pluginName, context) {
|
|
420
|
+
return {
|
|
421
|
+
order: contrib.order ?? 0,
|
|
422
|
+
run: async () => {
|
|
423
|
+
const pluginRef = context.plugins.find(pluginName).get();
|
|
424
|
+
if (!pluginRef) {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
await contrib.apply(context, pluginRef.options);
|
|
428
|
+
},
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
//#endregion
|
|
419
432
|
//#region ---- Helpers ----
|
|
420
433
|
wildcardToRegExp(pattern) {
|
|
421
434
|
const escaped = pattern.replace(/[.+?^${}()|\[\]\\]/g, '\\$&');
|
|
@@ -3215,6 +3228,24 @@ class AXPEntityDataProviderImpl {
|
|
|
3215
3228
|
insertOne(entity) {
|
|
3216
3229
|
return this.storageService.insertOne(this.entityName, entity);
|
|
3217
3230
|
}
|
|
3231
|
+
count(request) {
|
|
3232
|
+
return this.storageService.count(this.entityName, request);
|
|
3233
|
+
}
|
|
3234
|
+
queryAll(request, options) {
|
|
3235
|
+
return this.storageService.queryAll(this.entityName, request, options);
|
|
3236
|
+
}
|
|
3237
|
+
getMany(ids) {
|
|
3238
|
+
return this.storageService.getMany(this.entityName, ids);
|
|
3239
|
+
}
|
|
3240
|
+
exists(id) {
|
|
3241
|
+
return this.storageService.exists(this.entityName, id);
|
|
3242
|
+
}
|
|
3243
|
+
upsertOne(entity, options) {
|
|
3244
|
+
return this.storageService.upsertOne(this.entityName, entity, options);
|
|
3245
|
+
}
|
|
3246
|
+
aggregate(request, options) {
|
|
3247
|
+
return this.storageService.aggregate(this.entityName, request, options);
|
|
3248
|
+
}
|
|
3218
3249
|
}
|
|
3219
3250
|
class AXMEntityCrudService {
|
|
3220
3251
|
}
|
|
@@ -3316,6 +3347,24 @@ class AXMEntityCrudServiceImpl {
|
|
|
3316
3347
|
get storageService() {
|
|
3317
3348
|
return this._storageService;
|
|
3318
3349
|
}
|
|
3350
|
+
async count(request) {
|
|
3351
|
+
return this._entityDataProvider.count(request);
|
|
3352
|
+
}
|
|
3353
|
+
async queryAll(request, options) {
|
|
3354
|
+
return this._entityDataProvider.queryAll(request, options);
|
|
3355
|
+
}
|
|
3356
|
+
async getMany(ids) {
|
|
3357
|
+
return this._entityDataProvider.getMany(ids);
|
|
3358
|
+
}
|
|
3359
|
+
async exists(id) {
|
|
3360
|
+
return this._entityDataProvider.exists(id);
|
|
3361
|
+
}
|
|
3362
|
+
async upsertOne(entity, options) {
|
|
3363
|
+
return this._entityDataProvider.upsertOne(entity, options);
|
|
3364
|
+
}
|
|
3365
|
+
async aggregate(request, options) {
|
|
3366
|
+
return this._entityDataProvider.aggregate(request, options);
|
|
3367
|
+
}
|
|
3319
3368
|
async custom(request) { }
|
|
3320
3369
|
}
|
|
3321
3370
|
|
|
@@ -3943,6 +3992,11 @@ class AXPEntityDetailListViewModel {
|
|
|
3943
3992
|
this.filterOperatorMiddleware = this.injector.get(AXPFilterOperatorMiddlewareService);
|
|
3944
3993
|
this.expressionEvaluator = this.injector.get(AXPExpressionEvaluatorService);
|
|
3945
3994
|
this.queryExecutor = this.injector.get(AXPQueryExecutor);
|
|
3995
|
+
this.settingsService = this.injector.get(AXPSettingsService);
|
|
3996
|
+
this.destroyed = new Subject();
|
|
3997
|
+
this.showRowIndexColumnEnabled = signal(false, ...(ngDevMode ? [{ debugName: "showRowIndexColumnEnabled" }] : /* istanbul ignore next */ []));
|
|
3998
|
+
/** Whether the row index column is shown (user setting). */
|
|
3999
|
+
this.showIndexColumn = computed(() => this.showRowIndexColumnEnabled(), ...(ngDevMode ? [{ debugName: "showIndexColumn" }] : /* istanbul ignore next */ []));
|
|
3946
4000
|
this.dataSource = new AXDataSource({
|
|
3947
4001
|
byKey: async (key) => {
|
|
3948
4002
|
const execute = this.detailEntity()?.queries?.byKey?.execute;
|
|
@@ -4082,8 +4136,28 @@ class AXPEntityDetailListViewModel {
|
|
|
4082
4136
|
};
|
|
4083
4137
|
return await this.expressionEvaluator.evaluate(actionData, scope);
|
|
4084
4138
|
};
|
|
4139
|
+
void this.syncShowRowIndexColumnSetting();
|
|
4140
|
+
this.settingsService.onLoaded.pipe(takeUntil(this.destroyed)).subscribe(() => {
|
|
4141
|
+
void this.syncShowRowIndexColumnSetting();
|
|
4142
|
+
});
|
|
4143
|
+
this.settingsService.onChanged.pipe(takeUntil(this.destroyed)).subscribe(() => {
|
|
4144
|
+
void this.syncShowRowIndexColumnSetting();
|
|
4145
|
+
});
|
|
4085
4146
|
this.initialize();
|
|
4086
4147
|
}
|
|
4148
|
+
async syncShowRowIndexColumnSetting() {
|
|
4149
|
+
try {
|
|
4150
|
+
const value = await this.settingsService.get(AXPCommonSettings.ShowRowIndexColumn);
|
|
4151
|
+
this.showRowIndexColumnEnabled.set(value ?? false);
|
|
4152
|
+
}
|
|
4153
|
+
catch {
|
|
4154
|
+
this.showRowIndexColumnEnabled.set(false);
|
|
4155
|
+
}
|
|
4156
|
+
}
|
|
4157
|
+
destroy() {
|
|
4158
|
+
this.destroyed.next();
|
|
4159
|
+
this.destroyed.complete();
|
|
4160
|
+
}
|
|
4087
4161
|
async initialize() {
|
|
4088
4162
|
const entityResolver = this.injector.get(AXPEntityDefinitionRegistryService);
|
|
4089
4163
|
const [moduleName, entityName] = this.detailEntityConfig.entity.split('.');
|
|
@@ -4223,6 +4297,118 @@ const AXPEntityEventsKeys = {
|
|
|
4223
4297
|
REFRESH_DATA: 'entity:refresh-data',
|
|
4224
4298
|
};
|
|
4225
4299
|
|
|
4300
|
+
/**
|
|
4301
|
+
* Resolves a stable row id from entity list row data.
|
|
4302
|
+
*/
|
|
4303
|
+
function getEntityListRowId(data, key = 'id') {
|
|
4304
|
+
const value = data[key];
|
|
4305
|
+
if (value != null && value !== '') {
|
|
4306
|
+
return String(value);
|
|
4307
|
+
}
|
|
4308
|
+
return '';
|
|
4309
|
+
}
|
|
4310
|
+
/**
|
|
4311
|
+
* Finds row data in a hierarchical grid tree (root rows and nested children).
|
|
4312
|
+
*/
|
|
4313
|
+
function findEntityListRowDataInTree(items, id, key) {
|
|
4314
|
+
for (const item of items) {
|
|
4315
|
+
if (item && typeof item === 'object' && String(item[key]) === id) {
|
|
4316
|
+
return item;
|
|
4317
|
+
}
|
|
4318
|
+
const rec = item;
|
|
4319
|
+
const metaChildren = rec?.['__meta__']?.['children'];
|
|
4320
|
+
const directChildren = rec?.['children'];
|
|
4321
|
+
const childArr = Array.isArray(metaChildren)
|
|
4322
|
+
? metaChildren
|
|
4323
|
+
: Array.isArray(directChildren)
|
|
4324
|
+
? directChildren
|
|
4325
|
+
: null;
|
|
4326
|
+
if (childArr?.length) {
|
|
4327
|
+
const found = findEntityListRowDataInTree(childArr, id, key);
|
|
4328
|
+
if (found) {
|
|
4329
|
+
return found;
|
|
4330
|
+
}
|
|
4331
|
+
}
|
|
4332
|
+
}
|
|
4333
|
+
return null;
|
|
4334
|
+
}
|
|
4335
|
+
/**
|
|
4336
|
+
* Restores expanded rows after data load (parents before children).
|
|
4337
|
+
*/
|
|
4338
|
+
async function restoreEntityListExpandedRows(options) {
|
|
4339
|
+
const pending = [...new Set(options.expandedRowIds.filter(Boolean))];
|
|
4340
|
+
if (!pending.length) {
|
|
4341
|
+
return;
|
|
4342
|
+
}
|
|
4343
|
+
let safety = 0;
|
|
4344
|
+
const maxPasses = Math.max(pending.length * 3, 10);
|
|
4345
|
+
while (pending.length > 0 && safety++ < maxPasses) {
|
|
4346
|
+
const rows = options.getDisplayedRows();
|
|
4347
|
+
let progressed = false;
|
|
4348
|
+
for (let i = pending.length - 1; i >= 0; i--) {
|
|
4349
|
+
const id = pending[i];
|
|
4350
|
+
const item = findEntityListRowDataInTree(rows, id, options.rowKey);
|
|
4351
|
+
if (!item) {
|
|
4352
|
+
continue;
|
|
4353
|
+
}
|
|
4354
|
+
const meta = item['__meta__'];
|
|
4355
|
+
if (meta?.['expanded'] !== true) {
|
|
4356
|
+
await options.expandRow({ data: item });
|
|
4357
|
+
}
|
|
4358
|
+
pending.splice(i, 1);
|
|
4359
|
+
progressed = true;
|
|
4360
|
+
}
|
|
4361
|
+
if (!progressed) {
|
|
4362
|
+
break;
|
|
4363
|
+
}
|
|
4364
|
+
}
|
|
4365
|
+
}
|
|
4366
|
+
|
|
4367
|
+
/**
|
|
4368
|
+
* Applies take/skip to the data source without triggering {@link AXDataSource.load}.
|
|
4369
|
+
*/
|
|
4370
|
+
function applyDataSourcePagingWithoutLoad(dataSource, paging) {
|
|
4371
|
+
const take = Math.max(1, paging.take);
|
|
4372
|
+
const skip = Math.max(0, paging.skip);
|
|
4373
|
+
const page = Math.floor(skip / take);
|
|
4374
|
+
const ds = dataSource;
|
|
4375
|
+
dataSource.config.pageSize = take;
|
|
4376
|
+
if (ds._query) {
|
|
4377
|
+
ds._query.take = take;
|
|
4378
|
+
ds._query.skip = skip;
|
|
4379
|
+
}
|
|
4380
|
+
ds._page = page;
|
|
4381
|
+
}
|
|
4382
|
+
function getDataSourcePageIndex(dataSource) {
|
|
4383
|
+
const ds = dataSource;
|
|
4384
|
+
return ds._page ?? 0;
|
|
4385
|
+
}
|
|
4386
|
+
function normalizeListPaging(paging, defaultTake) {
|
|
4387
|
+
const take = typeof paging?.take === 'number' && paging.take > 0 ? paging.take : defaultTake;
|
|
4388
|
+
const skip = typeof paging?.skip === 'number' && paging.skip >= 0 ? paging.skip : 0;
|
|
4389
|
+
return { take, skip };
|
|
4390
|
+
}
|
|
4391
|
+
|
|
4392
|
+
const AXPEntityListPersistenceModeDefault = 'persistent';
|
|
4393
|
+
function normalizeEntityListPersistenceMode(value) {
|
|
4394
|
+
if (value === 'none' || value === 'persistent' || value === 'route') {
|
|
4395
|
+
return value;
|
|
4396
|
+
}
|
|
4397
|
+
return AXPEntityListPersistenceModeDefault;
|
|
4398
|
+
}
|
|
4399
|
+
function canPersistEntityListState(mode) {
|
|
4400
|
+
return mode !== 'none';
|
|
4401
|
+
}
|
|
4402
|
+
/** `none` never reads list state from user settings. */
|
|
4403
|
+
function shouldLoadEntityListStateFromStorage(mode) {
|
|
4404
|
+
return mode !== 'none';
|
|
4405
|
+
}
|
|
4406
|
+
/** `route` clears stored list state when the route entity (module + name) changes. */
|
|
4407
|
+
function shouldResetEntityListStateOnRouteEntry(mode) {
|
|
4408
|
+
return mode === 'route';
|
|
4409
|
+
}
|
|
4410
|
+
const ENTITY_LIST_ROUTE_CONTEXT_SESSION_KEY = 'axp-entity-list-route-context';
|
|
4411
|
+
|
|
4226
4412
|
/**
|
|
4227
4413
|
* Entity Event Dispatcher - A wrapper for entity-specific events
|
|
4228
4414
|
* Handles pattern-based dispatching for entity operations with wildcard support
|
|
@@ -4556,14 +4742,17 @@ class AXPEntityMasterListViewModel {
|
|
|
4556
4742
|
return `${resolvedCommand}${suffix}`;
|
|
4557
4743
|
}
|
|
4558
4744
|
async setView(viewName = null) {
|
|
4559
|
-
|
|
4560
|
-
|
|
4745
|
+
let selectedViewName;
|
|
4746
|
+
if (await this.shouldLoadPersistedListState()) {
|
|
4747
|
+
const entitySetting = await this.settings.get(this.settingEntityKey);
|
|
4748
|
+
selectedViewName = entitySetting?.list?.currentView;
|
|
4749
|
+
}
|
|
4561
4750
|
if (viewName != this.view().name) {
|
|
4562
4751
|
this.view.set(this.views().find((c) => c.name == (viewName || selectedViewName)) ?? this.views()[0]);
|
|
4563
4752
|
this.applyViewSorts();
|
|
4564
4753
|
this.applyViewColumns();
|
|
4565
4754
|
this.applyViewFilters();
|
|
4566
|
-
|
|
4755
|
+
this.resolvedListPaging.set(null);
|
|
4567
4756
|
await this.applySettings();
|
|
4568
4757
|
}
|
|
4569
4758
|
}
|
|
@@ -4587,6 +4776,15 @@ class AXPEntityMasterListViewModel {
|
|
|
4587
4776
|
this.lastAppliedSortKey = null;
|
|
4588
4777
|
this.lastAppliedFilterKey = null;
|
|
4589
4778
|
this.hasQueryParamsFilters = false; // Flag to prevent overriding queryParams filters
|
|
4779
|
+
/** Persisted expanded row ids for hierarchical lists (per view). */
|
|
4780
|
+
this.expandedRowIds = signal([], ...(ngDevMode ? [{ debugName: "expandedRowIds" }] : /* istanbul ignore next */ []));
|
|
4781
|
+
/** When true, row expand/collapse is not written to user settings (restore in progress). */
|
|
4782
|
+
this.skipExpandedRowPersistence = false;
|
|
4783
|
+
/** Resolved take/skip for the current view (null until loaded from settings). */
|
|
4784
|
+
this.resolvedListPaging = signal(null, ...(ngDevMode ? [{ debugName: "resolvedListPaging" }] : /* istanbul ignore next */ []));
|
|
4785
|
+
/** When true, pager changes are not persisted (programmatic UI sync). */
|
|
4786
|
+
this.skipListPagingPersistence = false;
|
|
4787
|
+
this.listPersistenceMode = null;
|
|
4590
4788
|
this.events$ = new Subject();
|
|
4591
4789
|
//****************** Views ******************//
|
|
4592
4790
|
this.views = computed(() => {
|
|
@@ -4596,6 +4794,18 @@ class AXPEntityMasterListViewModel {
|
|
|
4596
4794
|
});
|
|
4597
4795
|
}, ...(ngDevMode ? [{ debugName: "views" }] : /* istanbul ignore next */ []));
|
|
4598
4796
|
this.view = signal(this.views()[0], ...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
|
|
4797
|
+
this.showRowIndexColumnEnabled = signal(false, ...(ngDevMode ? [{ debugName: "showRowIndexColumnEnabled" }] : /* istanbul ignore next */ []));
|
|
4798
|
+
/**
|
|
4799
|
+
* Row index column: if the list view defines `indexCol` (true/false), that overrides the user setting;
|
|
4800
|
+
* if `indexCol` is omitted, visibility follows {@link AXPCommonSettings.ShowRowIndexColumn}.
|
|
4801
|
+
*/
|
|
4802
|
+
this.showIndexColumn = computed(() => {
|
|
4803
|
+
const indexCol = this.view().indexCol;
|
|
4804
|
+
if (indexCol !== undefined) {
|
|
4805
|
+
return indexCol;
|
|
4806
|
+
}
|
|
4807
|
+
return this.showRowIndexColumnEnabled();
|
|
4808
|
+
}, ...(ngDevMode ? [{ debugName: "showIndexColumn" }] : /* istanbul ignore next */ []));
|
|
4599
4809
|
this.dataSource = new AXDataSource({
|
|
4600
4810
|
byKey: async (key) => {
|
|
4601
4811
|
const execute = this.entityDef.queries?.byKey?.execute;
|
|
@@ -4766,13 +4976,88 @@ class AXPEntityMasterListViewModel {
|
|
|
4766
4976
|
}
|
|
4767
4977
|
});
|
|
4768
4978
|
this.sortedFields.set(this.sortableFields());
|
|
4979
|
+
void this.syncShowRowIndexColumnSetting();
|
|
4980
|
+
this.settings.onLoaded.pipe(takeUntil(this.destroyed)).subscribe(() => {
|
|
4981
|
+
void this.syncShowRowIndexColumnSetting();
|
|
4982
|
+
});
|
|
4983
|
+
this.settings.onChanged.pipe(takeUntil(this.destroyed)).subscribe(() => {
|
|
4984
|
+
void this.syncShowRowIndexColumnSetting();
|
|
4985
|
+
});
|
|
4986
|
+
}
|
|
4987
|
+
async syncShowRowIndexColumnSetting() {
|
|
4988
|
+
try {
|
|
4989
|
+
const value = await this.settings.get(AXPCommonSettings.ShowRowIndexColumn);
|
|
4990
|
+
this.showRowIndexColumnEnabled.set(value ?? false);
|
|
4991
|
+
}
|
|
4992
|
+
catch {
|
|
4993
|
+
console.log('catch');
|
|
4994
|
+
this.showRowIndexColumnEnabled.set(false);
|
|
4995
|
+
}
|
|
4996
|
+
}
|
|
4997
|
+
/**
|
|
4998
|
+
* Applies {@link AXPCommonSettings.EntityListPersistenceMode} for this list instance.
|
|
4999
|
+
* Call once when the list view model is created (before loading list UI state).
|
|
5000
|
+
*/
|
|
5001
|
+
async initializeListPersistence() {
|
|
5002
|
+
const mode = await this.getListPersistenceMode();
|
|
5003
|
+
debugger;
|
|
5004
|
+
if (!shouldResetEntityListStateOnRouteEntry(mode)) {
|
|
5005
|
+
return;
|
|
5006
|
+
}
|
|
5007
|
+
const routeKey = this.settingEntityKey;
|
|
5008
|
+
let previousRouteKey = null;
|
|
5009
|
+
try {
|
|
5010
|
+
previousRouteKey = sessionStorage.getItem(ENTITY_LIST_ROUTE_CONTEXT_SESSION_KEY);
|
|
5011
|
+
}
|
|
5012
|
+
catch {
|
|
5013
|
+
previousRouteKey = null;
|
|
5014
|
+
}
|
|
5015
|
+
if (previousRouteKey !== routeKey) {
|
|
5016
|
+
await this.clearEntityListSettings();
|
|
5017
|
+
try {
|
|
5018
|
+
sessionStorage.setItem(ENTITY_LIST_ROUTE_CONTEXT_SESSION_KEY, routeKey);
|
|
5019
|
+
}
|
|
5020
|
+
catch {
|
|
5021
|
+
// sessionStorage may be unavailable
|
|
5022
|
+
}
|
|
5023
|
+
}
|
|
5024
|
+
}
|
|
5025
|
+
async getListPersistenceMode() {
|
|
5026
|
+
if (this.listPersistenceMode != null) {
|
|
5027
|
+
return this.listPersistenceMode;
|
|
5028
|
+
}
|
|
5029
|
+
const value = await this.settings.get(AXPCommonSettings.EntityListPersistenceMode);
|
|
5030
|
+
this.listPersistenceMode = normalizeEntityListPersistenceMode(value);
|
|
5031
|
+
return this.listPersistenceMode;
|
|
5032
|
+
}
|
|
5033
|
+
async shouldLoadPersistedListState() {
|
|
5034
|
+
return shouldLoadEntityListStateFromStorage(await this.getListPersistenceMode());
|
|
5035
|
+
}
|
|
5036
|
+
async shouldPersistListState() {
|
|
5037
|
+
return canPersistEntityListState(await this.getListPersistenceMode());
|
|
5038
|
+
}
|
|
5039
|
+
async clearEntityListSettings() {
|
|
5040
|
+
await this.settings.scope(AXPPlatformScope.User).update(this.settingEntityKey, (prev) => {
|
|
5041
|
+
if (!prev || typeof prev !== 'object') {
|
|
5042
|
+
return {};
|
|
5043
|
+
}
|
|
5044
|
+
const next = { ...prev };
|
|
5045
|
+
delete next['list'];
|
|
5046
|
+
return next;
|
|
5047
|
+
});
|
|
4769
5048
|
}
|
|
4770
5049
|
async applySettings() {
|
|
4771
|
-
this.
|
|
5050
|
+
if (await this.shouldPersistListState()) {
|
|
5051
|
+
this.saveSettings('view');
|
|
5052
|
+
}
|
|
5053
|
+
if (!(await this.shouldLoadPersistedListState())) {
|
|
5054
|
+
this.loadListPagingFromViewSettings(null);
|
|
5055
|
+
this.expandedRowIds.set([]);
|
|
5056
|
+
return;
|
|
5057
|
+
}
|
|
4772
5058
|
const listViewSetting = await this.settings.get(this.settingEntityKey);
|
|
4773
5059
|
if (listViewSetting) {
|
|
4774
5060
|
const columns = listViewSetting.list?.views?.[this.view().name]?.columns;
|
|
4775
|
-
const pageSize = listViewSetting.list?.views?.[this.view().name]?.pageSize;
|
|
4776
5061
|
const sorts = listViewSetting.list?.views?.[this.view().name]?.sorts;
|
|
4777
5062
|
const filters = listViewSetting.list?.views?.[this.view().name]?.filters;
|
|
4778
5063
|
let columnVisibilityMap;
|
|
@@ -4781,7 +5066,7 @@ class AXPEntityMasterListViewModel {
|
|
|
4781
5066
|
columnVisibilityMap = new Map(columns.map((col) => [col.name, col.visible]));
|
|
4782
5067
|
columnWidthsMap = new Map(columns.map((col) => [col.name, col.width]));
|
|
4783
5068
|
}
|
|
4784
|
-
|
|
5069
|
+
this.loadListPagingFromViewSettings(listViewSetting);
|
|
4785
5070
|
if (columns && columnVisibilityMap && columnWidthsMap) {
|
|
4786
5071
|
this.columns.update((prev) => prev
|
|
4787
5072
|
.map((c) => {
|
|
@@ -4803,16 +5088,102 @@ class AXPEntityMasterListViewModel {
|
|
|
4803
5088
|
if (Array.isArray(filters) && !this.hasQueryParamsFilters) {
|
|
4804
5089
|
this.filterQueries.set(filters);
|
|
4805
5090
|
}
|
|
5091
|
+
const expandedRowIds = listViewSetting.list?.views?.[this.view().name]?.expandedRowIds;
|
|
5092
|
+
if (Array.isArray(expandedRowIds)) {
|
|
5093
|
+
this.expandedRowIds.set(expandedRowIds.map((id) => String(id)).filter(Boolean));
|
|
5094
|
+
}
|
|
5095
|
+
else {
|
|
5096
|
+
this.expandedRowIds.set([]);
|
|
5097
|
+
}
|
|
5098
|
+
}
|
|
5099
|
+
else {
|
|
5100
|
+
this.loadListPagingFromViewSettings(null);
|
|
5101
|
+
}
|
|
5102
|
+
}
|
|
5103
|
+
async ensureListPagingResolved() {
|
|
5104
|
+
if (this.resolvedListPaging() != null) {
|
|
5105
|
+
return;
|
|
5106
|
+
}
|
|
5107
|
+
if (!(await this.shouldLoadPersistedListState())) {
|
|
5108
|
+
this.loadListPagingFromViewSettings(null);
|
|
5109
|
+
return;
|
|
5110
|
+
}
|
|
5111
|
+
const entitySetting = await this.settings.get(this.settingEntityKey);
|
|
5112
|
+
this.loadListPagingFromViewSettings(entitySetting);
|
|
5113
|
+
}
|
|
5114
|
+
getResolvedListPaging() {
|
|
5115
|
+
return (this.resolvedListPaging() ??
|
|
5116
|
+
normalizeListPaging(undefined, this.view().pageSize || this.dataSource.config.pageSize || 10));
|
|
5117
|
+
}
|
|
5118
|
+
applyPagingToDataSourceWithoutLoad() {
|
|
5119
|
+
applyDataSourcePagingWithoutLoad(this.dataSource, this.getResolvedListPaging());
|
|
5120
|
+
}
|
|
5121
|
+
saveListPaging(take, skip) {
|
|
5122
|
+
const paging = normalizeListPaging({ take, skip }, this.view().pageSize || 10);
|
|
5123
|
+
this.resolvedListPaging.set(paging);
|
|
5124
|
+
this.saveSettings('listPaging', paging);
|
|
5125
|
+
}
|
|
5126
|
+
resetListPagingSkip() {
|
|
5127
|
+
const paging = normalizeListPaging({ take: this.getResolvedListPaging().take, skip: 0 }, this.view().pageSize || 10);
|
|
5128
|
+
this.resolvedListPaging.set(paging);
|
|
5129
|
+
this.saveSettings('listPaging', paging);
|
|
5130
|
+
}
|
|
5131
|
+
loadListPagingFromViewSettings(entitySetting) {
|
|
5132
|
+
const viewSettings = entitySetting?.list?.views?.[this.view().name];
|
|
5133
|
+
const defaultTake = this.view().pageSize || 10;
|
|
5134
|
+
let paging = viewSettings?.paging;
|
|
5135
|
+
if (!paging && typeof viewSettings?.pageSize === 'number') {
|
|
5136
|
+
paging = { take: viewSettings.pageSize, skip: 0 };
|
|
4806
5137
|
}
|
|
5138
|
+
this.resolvedListPaging.set(normalizeListPaging(paging, defaultTake));
|
|
5139
|
+
}
|
|
5140
|
+
getExpandedRowIds() {
|
|
5141
|
+
return this.expandedRowIds();
|
|
5142
|
+
}
|
|
5143
|
+
/**
|
|
5144
|
+
* Updates persisted expanded row ids when the user expands or collapses a tree row.
|
|
5145
|
+
*/
|
|
5146
|
+
updateExpandedRowId(rowId, expanded) {
|
|
5147
|
+
if (!rowId || !this.parentKey()) {
|
|
5148
|
+
return;
|
|
5149
|
+
}
|
|
5150
|
+
const next = new Set(this.expandedRowIds());
|
|
5151
|
+
if (expanded) {
|
|
5152
|
+
next.add(rowId);
|
|
5153
|
+
}
|
|
5154
|
+
else {
|
|
5155
|
+
next.delete(rowId);
|
|
5156
|
+
}
|
|
5157
|
+
const ids = Array.from(next);
|
|
5158
|
+
this.expandedRowIds.set(ids);
|
|
5159
|
+
this.saveSettings('expandedRows', ids);
|
|
5160
|
+
}
|
|
5161
|
+
handleRowExpandChange(rowData) {
|
|
5162
|
+
if (this.skipExpandedRowPersistence || !this.parentKey()) {
|
|
5163
|
+
return;
|
|
5164
|
+
}
|
|
5165
|
+
const key = this.dataSource.config?.key ?? 'id';
|
|
5166
|
+
const rowId = getEntityListRowId(rowData, key);
|
|
5167
|
+
if (!rowId) {
|
|
5168
|
+
return;
|
|
5169
|
+
}
|
|
5170
|
+
// onItemExpanded fires before the grid toggles __meta__.expanded on expandedItem.
|
|
5171
|
+
const meta = rowData['__meta__'];
|
|
5172
|
+
const wasExpanded = meta?.['expanded'] === true;
|
|
5173
|
+
this.updateExpandedRowId(rowId, !wasExpanded);
|
|
4807
5174
|
}
|
|
4808
5175
|
async saveSettings(changesType, data) {
|
|
5176
|
+
if (!(await this.shouldPersistListState())) {
|
|
5177
|
+
return;
|
|
5178
|
+
}
|
|
4809
5179
|
const updateSettings = (updateFn) => {
|
|
4810
5180
|
this.settings.scope(AXPPlatformScope.User).update(this.settingEntityKey, updateFn);
|
|
4811
5181
|
};
|
|
4812
5182
|
switch (changesType) {
|
|
4813
|
-
case 'columnSizes':
|
|
5183
|
+
case 'columnSizes': {
|
|
5184
|
+
const columnSizeData = data;
|
|
4814
5185
|
updateSettings((prev) => {
|
|
4815
|
-
const field =
|
|
5186
|
+
const field = columnSizeData.dataField.split('-')[1];
|
|
4816
5187
|
const newSettings = { ...prev };
|
|
4817
5188
|
const existingColumns = prev?.list?.views?.[this.view().name]?.columns;
|
|
4818
5189
|
const baseColumns = Array.isArray(existingColumns) && existingColumns.length
|
|
@@ -4824,7 +5195,7 @@ class AXPEntityMasterListViewModel {
|
|
|
4824
5195
|
}));
|
|
4825
5196
|
const updatedColumns = baseColumns.map((c) => ({
|
|
4826
5197
|
...c,
|
|
4827
|
-
width: c.name === field ?
|
|
5198
|
+
width: c.name === field ? columnSizeData.width : c.width,
|
|
4828
5199
|
}));
|
|
4829
5200
|
const x = this.allAvailableColumns().map((c) => ({
|
|
4830
5201
|
name: c.column?.options?.dataPath ?? c.name,
|
|
@@ -4835,10 +5206,12 @@ class AXPEntityMasterListViewModel {
|
|
|
4835
5206
|
return newSettings;
|
|
4836
5207
|
});
|
|
4837
5208
|
break;
|
|
4838
|
-
|
|
5209
|
+
}
|
|
5210
|
+
case 'columnOrders': {
|
|
5211
|
+
const orderedColumns = data;
|
|
4839
5212
|
updateSettings((prev) => {
|
|
4840
5213
|
const newSettings = { ...prev };
|
|
4841
|
-
set(newSettings, `list.views.${this.view().name}.columns`,
|
|
5214
|
+
set(newSettings, `list.views.${this.view().name}.columns`, orderedColumns.map((c) => ({
|
|
4842
5215
|
name: c.column?.options?.dataPath ?? c.name,
|
|
4843
5216
|
visible: c.visible,
|
|
4844
5217
|
width: c.width,
|
|
@@ -4846,6 +5219,7 @@ class AXPEntityMasterListViewModel {
|
|
|
4846
5219
|
return newSettings;
|
|
4847
5220
|
});
|
|
4848
5221
|
break;
|
|
5222
|
+
}
|
|
4849
5223
|
case 'view':
|
|
4850
5224
|
updateSettings((prev) => ({
|
|
4851
5225
|
...prev,
|
|
@@ -4865,6 +5239,26 @@ class AXPEntityMasterListViewModel {
|
|
|
4865
5239
|
[this.view().name]: {
|
|
4866
5240
|
...prev?.list?.views?.[this.view().name],
|
|
4867
5241
|
pageSize: data,
|
|
5242
|
+
paging: normalizeListPaging({
|
|
5243
|
+
take: data,
|
|
5244
|
+
skip: prev?.list?.views?.[this.view().name]?.paging?.skip,
|
|
5245
|
+
}, this.view().pageSize || 10),
|
|
5246
|
+
},
|
|
5247
|
+
},
|
|
5248
|
+
},
|
|
5249
|
+
}));
|
|
5250
|
+
break;
|
|
5251
|
+
case 'listPaging':
|
|
5252
|
+
updateSettings((prev) => ({
|
|
5253
|
+
...prev,
|
|
5254
|
+
list: {
|
|
5255
|
+
...prev?.list,
|
|
5256
|
+
views: {
|
|
5257
|
+
...prev?.list?.views,
|
|
5258
|
+
[this.view().name]: {
|
|
5259
|
+
...prev?.list?.views?.[this.view().name],
|
|
5260
|
+
paging: data,
|
|
5261
|
+
pageSize: data.take,
|
|
4868
5262
|
},
|
|
4869
5263
|
},
|
|
4870
5264
|
},
|
|
@@ -4900,6 +5294,21 @@ class AXPEntityMasterListViewModel {
|
|
|
4900
5294
|
},
|
|
4901
5295
|
}));
|
|
4902
5296
|
break;
|
|
5297
|
+
case 'expandedRows':
|
|
5298
|
+
updateSettings((prev) => ({
|
|
5299
|
+
...prev,
|
|
5300
|
+
list: {
|
|
5301
|
+
...prev?.list,
|
|
5302
|
+
views: {
|
|
5303
|
+
...prev?.list?.views,
|
|
5304
|
+
[this.view().name]: {
|
|
5305
|
+
...prev?.list?.views?.[this.view().name],
|
|
5306
|
+
expandedRowIds: data,
|
|
5307
|
+
},
|
|
5308
|
+
},
|
|
5309
|
+
},
|
|
5310
|
+
}));
|
|
5311
|
+
break;
|
|
4903
5312
|
default:
|
|
4904
5313
|
break;
|
|
4905
5314
|
}
|
|
@@ -5139,6 +5548,7 @@ class AXPEntityMasterListViewModel {
|
|
|
5139
5548
|
this.applyViewFilters();
|
|
5140
5549
|
}
|
|
5141
5550
|
async applyFilterAndSort() {
|
|
5551
|
+
await this.ensureListPagingResolved();
|
|
5142
5552
|
const sorts = this.sortedFields()
|
|
5143
5553
|
.filter((sf) => sf.dir)
|
|
5144
5554
|
.map((s) => ({ name: s.name, dir: s.dir }));
|
|
@@ -5148,10 +5558,12 @@ class AXPEntityMasterListViewModel {
|
|
|
5148
5558
|
if (sortKey === this.lastAppliedSortKey && filterKey === this.lastAppliedFilterKey) {
|
|
5149
5559
|
return; // No effective change; avoid redundant refresh
|
|
5150
5560
|
}
|
|
5151
|
-
|
|
5152
|
-
const filtersChanged = filterKey !== this.lastAppliedFilterKey;
|
|
5561
|
+
const filtersChanged = this.lastAppliedFilterKey != null && filterKey !== this.lastAppliedFilterKey;
|
|
5153
5562
|
this.lastAppliedSortKey = sortKey;
|
|
5154
5563
|
this.lastAppliedFilterKey = filterKey;
|
|
5564
|
+
if (filtersChanged) {
|
|
5565
|
+
this.resetListPagingSkip();
|
|
5566
|
+
}
|
|
5155
5567
|
this.dataSource.clearFilter();
|
|
5156
5568
|
this.dataSource.sort(...sorts.map((s) => ({ dir: s.dir, field: s.name })));
|
|
5157
5569
|
this.dataSource.filter(this.filterOperatorMiddleware.transformFilter({
|
|
@@ -5358,7 +5770,9 @@ class AXPEntityListViewModelFactory {
|
|
|
5358
5770
|
this.layout.setNavigationLoading(true);
|
|
5359
5771
|
const config = await this.entityService.resolve(moduleName, entityName);
|
|
5360
5772
|
this.layout.setNavigationLoading(false);
|
|
5361
|
-
|
|
5773
|
+
const vm = new AXPEntityMasterListViewModel(this.injector, config);
|
|
5774
|
+
await vm.initializeListPersistence();
|
|
5775
|
+
return vm;
|
|
5362
5776
|
}
|
|
5363
5777
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityListViewModelFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5364
5778
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityListViewModelFactory, providedIn: 'root' }); }
|
|
@@ -6107,6 +6521,150 @@ const AXPEntityDetailViewModelResolver = (route, state, service = inject(AXPEnti
|
|
|
6107
6521
|
return service.create(moduleName, entityName, id);
|
|
6108
6522
|
};
|
|
6109
6523
|
|
|
6524
|
+
//#endregion
|
|
6525
|
+
//#region ---- Quick search: schema-driven field paths ----
|
|
6526
|
+
const NON_TEXT_DATATYPES = new Set([
|
|
6527
|
+
'number',
|
|
6528
|
+
'integer',
|
|
6529
|
+
'int',
|
|
6530
|
+
'long',
|
|
6531
|
+
'float',
|
|
6532
|
+
'double',
|
|
6533
|
+
'decimal',
|
|
6534
|
+
'money',
|
|
6535
|
+
'currency',
|
|
6536
|
+
'boolean',
|
|
6537
|
+
'bool',
|
|
6538
|
+
'date',
|
|
6539
|
+
'datetime',
|
|
6540
|
+
'time',
|
|
6541
|
+
'object',
|
|
6542
|
+
'array',
|
|
6543
|
+
'json',
|
|
6544
|
+
'image',
|
|
6545
|
+
'file',
|
|
6546
|
+
'binary',
|
|
6547
|
+
]);
|
|
6548
|
+
/**
|
|
6549
|
+
* Whether an entity property likely stores free text worth a `contains` quick-search clause.
|
|
6550
|
+
*/
|
|
6551
|
+
function isTextLikeDataType(dataType) {
|
|
6552
|
+
const dt = (dataType ?? 'string').toLowerCase().trim();
|
|
6553
|
+
if (!dt || NON_TEXT_DATATYPES.has(dt)) {
|
|
6554
|
+
return false;
|
|
6555
|
+
}
|
|
6556
|
+
return true;
|
|
6557
|
+
}
|
|
6558
|
+
/**
|
|
6559
|
+
* Lodash-get paths for quick search from a single entity definition: string-like property names
|
|
6560
|
+
* plus lookup `expose[].target` paths (e.g. `brand.title`).
|
|
6561
|
+
*/
|
|
6562
|
+
function collectQuickSearchPathsFromSingleEntityDefinition(entity) {
|
|
6563
|
+
if (!entity?.properties?.length) {
|
|
6564
|
+
return [];
|
|
6565
|
+
}
|
|
6566
|
+
const paths = new Set();
|
|
6567
|
+
for (const p of entity.properties) {
|
|
6568
|
+
if (isTextLikeDataType(p.schema?.dataType)) {
|
|
6569
|
+
paths.add(p.name);
|
|
6570
|
+
}
|
|
6571
|
+
const opts = p.schema?.interface?.options;
|
|
6572
|
+
const expose = opts?.['expose'];
|
|
6573
|
+
if (!Array.isArray(expose)) {
|
|
6574
|
+
continue;
|
|
6575
|
+
}
|
|
6576
|
+
for (const row of expose) {
|
|
6577
|
+
if (row && typeof row === 'object' && typeof row.target === 'string') {
|
|
6578
|
+
const t = (row.target).trim();
|
|
6579
|
+
if (t) {
|
|
6580
|
+
paths.add(t);
|
|
6581
|
+
}
|
|
6582
|
+
}
|
|
6583
|
+
}
|
|
6584
|
+
}
|
|
6585
|
+
return [...paths];
|
|
6586
|
+
}
|
|
6587
|
+
//#endregion
|
|
6588
|
+
//#region ---- Column-derived nested paths ----
|
|
6589
|
+
/**
|
|
6590
|
+
* Adds dotted paths from master columns (`name` or `options.dataPath`), e.g. `person.fullName`, `jobDefinition.title`.
|
|
6591
|
+
*/
|
|
6592
|
+
function collectNestedFieldPathsFromEntityColumns(entity) {
|
|
6593
|
+
if (!entity?.columns?.length) {
|
|
6594
|
+
return [];
|
|
6595
|
+
}
|
|
6596
|
+
const paths = new Set();
|
|
6597
|
+
for (const col of entity.columns) {
|
|
6598
|
+
const name = col.name.trim();
|
|
6599
|
+
if (name.includes('.')) {
|
|
6600
|
+
paths.add(name);
|
|
6601
|
+
}
|
|
6602
|
+
const rawDp = col.options?.['dataPath'];
|
|
6603
|
+
if (typeof rawDp === 'string') {
|
|
6604
|
+
const dp = rawDp.trim();
|
|
6605
|
+
if (dp.includes('.')) {
|
|
6606
|
+
paths.add(dp);
|
|
6607
|
+
}
|
|
6608
|
+
}
|
|
6609
|
+
}
|
|
6610
|
+
return [...paths];
|
|
6611
|
+
}
|
|
6612
|
+
//#endregion
|
|
6613
|
+
//#region ---- Related merge-detail paths ----
|
|
6614
|
+
function parseRelatedEntityFullName(fullName) {
|
|
6615
|
+
const t = fullName.trim();
|
|
6616
|
+
const idx = t.indexOf('.');
|
|
6617
|
+
if (idx <= 0 || idx >= t.length - 1) {
|
|
6618
|
+
return null;
|
|
6619
|
+
}
|
|
6620
|
+
return {
|
|
6621
|
+
moduleName: t.slice(0, idx),
|
|
6622
|
+
entityName: t.slice(idx + 1),
|
|
6623
|
+
};
|
|
6624
|
+
}
|
|
6625
|
+
//#endregion
|
|
6626
|
+
//#region ---- Public API ----
|
|
6627
|
+
/**
|
|
6628
|
+
* Collects lodash-get field paths used for mock/API quick search (`contains` / OR filters):
|
|
6629
|
+
* host properties and lookup expose targets, dotted column paths, and merge-detail related entities
|
|
6630
|
+
* prefixed with the related entity merge `persistence.dataPath` (e.g. `person.firstName`).
|
|
6631
|
+
*/
|
|
6632
|
+
async function collectEntityQuickSearchFieldPaths(entity, resolveRelatedDefinition) {
|
|
6633
|
+
if (!entity) {
|
|
6634
|
+
return [];
|
|
6635
|
+
}
|
|
6636
|
+
const paths = new Set();
|
|
6637
|
+
for (const p of collectQuickSearchPathsFromSingleEntityDefinition(entity)) {
|
|
6638
|
+
paths.add(p);
|
|
6639
|
+
}
|
|
6640
|
+
for (const p of collectNestedFieldPathsFromEntityColumns(entity)) {
|
|
6641
|
+
paths.add(p);
|
|
6642
|
+
}
|
|
6643
|
+
const related = entity.relatedEntities ?? [];
|
|
6644
|
+
for (const rel of related) {
|
|
6645
|
+
const dataPath = rel.persistence?.dataPath?.trim();
|
|
6646
|
+
if (!dataPath || rel.layout?.type !== 'merge-detail') {
|
|
6647
|
+
continue;
|
|
6648
|
+
}
|
|
6649
|
+
const parsed = rel.entity ? parseRelatedEntityFullName(rel.entity) : null;
|
|
6650
|
+
if (!parsed) {
|
|
6651
|
+
continue;
|
|
6652
|
+
}
|
|
6653
|
+
const relatedDef = await resolveRelatedDefinition(parsed.moduleName, parsed.entityName);
|
|
6654
|
+
if (!relatedDef) {
|
|
6655
|
+
continue;
|
|
6656
|
+
}
|
|
6657
|
+
for (const p of collectQuickSearchPathsFromSingleEntityDefinition(relatedDef)) {
|
|
6658
|
+
paths.add(`${dataPath}.${p}`);
|
|
6659
|
+
}
|
|
6660
|
+
for (const p of collectNestedFieldPathsFromEntityColumns(relatedDef)) {
|
|
6661
|
+
paths.add(`${dataPath}.${p}`);
|
|
6662
|
+
}
|
|
6663
|
+
}
|
|
6664
|
+
return [...paths];
|
|
6665
|
+
}
|
|
6666
|
+
//#endregion
|
|
6667
|
+
|
|
6110
6668
|
class AXPEntityPreloadFiltersViewModel {
|
|
6111
6669
|
//#region ---- Constructor ----
|
|
6112
6670
|
constructor(injector, config) {
|
|
@@ -6199,6 +6757,225 @@ const AXPEntityPreloadFiltersViewModelResolver = async (route, state) => {
|
|
|
6199
6757
|
};
|
|
6200
6758
|
//#endregion
|
|
6201
6759
|
|
|
6760
|
+
//#region ---- Path / numeric helpers ----
|
|
6761
|
+
function getPath(obj, path) {
|
|
6762
|
+
if (obj == null || path.length === 0) {
|
|
6763
|
+
return undefined;
|
|
6764
|
+
}
|
|
6765
|
+
const parts = path.split('.');
|
|
6766
|
+
let cur = obj;
|
|
6767
|
+
for (const p of parts) {
|
|
6768
|
+
if (cur == null || typeof cur !== 'object') {
|
|
6769
|
+
return undefined;
|
|
6770
|
+
}
|
|
6771
|
+
cur = cur[p];
|
|
6772
|
+
}
|
|
6773
|
+
return cur;
|
|
6774
|
+
}
|
|
6775
|
+
function toNumber(value) {
|
|
6776
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
6777
|
+
return value;
|
|
6778
|
+
}
|
|
6779
|
+
if (typeof value === 'string' && value.trim().length > 0) {
|
|
6780
|
+
const n = Number(value);
|
|
6781
|
+
return Number.isFinite(n) ? n : null;
|
|
6782
|
+
}
|
|
6783
|
+
return null;
|
|
6784
|
+
}
|
|
6785
|
+
function defaultAlias(measure, index) {
|
|
6786
|
+
if (measure.alias?.trim()) {
|
|
6787
|
+
return measure.alias.trim();
|
|
6788
|
+
}
|
|
6789
|
+
if (measure.reducer === 'count') {
|
|
6790
|
+
return index === 0 ? 'count' : `count_${index}`;
|
|
6791
|
+
}
|
|
6792
|
+
const field = measure.field ?? 'value';
|
|
6793
|
+
const safeField = field.replace(/\./g, '_');
|
|
6794
|
+
return `${measure.reducer}_${safeField}`;
|
|
6795
|
+
}
|
|
6796
|
+
/**
|
|
6797
|
+
* Pure aggregation over already-filtered plain rows (e.g. outputs of {@link filterSortEntityRows}).
|
|
6798
|
+
*/
|
|
6799
|
+
function computeEntityAggregates(rows, request) {
|
|
6800
|
+
const groupBy = request.groupBy ?? [];
|
|
6801
|
+
const measures = request.measures ?? [];
|
|
6802
|
+
if (measures.length === 0) {
|
|
6803
|
+
return [];
|
|
6804
|
+
}
|
|
6805
|
+
const groups = new Map();
|
|
6806
|
+
const stableGroupKey = (row) => {
|
|
6807
|
+
const parts = groupBy.map((path) => getPath(row, path));
|
|
6808
|
+
return JSON.stringify(parts);
|
|
6809
|
+
};
|
|
6810
|
+
for (const row of rows) {
|
|
6811
|
+
const k = stableGroupKey(row);
|
|
6812
|
+
let bucket = groups.get(k);
|
|
6813
|
+
if (!bucket) {
|
|
6814
|
+
bucket = {
|
|
6815
|
+
keyParts: groupBy.map((path) => getPath(row, path)),
|
|
6816
|
+
rows: [],
|
|
6817
|
+
};
|
|
6818
|
+
groups.set(k, bucket);
|
|
6819
|
+
}
|
|
6820
|
+
bucket.rows.push(row);
|
|
6821
|
+
}
|
|
6822
|
+
const result = [];
|
|
6823
|
+
for (const bucket of groups.values()) {
|
|
6824
|
+
const out = {};
|
|
6825
|
+
groupBy.forEach((field, i) => {
|
|
6826
|
+
out[field] = bucket.keyParts[i];
|
|
6827
|
+
});
|
|
6828
|
+
measures.forEach((measure, index) => {
|
|
6829
|
+
const alias = defaultAlias(measure, index);
|
|
6830
|
+
const gRows = bucket.rows;
|
|
6831
|
+
if (measure.reducer === 'count') {
|
|
6832
|
+
out[alias] = gRows.length;
|
|
6833
|
+
return;
|
|
6834
|
+
}
|
|
6835
|
+
const fieldPath = measure.field;
|
|
6836
|
+
if (!fieldPath) {
|
|
6837
|
+
out[alias] = null;
|
|
6838
|
+
return;
|
|
6839
|
+
}
|
|
6840
|
+
const nums = gRows.map((r) => toNumber(getPath(r, fieldPath))).filter((n) => n !== null);
|
|
6841
|
+
switch (measure.reducer) {
|
|
6842
|
+
case 'sum':
|
|
6843
|
+
out[alias] = nums.reduce((a, b) => a + b, 0);
|
|
6844
|
+
break;
|
|
6845
|
+
case 'min':
|
|
6846
|
+
out[alias] = nums.length ? Math.min(...nums) : null;
|
|
6847
|
+
break;
|
|
6848
|
+
case 'max':
|
|
6849
|
+
out[alias] = nums.length ? Math.max(...nums) : null;
|
|
6850
|
+
break;
|
|
6851
|
+
case 'avg':
|
|
6852
|
+
out[alias] = nums.length ? nums.reduce((a, b) => a + b, 0) / nums.length : null;
|
|
6853
|
+
break;
|
|
6854
|
+
default:
|
|
6855
|
+
out[alias] = null;
|
|
6856
|
+
}
|
|
6857
|
+
});
|
|
6858
|
+
result.push(out);
|
|
6859
|
+
}
|
|
6860
|
+
return result;
|
|
6861
|
+
}
|
|
6862
|
+
//#endregion
|
|
6863
|
+
|
|
6864
|
+
//#endregion
|
|
6865
|
+
//#region ---- Pure helpers ----
|
|
6866
|
+
/**
|
|
6867
|
+
* Fields where `contains` means hierarchical category membership (expand to descendants).
|
|
6868
|
+
* Excludes e.g. `roleIds`, which uses array membership only and must use normal filter logic.
|
|
6869
|
+
*/
|
|
6870
|
+
function isCategoryContainsFieldName(field) {
|
|
6871
|
+
if (field === 'categoryIds') {
|
|
6872
|
+
return true;
|
|
6873
|
+
}
|
|
6874
|
+
if (typeof field === 'string' && field.endsWith('Ids') && field !== 'roleIds') {
|
|
6875
|
+
return true;
|
|
6876
|
+
}
|
|
6877
|
+
return false;
|
|
6878
|
+
}
|
|
6879
|
+
/**
|
|
6880
|
+
* Check if the entity is a category entity (ends with 'Category').
|
|
6881
|
+
*/
|
|
6882
|
+
function isCategoryEntity(entityName) {
|
|
6883
|
+
return entityName.endsWith('Category');
|
|
6884
|
+
}
|
|
6885
|
+
/**
|
|
6886
|
+
* Check if the filter is a category filter (contains operator on categoryIds field).
|
|
6887
|
+
* Handles both simple filters and compound filters.
|
|
6888
|
+
*/
|
|
6889
|
+
function isCategoryFilter(filter) {
|
|
6890
|
+
if (filter?.operator?.type === 'contains' && isCategoryContainsFieldName(filter.field)) {
|
|
6891
|
+
return true;
|
|
6892
|
+
}
|
|
6893
|
+
if (filter?.logic && filter?.filters && Array.isArray(filter.filters)) {
|
|
6894
|
+
return filter.filters.some((nestedFilter) => nestedFilter?.operator?.type === 'contains' && isCategoryContainsFieldName(nestedFilter.field));
|
|
6895
|
+
}
|
|
6896
|
+
return false;
|
|
6897
|
+
}
|
|
6898
|
+
//#endregion
|
|
6899
|
+
//#region ---- Query execution ----
|
|
6900
|
+
/**
|
|
6901
|
+
* Apply recursive category filtering: entities that belong to the category or any of its children.
|
|
6902
|
+
*/
|
|
6903
|
+
async function applyRecursiveCategoryFilter(result, filter, entityName, getAllChildCategoryIds) {
|
|
6904
|
+
let categoryFilter = filter;
|
|
6905
|
+
let otherFilters = [];
|
|
6906
|
+
if (filter?.logic && filter?.filters && Array.isArray(filter.filters)) {
|
|
6907
|
+
const categoryFilterIndex = filter.filters.findIndex((f) => f?.operator?.type === 'contains' && isCategoryContainsFieldName(f.field));
|
|
6908
|
+
if (categoryFilterIndex !== -1) {
|
|
6909
|
+
categoryFilter = filter.filters[categoryFilterIndex];
|
|
6910
|
+
otherFilters = filter.filters.filter((_, index) => index !== categoryFilterIndex);
|
|
6911
|
+
}
|
|
6912
|
+
}
|
|
6913
|
+
if (!categoryFilter) {
|
|
6914
|
+
return applyFilterArray(result, [filter]);
|
|
6915
|
+
}
|
|
6916
|
+
const categoryId = categoryFilter.value;
|
|
6917
|
+
const categoryField = categoryFilter.field;
|
|
6918
|
+
const allCategoryIds = await getAllChildCategoryIds(categoryId, entityName);
|
|
6919
|
+
let filteredResult = result.filter((item) => {
|
|
6920
|
+
const categoryIds = item[categoryField];
|
|
6921
|
+
if (!categoryIds)
|
|
6922
|
+
return false;
|
|
6923
|
+
const itemCategoryIds = Array.isArray(categoryIds) ? categoryIds : [categoryIds];
|
|
6924
|
+
return itemCategoryIds.some((itemCategoryId) => allCategoryIds.includes(itemCategoryId));
|
|
6925
|
+
});
|
|
6926
|
+
if (otherFilters.length > 0) {
|
|
6927
|
+
filteredResult = applyFilterArray(filteredResult, otherFilters);
|
|
6928
|
+
}
|
|
6929
|
+
return filteredResult;
|
|
6930
|
+
}
|
|
6931
|
+
/**
|
|
6932
|
+
* Calculate childrenCount for each category entity when missing.
|
|
6933
|
+
*/
|
|
6934
|
+
async function calculateChildrenCounts(items, entityName, getDirectChildCount) {
|
|
6935
|
+
return Promise.all(items.map(async (item) => {
|
|
6936
|
+
if (typeof item.childrenCount === 'number') {
|
|
6937
|
+
return { ...item };
|
|
6938
|
+
}
|
|
6939
|
+
const childrenCount = await getDirectChildCount(item.id, entityName);
|
|
6940
|
+
return { ...item, childrenCount };
|
|
6941
|
+
}));
|
|
6942
|
+
}
|
|
6943
|
+
/**
|
|
6944
|
+
* Loads raw rows for an entity and applies the same sorting and filtering as {@link runEntityQuery},
|
|
6945
|
+
* without pagination.
|
|
6946
|
+
*/
|
|
6947
|
+
async function filterSortEntityRows(entityName, request, adapters) {
|
|
6948
|
+
let result = await adapters.getRawAll(entityName);
|
|
6949
|
+
if (request.sort && request.sort.length) {
|
|
6950
|
+
result = applySortArray(result, request.sort);
|
|
6951
|
+
}
|
|
6952
|
+
if (request.filter && isCategoryFilter(request.filter)) {
|
|
6953
|
+
result = await applyRecursiveCategoryFilter(result, request.filter, entityName, adapters.getAllChildCategoryIds);
|
|
6954
|
+
}
|
|
6955
|
+
else {
|
|
6956
|
+
result = applyFilterArray(result, request.filter ? [request.filter] : []);
|
|
6957
|
+
}
|
|
6958
|
+
if (isCategoryEntity(entityName)) {
|
|
6959
|
+
result = await calculateChildrenCounts(result, entityName, adapters.getDirectChildCount);
|
|
6960
|
+
}
|
|
6961
|
+
return result;
|
|
6962
|
+
}
|
|
6963
|
+
/**
|
|
6964
|
+
* Shared entity query logic: sort, filter (including recursive category filter), childrenCount, pagination.
|
|
6965
|
+
*/
|
|
6966
|
+
async function runEntityQuery(entityName, request, adapters) {
|
|
6967
|
+
const rows = await filterSortEntityRows(entityName, request, adapters);
|
|
6968
|
+
const skip = request.skip ?? 0;
|
|
6969
|
+
const take = request.take ?? 0;
|
|
6970
|
+
return {
|
|
6971
|
+
total: rows.length,
|
|
6972
|
+
items: rows.slice(skip, skip + take),
|
|
6973
|
+
};
|
|
6974
|
+
}
|
|
6975
|
+
//#endregion
|
|
6976
|
+
|
|
6977
|
+
//#endregion
|
|
6978
|
+
|
|
6202
6979
|
//#region ---- Imports ----
|
|
6203
6980
|
//#endregion
|
|
6204
6981
|
//#region ---- Constants ----
|
|
@@ -6938,7 +7715,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
6938
7715
|
// Use setTimeout to ensure DOM is updated after tree reload
|
|
6939
7716
|
setTimeout(() => {
|
|
6940
7717
|
if (this.searchValue().trim()) {
|
|
6941
|
-
this.highlightService.highlight('ax-tree-view .
|
|
7718
|
+
this.highlightService.highlight('ax-tree-view .truncate', this.searchValue().trim());
|
|
6942
7719
|
}
|
|
6943
7720
|
}, 100);
|
|
6944
7721
|
}
|
|
@@ -10437,6 +11214,7 @@ class AXPEntityListTableService {
|
|
|
10437
11214
|
this.workflow = inject(AXPWorkflowService);
|
|
10438
11215
|
this.commandService = inject(AXPCommandService);
|
|
10439
11216
|
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
11217
|
+
this.settings = inject(AXPSettingsService);
|
|
10440
11218
|
this.evaluateExpressions = async (options, data) => {
|
|
10441
11219
|
if (!options) {
|
|
10442
11220
|
return {};
|
|
@@ -10457,6 +11235,20 @@ class AXPEntityListTableService {
|
|
|
10457
11235
|
* Convert Entity to List Widget Options
|
|
10458
11236
|
*/
|
|
10459
11237
|
async convertEntityToListOptions(entity, options, allActions) {
|
|
11238
|
+
const viewIndexCol = entity.interfaces?.master?.list?.views?.[0]?.indexCol;
|
|
11239
|
+
let showIndex = false;
|
|
11240
|
+
if (viewIndexCol !== undefined) {
|
|
11241
|
+
showIndex = viewIndexCol;
|
|
11242
|
+
}
|
|
11243
|
+
else {
|
|
11244
|
+
try {
|
|
11245
|
+
const fromSetting = await this.settings.get(AXPCommonSettings.ShowRowIndexColumn);
|
|
11246
|
+
showIndex = fromSetting ?? false;
|
|
11247
|
+
}
|
|
11248
|
+
catch {
|
|
11249
|
+
showIndex = false;
|
|
11250
|
+
}
|
|
11251
|
+
}
|
|
10460
11252
|
const listOptions = {
|
|
10461
11253
|
// 📊 Data Source
|
|
10462
11254
|
dataSource: this.createDataSource(entity),
|
|
@@ -10466,7 +11258,7 @@ class AXPEntityListTableService {
|
|
|
10466
11258
|
primaryCommands: this.createRowCommands(allActions, 'primary'),
|
|
10467
11259
|
secondaryCommands: this.createRowCommands(allActions, 'secondary'),
|
|
10468
11260
|
// ⚙️ Table Features
|
|
10469
|
-
showIndex
|
|
11261
|
+
showIndex,
|
|
10470
11262
|
allowSelection: this.hasSelectedScopeActions(entity),
|
|
10471
11263
|
paging: true,
|
|
10472
11264
|
showHeader: true,
|
|
@@ -10483,7 +11275,6 @@ class AXPEntityListTableService {
|
|
|
10483
11275
|
// 🎪 Events
|
|
10484
11276
|
...this.createDefaultEvents(entity, allActions, options?.excludeProperties),
|
|
10485
11277
|
};
|
|
10486
|
-
console.log('listOptions', listOptions);
|
|
10487
11278
|
return listOptions;
|
|
10488
11279
|
}
|
|
10489
11280
|
//#endregion
|
|
@@ -10871,6 +11662,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
10871
11662
|
this.commandService = inject(AXPCommandService);
|
|
10872
11663
|
this.eventService = inject(AXPBroadcastEventService);
|
|
10873
11664
|
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
11665
|
+
this.route = inject(ActivatedRoute);
|
|
10874
11666
|
this.isMounted = signal(false, ...(ngDevMode ? [{ debugName: "isMounted" }] : /* istanbul ignore next */ []));
|
|
10875
11667
|
this.entity = signal(null, ...(ngDevMode ? [{ debugName: "entity" }] : /* istanbul ignore next */ []));
|
|
10876
11668
|
this.listNode = signal(null, ...(ngDevMode ? [{ debugName: "listNode" }] : /* istanbul ignore next */ []));
|
|
@@ -11044,13 +11836,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
11044
11836
|
// console.log(this.listWidget()?.instance.output('selectedRows'));
|
|
11045
11837
|
// }
|
|
11046
11838
|
async execute(commandName, _data) {
|
|
11047
|
-
const action = this.
|
|
11048
|
-
return (c.name == commandName &&
|
|
11049
|
-
((this.selectedItems().length
|
|
11050
|
-
? c.scope == AXPEntityCommandScope.Selected
|
|
11051
|
-
: c.scope == AXPEntityCommandScope.Individual) ||
|
|
11052
|
-
c.scope == AXPEntityCommandScope.TypeLevel));
|
|
11053
|
-
});
|
|
11839
|
+
const action = this.findToolbarAction(commandName);
|
|
11054
11840
|
const command = commandName.split('&')[0];
|
|
11055
11841
|
const commandData = action?.scope == AXPEntityCommandScope.Selected
|
|
11056
11842
|
? this.selectedItems()
|
|
@@ -11116,6 +11902,29 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
11116
11902
|
});
|
|
11117
11903
|
}
|
|
11118
11904
|
}
|
|
11905
|
+
/**
|
|
11906
|
+
* Resolves toolbar commands including nested dropdown (`items`) actions.
|
|
11907
|
+
*/
|
|
11908
|
+
findToolbarAction(commandName) {
|
|
11909
|
+
const scopeMatches = (c) => (this.selectedItems().length
|
|
11910
|
+
? c.scope === AXPEntityCommandScope.Selected
|
|
11911
|
+
: c.scope === AXPEntityCommandScope.Individual) || c.scope === AXPEntityCommandScope.TypeLevel;
|
|
11912
|
+
const visit = (nodes) => {
|
|
11913
|
+
for (const node of nodes) {
|
|
11914
|
+
if (node.name === commandName && scopeMatches(node)) {
|
|
11915
|
+
return node;
|
|
11916
|
+
}
|
|
11917
|
+
if (node.items?.length) {
|
|
11918
|
+
const nested = visit(node.items);
|
|
11919
|
+
if (nested) {
|
|
11920
|
+
return nested;
|
|
11921
|
+
}
|
|
11922
|
+
}
|
|
11923
|
+
}
|
|
11924
|
+
return undefined;
|
|
11925
|
+
};
|
|
11926
|
+
return visit(this.allActions());
|
|
11927
|
+
}
|
|
11119
11928
|
async evaluateToolbarExpressions(opts, expressionData) {
|
|
11120
11929
|
if (!opts) {
|
|
11121
11930
|
return {};
|
|
@@ -11128,6 +11937,92 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
11128
11937
|
};
|
|
11129
11938
|
return (await this.expressionEvaluator.evaluate(opts, scope));
|
|
11130
11939
|
}
|
|
11940
|
+
/**
|
|
11941
|
+
* Parses the `filters` query param (same shape as standalone entity list routes).
|
|
11942
|
+
*/
|
|
11943
|
+
parseFiltersFromRoute() {
|
|
11944
|
+
const filtersJson = this.route.snapshot.queryParamMap.get('filters');
|
|
11945
|
+
if (!filtersJson) {
|
|
11946
|
+
return [];
|
|
11947
|
+
}
|
|
11948
|
+
try {
|
|
11949
|
+
const parsed = JSON.parse(filtersJson);
|
|
11950
|
+
const rows = [];
|
|
11951
|
+
if (Array.isArray(parsed)) {
|
|
11952
|
+
for (const item of parsed) {
|
|
11953
|
+
if (item && typeof item === 'object' && typeof item.field === 'string') {
|
|
11954
|
+
rows.push(item);
|
|
11955
|
+
}
|
|
11956
|
+
}
|
|
11957
|
+
}
|
|
11958
|
+
else if (parsed !== null && typeof parsed === 'object') {
|
|
11959
|
+
for (const [field, value] of Object.entries(parsed)) {
|
|
11960
|
+
rows.push({ field, value, operator: { type: 'equal' } });
|
|
11961
|
+
}
|
|
11962
|
+
}
|
|
11963
|
+
return rows
|
|
11964
|
+
.filter((row) => row.field && row.value !== undefined && row.value !== null && row.value !== '')
|
|
11965
|
+
.map((row) => ({
|
|
11966
|
+
field: row.field,
|
|
11967
|
+
operator: row.operator && typeof row.operator === 'object' && 'type' in row.operator
|
|
11968
|
+
? row.operator
|
|
11969
|
+
: { type: 'equal' },
|
|
11970
|
+
value: row.value,
|
|
11971
|
+
hidden: true,
|
|
11972
|
+
}));
|
|
11973
|
+
}
|
|
11974
|
+
catch {
|
|
11975
|
+
return [];
|
|
11976
|
+
}
|
|
11977
|
+
}
|
|
11978
|
+
/**
|
|
11979
|
+
* Route `filters` apply only when the active details `page` matches this list's entity
|
|
11980
|
+
* (e.g. WorkOrder filters must not affect FailureRegister on the same asset layout).
|
|
11981
|
+
*/
|
|
11982
|
+
shouldApplyRouteFilters() {
|
|
11983
|
+
const pageId = this.route.snapshot.queryParamMap.get('page');
|
|
11984
|
+
if (!pageId) {
|
|
11985
|
+
return false;
|
|
11986
|
+
}
|
|
11987
|
+
const entitySource = this.entitySource();
|
|
11988
|
+
if (!entitySource) {
|
|
11989
|
+
return false;
|
|
11990
|
+
}
|
|
11991
|
+
const [, entityName] = entitySource.split('.');
|
|
11992
|
+
return !!entityName && pageId === entityName;
|
|
11993
|
+
}
|
|
11994
|
+
/**
|
|
11995
|
+
* Merges route filters into related-entity toolbar filters (route wins per field).
|
|
11996
|
+
*/
|
|
11997
|
+
mergeToolbarFilters(baseFilters, routeFilters) {
|
|
11998
|
+
const byField = new Map(baseFilters.map((filter) => [filter.field, filter]));
|
|
11999
|
+
for (const filter of routeFilters) {
|
|
12000
|
+
byField.set(filter.field, filter);
|
|
12001
|
+
}
|
|
12002
|
+
return [...byField.values()];
|
|
12003
|
+
}
|
|
12004
|
+
getMergedToolbarFilters() {
|
|
12005
|
+
const base = (this.getValue()?.toolbar?.filters ?? []);
|
|
12006
|
+
if (!this.shouldApplyRouteFilters()) {
|
|
12007
|
+
return base;
|
|
12008
|
+
}
|
|
12009
|
+
const routeFilters = this.parseFiltersFromRoute();
|
|
12010
|
+
return routeFilters.length ? this.mergeToolbarFilters(base, routeFilters) : base;
|
|
12011
|
+
}
|
|
12012
|
+
/**
|
|
12013
|
+
* Applies merged route + parent-scope filters to the widget value and data source.
|
|
12014
|
+
*/
|
|
12015
|
+
applyMergedRouteFiltersToList() {
|
|
12016
|
+
const merged = this.getMergedToolbarFilters();
|
|
12017
|
+
const current = this.getValue();
|
|
12018
|
+
if (!isEqual$1(current?.toolbar?.filters, merged)) {
|
|
12019
|
+
this.setValue({
|
|
12020
|
+
...current,
|
|
12021
|
+
toolbar: { ...(current?.toolbar ?? {}), filters: merged },
|
|
12022
|
+
});
|
|
12023
|
+
}
|
|
12024
|
+
this.pushToolbarFiltersToDataSource();
|
|
12025
|
+
}
|
|
11131
12026
|
/**
|
|
11132
12027
|
* Re-evaluates related-entity list filters from the live dialog form context (e.g. after create saves the main row id).
|
|
11133
12028
|
*/
|
|
@@ -11317,23 +12212,27 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
11317
12212
|
mode: 'view',
|
|
11318
12213
|
defaultValue: this.getValue()?.table,
|
|
11319
12214
|
});
|
|
12215
|
+
const mergedToolbarFilters = this.getMergedToolbarFilters();
|
|
11320
12216
|
this.toolbarNode.set({
|
|
11321
12217
|
type: AXPWidgetsCatalog.listToolbar,
|
|
11322
12218
|
path: `toolbar`,
|
|
11323
12219
|
options: toolbarOptions,
|
|
11324
12220
|
mode: 'view',
|
|
11325
12221
|
defaultValue: {
|
|
11326
|
-
filters:
|
|
12222
|
+
filters: mergedToolbarFilters,
|
|
11327
12223
|
sorts: this.getValue()?.toolbar?.sorts,
|
|
11328
12224
|
columns: this.getValue()?.toolbar?.columns,
|
|
11329
12225
|
},
|
|
11330
12226
|
});
|
|
11331
12227
|
queueMicrotask(() => {
|
|
11332
|
-
|
|
12228
|
+
this.applyMergedRouteFiltersToList();
|
|
11333
12229
|
});
|
|
11334
12230
|
}, 100);
|
|
11335
12231
|
}
|
|
11336
12232
|
async ngAfterViewInit() {
|
|
12233
|
+
this.route.queryParamMap.pipe(takeUntil(this.destroyed)).subscribe(() => {
|
|
12234
|
+
this.applyMergedRouteFiltersToList();
|
|
12235
|
+
});
|
|
11337
12236
|
this.workflow.events$
|
|
11338
12237
|
.pipe(ofType(AXPRefreshEvent))
|
|
11339
12238
|
.pipe(takeUntil(this.destroyed))
|
|
@@ -12742,7 +13641,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
|
|
|
12742
13641
|
[placeholder]="
|
|
12743
13642
|
selectedItemsValue().length
|
|
12744
13643
|
? ''
|
|
12745
|
-
:
|
|
13644
|
+
: placeholderValue() || (('@general:widgets.lookup.placeholder' | translate | async) ?? '')
|
|
12746
13645
|
"
|
|
12747
13646
|
[addOnEnter]="false"
|
|
12748
13647
|
[addOnComma]="false"
|
|
@@ -12781,7 +13680,7 @@ class AXPLookupWidgetTagboxComponent extends LookupWidgetLookBase {
|
|
|
12781
13680
|
<div class="inline-flex items-center gap-1.5 rounded-md px-3 py-1 text-sm surface">
|
|
12782
13681
|
<span>{{ getDisplayRaw(item) | translate | async }}</span>
|
|
12783
13682
|
<button type="button" (click)="tagBoxComponent.removeItem(index)">
|
|
12784
|
-
<ax-icon class="icon icon-close"></ax-icon>
|
|
13683
|
+
<ax-icon class="ax-icon ax-icon-close"></ax-icon>
|
|
12785
13684
|
</button>
|
|
12786
13685
|
</div>
|
|
12787
13686
|
</ng-template>
|
|
@@ -12802,7 +13701,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
12802
13701
|
[placeholder]="
|
|
12803
13702
|
selectedItemsValue().length
|
|
12804
13703
|
? ''
|
|
12805
|
-
:
|
|
13704
|
+
: placeholderValue() || (('@general:widgets.lookup.placeholder' | translate | async) ?? '')
|
|
12806
13705
|
"
|
|
12807
13706
|
[addOnEnter]="false"
|
|
12808
13707
|
[addOnComma]="false"
|
|
@@ -12841,7 +13740,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
12841
13740
|
<div class="inline-flex items-center gap-1.5 rounded-md px-3 py-1 text-sm surface">
|
|
12842
13741
|
<span>{{ getDisplayRaw(item) | translate | async }}</span>
|
|
12843
13742
|
<button type="button" (click)="tagBoxComponent.removeItem(index)">
|
|
12844
|
-
<ax-icon class="icon icon-close"></ax-icon>
|
|
13743
|
+
<ax-icon class="ax-icon ax-icon-close"></ax-icon>
|
|
12845
13744
|
</button>
|
|
12846
13745
|
</div>
|
|
12847
13746
|
</ng-template>
|
|
@@ -13125,6 +14024,14 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
13125
14024
|
}
|
|
13126
14025
|
});
|
|
13127
14026
|
}
|
|
14027
|
+
outputs() {
|
|
14028
|
+
return [
|
|
14029
|
+
{
|
|
14030
|
+
name: 'selectedItems',
|
|
14031
|
+
value: this.selectedItems(),
|
|
14032
|
+
},
|
|
14033
|
+
];
|
|
14034
|
+
}
|
|
13128
14035
|
singleOrMultiple(values) {
|
|
13129
14036
|
return this.multiple() ? values : values[0];
|
|
13130
14037
|
}
|
|
@@ -13139,7 +14046,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
13139
14046
|
this.componentLook()?.focus();
|
|
13140
14047
|
}
|
|
13141
14048
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLookupWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
13142
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLookupWidgetEditComponent, isStandalone: true, selector: "axp-lookup-widget-edit", viewQueries: [{ propertyName: "componentLook", first: true, predicate: LookupWidgetLookBase, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
14049
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLookupWidgetEditComponent, isStandalone: true, selector: "axp-lookup-widget-edit", host: { classAttribute: "w-full" }, viewQueries: [{ propertyName: "componentLook", first: true, predicate: LookupWidgetLookBase, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
13143
14050
|
@if (entityDef()) {
|
|
13144
14051
|
<div class="flex items-center gap-1 w-full">
|
|
13145
14052
|
@switch (look()) {
|
|
@@ -13264,6 +14171,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
13264
14171
|
</div>
|
|
13265
14172
|
}
|
|
13266
14173
|
`,
|
|
14174
|
+
host: {
|
|
14175
|
+
class: 'w-full',
|
|
14176
|
+
},
|
|
13267
14177
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
13268
14178
|
imports: [
|
|
13269
14179
|
CommonModule,
|
|
@@ -14772,7 +15682,7 @@ class AXPMultiSourceSelectorWidgetEditComponent extends AXPValueWidgetComponent
|
|
|
14772
15682
|
<div class="inline-flex items-center gap-1.5 rounded-md px-3 py-1 text-sm surface">
|
|
14773
15683
|
<span>{{ getTagLabel(item) }}</span>
|
|
14774
15684
|
<button type="button" (click)="tagBoxComponent.removeItem(index)">
|
|
14775
|
-
<ax-icon class="icon icon-close"></ax-icon>
|
|
15685
|
+
<ax-icon class="ax-icon ax-icon-close"></ax-icon>
|
|
14776
15686
|
</button>
|
|
14777
15687
|
</div>
|
|
14778
15688
|
</ng-template>
|
|
@@ -14829,7 +15739,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
14829
15739
|
<div class="inline-flex items-center gap-1.5 rounded-md px-3 py-1 text-sm surface">
|
|
14830
15740
|
<span>{{ getTagLabel(item) }}</span>
|
|
14831
15741
|
<button type="button" (click)="tagBoxComponent.removeItem(index)">
|
|
14832
|
-
<ax-icon class="icon icon-close"></ax-icon>
|
|
15742
|
+
<ax-icon class="ax-icon ax-icon-close"></ax-icon>
|
|
14833
15743
|
</button>
|
|
14834
15744
|
</div>
|
|
14835
15745
|
</ng-template>
|
|
@@ -14844,7 +15754,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
14844
15754
|
AXValidationModule,
|
|
14845
15755
|
AXFormModule,
|
|
14846
15756
|
AXTagBoxModule,
|
|
14847
|
-
AXTranslationModule
|
|
15757
|
+
AXTranslationModule,
|
|
14848
15758
|
],
|
|
14849
15759
|
}]
|
|
14850
15760
|
}], propDecorators: { tagBox: [{ type: i0.ViewChild, args: ['tagBoxComponent', { isSignal: true }] }] } });
|
|
@@ -17283,9 +18193,16 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
|
|
|
17283
18193
|
return result;
|
|
17284
18194
|
};
|
|
17285
18195
|
const flatActions = flattenActions(mergedActions);
|
|
17286
|
-
|
|
17287
|
-
|
|
17288
|
-
|
|
18196
|
+
/**
|
|
18197
|
+
* Toolbar keys are `commandKey&action.name`. Several dropdown items can share the same `commandKey`
|
|
18198
|
+
* (e.g. multiple `WorkflowManagement.WorkflowDefinition:Execute` lifecycle templates). Matching only by
|
|
18199
|
+
* prefix makes `.find` return the first sibling — wrong template (e.g. offboarding runs onboarding).
|
|
18200
|
+
*/
|
|
18201
|
+
const action = command.name.includes('&')
|
|
18202
|
+
? flatActions.find((a) => a.name === command.name)
|
|
18203
|
+
: flatActions.find((a) => {
|
|
18204
|
+
return a.name === command.name || a.name === commandName || a.name.split('&')[0] === commandName;
|
|
18205
|
+
});
|
|
17289
18206
|
if (!action) {
|
|
17290
18207
|
console.warn(`Action ${commandName} not found in entity definition`);
|
|
17291
18208
|
return {
|
|
@@ -19241,6 +20158,9 @@ function getDedupKey(op, entityName, init) {
|
|
|
19241
20158
|
if (op === 'getOne' && init?.id !== undefined) {
|
|
19242
20159
|
return `getOne:${entityName}:${String(init.id)}`;
|
|
19243
20160
|
}
|
|
20161
|
+
if (op === 'exists' && init?.id !== undefined) {
|
|
20162
|
+
return `exists:${entityName}:${String(init.id)}`;
|
|
20163
|
+
}
|
|
19244
20164
|
if (op === 'getAll') {
|
|
19245
20165
|
return `getAll:${entityName}`;
|
|
19246
20166
|
}
|
|
@@ -19248,6 +20168,20 @@ function getDedupKey(op, entityName, init) {
|
|
|
19248
20168
|
const r = init.request;
|
|
19249
20169
|
return `query:${entityName}:${r.skip ?? 0}:${r.take ?? 0}:${JSON.stringify(r.filter ?? null)}:${JSON.stringify(r.sort ?? null)}:${JSON.stringify(r.params ?? null)}`;
|
|
19250
20170
|
}
|
|
20171
|
+
if (op === 'count' && init?.request) {
|
|
20172
|
+
const r = init.request;
|
|
20173
|
+
return `count:${entityName}:${JSON.stringify(r.filter ?? null)}:${JSON.stringify(r.sort ?? null)}`;
|
|
20174
|
+
}
|
|
20175
|
+
if (op === 'queryAll' && init?.request) {
|
|
20176
|
+
const r = init.request;
|
|
20177
|
+
return `queryAll:${entityName}:${JSON.stringify(r.filter ?? null)}:${JSON.stringify(r.sort ?? null)}:${JSON.stringify(init.queryAllOptions ?? null)}`;
|
|
20178
|
+
}
|
|
20179
|
+
if (op === 'getMany' && init?.ids) {
|
|
20180
|
+
return `getMany:${entityName}:${init.ids.map(String).join(',')}`;
|
|
20181
|
+
}
|
|
20182
|
+
if (op === 'aggregate' && init?.aggregateRequest) {
|
|
20183
|
+
return `aggregate:${entityName}:${JSON.stringify(init.aggregateRequest)}:${JSON.stringify(init.aggregateOptions ?? null)}`;
|
|
20184
|
+
}
|
|
19251
20185
|
return '';
|
|
19252
20186
|
}
|
|
19253
20187
|
class AXPMiddlewareEntityStorageService extends AXPEntityStorageService {
|
|
@@ -19307,6 +20241,13 @@ class AXPMiddlewareEntityStorageService extends AXPEntityStorageService {
|
|
|
19307
20241
|
insertOne: (name, e) => this.backend.insertOne(name, e),
|
|
19308
20242
|
query: (name, request) => this.backend.query(name, request),
|
|
19309
20243
|
updateOne: (name, id, data) => this.backend.updateOne(name, id, data),
|
|
20244
|
+
deleteOne: (name, id) => this.backend.deleteOne(name, id),
|
|
20245
|
+
count: (name, request) => this.backend.count(name, request),
|
|
20246
|
+
queryAll: (name, request, options) => this.backend.queryAll(name, request, options),
|
|
20247
|
+
getMany: (name, ids) => this.backend.getMany(name, ids),
|
|
20248
|
+
exists: (name, id) => this.backend.exists(name, id),
|
|
20249
|
+
upsertOne: (name, entity, options) => this.backend.upsertOne(name, entity, options),
|
|
20250
|
+
aggregate: (name, request, options) => this.backend.aggregate(name, request, options),
|
|
19310
20251
|
},
|
|
19311
20252
|
...init,
|
|
19312
20253
|
};
|
|
@@ -19378,6 +20319,100 @@ class AXPMiddlewareEntityStorageService extends AXPEntityStorageService {
|
|
|
19378
20319
|
const ctx = this.createCtx('query', entityName, { request });
|
|
19379
20320
|
return this.run(ctx, () => this.backend.query(ctx.entityName, request));
|
|
19380
20321
|
}
|
|
20322
|
+
async count(entityName, request) {
|
|
20323
|
+
const filterSortRequest = { ...request, skip: 0, take: 0 };
|
|
20324
|
+
const key = getDedupKey('count', entityName, { request: filterSortRequest });
|
|
20325
|
+
if (key) {
|
|
20326
|
+
const existing = this.inFlight.get(key);
|
|
20327
|
+
if (existing) {
|
|
20328
|
+
return existing;
|
|
20329
|
+
}
|
|
20330
|
+
const promise = this.runWithDedup(key, () => {
|
|
20331
|
+
const ctx = this.createCtx('count', entityName, { request: filterSortRequest });
|
|
20332
|
+
return this.run(ctx, () => this.backend.count(ctx.entityName, request));
|
|
20333
|
+
});
|
|
20334
|
+
this.inFlight.set(key, promise);
|
|
20335
|
+
return promise;
|
|
20336
|
+
}
|
|
20337
|
+
const ctx = this.createCtx('count', entityName, { request: filterSortRequest });
|
|
20338
|
+
return this.run(ctx, () => this.backend.count(ctx.entityName, request));
|
|
20339
|
+
}
|
|
20340
|
+
async queryAll(entityName, request, options) {
|
|
20341
|
+
const filterSortRequest = { ...request, skip: 0, take: 0 };
|
|
20342
|
+
const key = getDedupKey('queryAll', entityName, { request: filterSortRequest, queryAllOptions: options });
|
|
20343
|
+
if (key) {
|
|
20344
|
+
const existing = this.inFlight.get(key);
|
|
20345
|
+
if (existing) {
|
|
20346
|
+
return existing;
|
|
20347
|
+
}
|
|
20348
|
+
const promise = this.runWithDedup(key, () => {
|
|
20349
|
+
const ctx = this.createCtx('queryAll', entityName, { request: filterSortRequest });
|
|
20350
|
+
return this.run(ctx, () => this.backend.queryAll(ctx.entityName, request, options));
|
|
20351
|
+
});
|
|
20352
|
+
this.inFlight.set(key, promise);
|
|
20353
|
+
return promise;
|
|
20354
|
+
}
|
|
20355
|
+
const ctx = this.createCtx('queryAll', entityName, { request: filterSortRequest });
|
|
20356
|
+
return this.run(ctx, () => this.backend.queryAll(ctx.entityName, request, options));
|
|
20357
|
+
}
|
|
20358
|
+
async getMany(entityName, ids) {
|
|
20359
|
+
const key = getDedupKey('getMany', entityName, { ids: ids });
|
|
20360
|
+
if (key) {
|
|
20361
|
+
const existing = this.inFlight.get(key);
|
|
20362
|
+
if (existing) {
|
|
20363
|
+
return existing;
|
|
20364
|
+
}
|
|
20365
|
+
const promise = this.runWithDedup(key, () => {
|
|
20366
|
+
const ctx = this.createCtx('getMany', entityName);
|
|
20367
|
+
return this.run(ctx, () => this.backend.getMany(ctx.entityName, ids));
|
|
20368
|
+
});
|
|
20369
|
+
this.inFlight.set(key, promise);
|
|
20370
|
+
return promise;
|
|
20371
|
+
}
|
|
20372
|
+
const ctx = this.createCtx('getMany', entityName);
|
|
20373
|
+
return this.run(ctx, () => this.backend.getMany(ctx.entityName, ids));
|
|
20374
|
+
}
|
|
20375
|
+
async exists(entityName, id) {
|
|
20376
|
+
const key = getDedupKey('exists', entityName, { id });
|
|
20377
|
+
if (key) {
|
|
20378
|
+
const existing = this.inFlight.get(key);
|
|
20379
|
+
if (existing) {
|
|
20380
|
+
return existing;
|
|
20381
|
+
}
|
|
20382
|
+
const promise = this.runWithDedup(key, () => {
|
|
20383
|
+
const ctx = this.createCtx('exists', entityName, { id });
|
|
20384
|
+
return this.run(ctx, () => this.backend.exists(ctx.entityName, id));
|
|
20385
|
+
});
|
|
20386
|
+
this.inFlight.set(key, promise);
|
|
20387
|
+
return promise;
|
|
20388
|
+
}
|
|
20389
|
+
const ctx = this.createCtx('exists', entityName, { id });
|
|
20390
|
+
return this.run(ctx, () => this.backend.exists(ctx.entityName, id));
|
|
20391
|
+
}
|
|
20392
|
+
async upsertOne(entityName, entity, options) {
|
|
20393
|
+
const ctx = this.createCtx('upsertOne', entityName, { data: entity });
|
|
20394
|
+
ctx.locals.set('upsertOptions', options);
|
|
20395
|
+
return this.run(ctx, () => this.backend.upsertOne(ctx.entityName, entity, options));
|
|
20396
|
+
}
|
|
20397
|
+
async aggregate(entityName, request, options) {
|
|
20398
|
+
const key = getDedupKey('aggregate', entityName, { aggregateRequest: request, aggregateOptions: options });
|
|
20399
|
+
if (key) {
|
|
20400
|
+
const existing = this.inFlight.get(key);
|
|
20401
|
+
if (existing) {
|
|
20402
|
+
return existing;
|
|
20403
|
+
}
|
|
20404
|
+
const promise = this.runWithDedup(key, () => {
|
|
20405
|
+
const ctx = this.createCtx('aggregate', entityName);
|
|
20406
|
+
ctx.locals.set('aggregateRequest', request);
|
|
20407
|
+
ctx.locals.set('aggregateOptions', options);
|
|
20408
|
+
return this.run(ctx, () => this.backend.aggregate(ctx.entityName, request, options));
|
|
20409
|
+
});
|
|
20410
|
+
this.inFlight.set(key, promise);
|
|
20411
|
+
return promise;
|
|
20412
|
+
}
|
|
20413
|
+
const ctx = this.createCtx('aggregate', entityName);
|
|
20414
|
+
return this.run(ctx, () => this.backend.aggregate(ctx.entityName, request, options));
|
|
20415
|
+
}
|
|
19381
20416
|
async runWithDedup(key, fn) {
|
|
19382
20417
|
try {
|
|
19383
20418
|
return await fn();
|
|
@@ -20338,5 +21373,5 @@ var getEntityDetails_query = /*#__PURE__*/Object.freeze({
|
|
|
20338
21373
|
* Generated bundle index. Do not edit.
|
|
20339
21374
|
*/
|
|
20340
21375
|
|
|
20341
|
-
export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCategoryTreeService, AXPCreateEntityCommand, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntitiesListDataSourceDefinition, AXPEntityApplyUpdatesAction, AXPEntityCategoryTreeSelectorComponent, AXPEntityCategoryWidget, AXPEntityCategoryWidgetColumnComponent, AXPEntityCategoryWidgetEditComponent, AXPEntityCategoryWidgetViewComponent, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDataSelectorService, AXPEntityDefinitionProviderWidget, AXPEntityDefinitionProviderWidgetEditComponent, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailPopoverComponent, AXPEntityDetailPopoverService, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityEventsKeys, AXPEntityFormBuilderService, AXPEntityListTableService, AXPEntityListToolbarService, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityListWidget, AXPEntityListWidgetViewComponent, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityPreloadFiltersContainerComponent, AXPEntityPreloadFiltersViewModel, AXPEntityPreloadFiltersViewModelResolver, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPEntityUpdateViewSectionViewModel, AXPGetEntityDetailsQuery, AXPLayoutOrderingConfigService, AXPLookupWidget, AXPLookupWidgetColumnComponent, AXPLookupWidgetEditComponent, AXPLookupWidgetViewComponent, AXPMiddlewareAbortError, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPMultiSourceDefinitionProviderContext, AXPMultiSourceDefinitionProviderService, AXPMultiSourceFederatedSearchService, AXPMultiSourceSelectorComponent, AXPMultiSourceSelectorService, AXPMultiSourceSelectorWidget, AXPMultiSourceSelectorWidgetColumnComponent, AXPMultiSourceSelectorWidgetEditComponent, AXPMultiSourceSelectorWidgetViewComponent, AXPMultiSourceType, AXPOpenEntityDetailsCommand, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPRelatedColumnEnrichmentService, AXPRelatedColumnMetadataResolver, AXPSelectorStructureWidget, AXPSelectorStructureWidgetColumnComponent, AXPSelectorStructureWidgetEditComponent, AXPSelectorStructureWidgetViewComponent, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXPTruncatedBreadcrumbComponent, AXPUpdateEntityCommand, AXPViewEntityDetailsCommand, AXP_CATEGORY_TREE_ROOT_TITLE_I18N_KEY, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, AXP_MULTI_SOURCE_DEFINITION_PROVIDER, DEFAULT_COLUMN_ORDER, DEFAULT_PAIR_SPAN_RULES, DEFAULT_PROPERTY_ORDER, DEFAULT_SECTION_ORDER, EntityBuilder, EntityDataAccessor, actionExists, axpCreateEntityAiToolInputDefaults, axpCreateEntityCommandDefinition, cloneLayoutArrays, collectNestedCreateHiddenProperties, columnOrderingMiddleware, columnOrderingMiddlewareProvider, columnWidthMiddleware, columnWidthMiddlewareProvider, createColumnOrderingMiddlewareProvider, createLayoutOrderingMiddlewareProvider, createModifierContext, defaultMultiLanguageMiddleware, defaultMultiLanguageMiddlewareProvider, detectEntityChanges, ensureLayoutPropertyView, ensureLayoutSection, ensureListActions, entityDetailsCreateActions, entityDetailsCreateActionsDeferredParent, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsNewEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterEditAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware, getMasterInterfacePropertySortKey, isAXPMiddlewareAbortError, layoutOrderingMiddlewareFactory, layoutOrderingMiddlewareProvider, mergeForeignKeyFieldIntoCreateActions, provideEntity, resolveEntityPluginDetailPageOrder, searchResultDescriptionMiddleware, searchResultDescriptionMiddlewareProvider };
|
|
21376
|
+
export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCategoryTreeService, AXPCreateEntityCommand, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntitiesListDataSourceDefinition, AXPEntityApplyUpdatesAction, AXPEntityCategoryTreeSelectorComponent, AXPEntityCategoryWidget, AXPEntityCategoryWidgetColumnComponent, AXPEntityCategoryWidgetEditComponent, AXPEntityCategoryWidgetViewComponent, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDataSelectorService, AXPEntityDefinitionProviderWidget, AXPEntityDefinitionProviderWidgetEditComponent, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailPopoverComponent, AXPEntityDetailPopoverService, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityEventsKeys, AXPEntityFormBuilderService, AXPEntityListPersistenceModeDefault, AXPEntityListTableService, AXPEntityListToolbarService, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityListWidget, AXPEntityListWidgetViewComponent, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityPreloadFiltersContainerComponent, AXPEntityPreloadFiltersViewModel, AXPEntityPreloadFiltersViewModelResolver, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPEntityUpdateViewSectionViewModel, AXPGetEntityDetailsQuery, AXPLayoutOrderingConfigService, AXPLookupWidget, AXPLookupWidgetColumnComponent, AXPLookupWidgetEditComponent, AXPLookupWidgetViewComponent, AXPMiddlewareAbortError, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPMultiSourceDefinitionProviderContext, AXPMultiSourceDefinitionProviderService, AXPMultiSourceFederatedSearchService, AXPMultiSourceSelectorComponent, AXPMultiSourceSelectorService, AXPMultiSourceSelectorWidget, AXPMultiSourceSelectorWidgetColumnComponent, AXPMultiSourceSelectorWidgetEditComponent, AXPMultiSourceSelectorWidgetViewComponent, AXPMultiSourceType, AXPOpenEntityDetailsCommand, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPRelatedColumnEnrichmentService, AXPRelatedColumnMetadataResolver, AXPSelectorStructureWidget, AXPSelectorStructureWidgetColumnComponent, AXPSelectorStructureWidgetEditComponent, AXPSelectorStructureWidgetViewComponent, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXPTruncatedBreadcrumbComponent, AXPUpdateEntityCommand, AXPViewEntityDetailsCommand, AXP_CATEGORY_TREE_ROOT_TITLE_I18N_KEY, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, AXP_MULTI_SOURCE_DEFINITION_PROVIDER, DEFAULT_COLUMN_ORDER, DEFAULT_PAIR_SPAN_RULES, DEFAULT_PROPERTY_ORDER, DEFAULT_SECTION_ORDER, ENTITY_LIST_ROUTE_CONTEXT_SESSION_KEY, EntityBuilder, EntityDataAccessor, actionExists, applyDataSourcePagingWithoutLoad, axpCreateEntityAiToolInputDefaults, axpCreateEntityCommandDefinition, canPersistEntityListState, cloneLayoutArrays, collectEntityQuickSearchFieldPaths, collectNestedCreateHiddenProperties, collectNestedFieldPathsFromEntityColumns, collectQuickSearchPathsFromSingleEntityDefinition, columnOrderingMiddleware, columnOrderingMiddlewareProvider, columnWidthMiddleware, columnWidthMiddlewareProvider, computeEntityAggregates, createColumnOrderingMiddlewareProvider, createLayoutOrderingMiddlewareProvider, createModifierContext, defaultMultiLanguageMiddleware, defaultMultiLanguageMiddlewareProvider, detectEntityChanges, ensureLayoutPropertyView, ensureLayoutSection, ensureListActions, entityDetailsCreateActions, entityDetailsCreateActionsDeferredParent, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsNewEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterEditAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware, filterSortEntityRows, findEntityListRowDataInTree, getDataSourcePageIndex, getEntityListRowId, getMasterInterfacePropertySortKey, isAXPMiddlewareAbortError, isCategoryEntity, isCategoryFilter, layoutOrderingMiddlewareFactory, layoutOrderingMiddlewareProvider, mergeForeignKeyFieldIntoCreateActions, normalizeEntityListPersistenceMode, normalizeListPaging, provideEntity, resolveEntityPluginDetailPageOrder, restoreEntityListExpandedRows, runEntityQuery, searchResultDescriptionMiddleware, searchResultDescriptionMiddlewareProvider, shouldLoadEntityListStateFromStorage, shouldResetEntityListStateOnRouteEntry };
|
|
20342
21377
|
//# sourceMappingURL=acorex-platform-layout-entity.mjs.map
|