@acorex/platform 20.8.18 → 20.8.21
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/common/index.d.ts +71 -5
- package/fesm2022/acorex-platform-common.mjs +248 -59
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +28 -18
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +131 -35
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +7 -3
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +87 -16
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-default-entity-master-list-view.component-D2CtNrSn.mjs → acorex-platform-themes-default-entity-master-list-view.component-DnFEQS-L.mjs} +48 -15
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DnFEQS-L.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-error-404.component-CgVwJxdC.mjs +42 -0
- package/fesm2022/acorex-platform-themes-default-error-404.component-CgVwJxdC.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +17 -7
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/layout/components/index.d.ts +2 -1
- package/layout/entity/index.d.ts +22 -3
- package/layout/views/index.d.ts +2 -1
- package/layout/widget-core/index.d.ts +12 -3
- package/package.json +8 -8
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-D2CtNrSn.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-404.component-DVF9soT5.mjs +0 -25
- package/fesm2022/acorex-platform-themes-default-error-404.component-DVF9soT5.mjs.map +0 -1
|
@@ -2,14 +2,14 @@ import { AXToastService } from '@acorex/components/toast';
|
|
|
2
2
|
import * as i6 from '@acorex/core/translation';
|
|
3
3
|
import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
|
|
4
4
|
import * as i4$1 from '@acorex/platform/common';
|
|
5
|
-
import { AXPSettingsService, AXPCommonSettings, AXPFilterOperatorMiddlewareService, AXPEntityCommandScope, getEntityInfo, AXPRefreshEvent, AXPReloadEvent, AXPEntityQueryType, AXPCleanNestedFilters, AXPWorkflowNavigateAction, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER } from '@acorex/platform/common';
|
|
5
|
+
import { AXPNotFoundError, AXPSettingsService, AXPCommonSettings, AXPFilterOperatorMiddlewareService, AXPEntityCommandScope, getEntityInfo, AXPRefreshEvent, AXPReloadEvent, axpRedirectToNotFound, axpIsEntityRecordNotFound, AXPEntityQueryType, AXPCleanNestedFilters, AXPWorkflowNavigateAction, AXP_NOT_FOUND_ROUTE, AXP_PROTECTED_ROUTE_GUARDS, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER } from '@acorex/platform/common';
|
|
6
6
|
import * as i0 from '@angular/core';
|
|
7
7
|
import { InjectionToken, inject, Injector, runInInjectionContext, Injectable, input, viewChild, signal, ElementRef, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent, computed, ChangeDetectorRef, effect, Input, afterNextRender, untracked, ViewEncapsulation, viewChildren, linkedSignal, HostBinding, output, NgModule } from '@angular/core';
|
|
8
8
|
import { Subject, takeUntil } from 'rxjs';
|
|
9
9
|
import { AXPLayoutBuilderService } from '@acorex/platform/layout/builder';
|
|
10
10
|
import { AXPDeviceService, AXPBroadcastEventService, applyFilterArray, applySortArray, resolveActionLook, AXPExpressionEvaluatorService, AXPDistributedEventListenerService, AXPPlatformScope, AXPColumnWidthService, AXHighlightService, extractValue, setSmart, getChangedPaths, defaultColumnWidthProvider, AXP_COLUMN_WIDTH_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXPSystemActionType } from '@acorex/platform/core';
|
|
11
11
|
import { merge, castArray, cloneDeep, get, set, orderBy, isNil, isEmpty, isEqual } from 'lodash-es';
|
|
12
|
-
import { AXPSessionService
|
|
12
|
+
import { AXPSessionService } from '@acorex/platform/auth';
|
|
13
13
|
import { Router, ActivatedRoute, RouterModule, ROUTES } from '@angular/router';
|
|
14
14
|
import * as i3 from '@acorex/components/button';
|
|
15
15
|
import { AXButtonModule } from '@acorex/components/button';
|
|
@@ -604,7 +604,7 @@ class AXPEntityDefinitionRegistryService {
|
|
|
604
604
|
throw error; // Rethrow to allow error handling by caller
|
|
605
605
|
}
|
|
606
606
|
if (!config) {
|
|
607
|
-
throw new
|
|
607
|
+
throw new AXPNotFoundError(`Invalid entity name: ${key}`);
|
|
608
608
|
}
|
|
609
609
|
}
|
|
610
610
|
return config;
|
|
@@ -3948,7 +3948,7 @@ class AXPEntityMasterListViewModel {
|
|
|
3948
3948
|
this.events$.next({ action: 'refresh' });
|
|
3949
3949
|
}
|
|
3950
3950
|
});
|
|
3951
|
-
this.sortedFields.set(
|
|
3951
|
+
this.sortedFields.set([]);
|
|
3952
3952
|
void this.syncShowRowIndexColumnSetting();
|
|
3953
3953
|
this.settings.onLoaded.pipe(takeUntil(this.destroyed)).subscribe(() => {
|
|
3954
3954
|
void this.syncShowRowIndexColumnSetting();
|
|
@@ -4051,10 +4051,8 @@ class AXPEntityMasterListViewModel {
|
|
|
4051
4051
|
.sort((a, b) => columns.findIndex((col) => col.name === (a.column?.options?.dataPath ?? a.name)) -
|
|
4052
4052
|
columns.findIndex((col) => col.name === (b.column?.options?.dataPath ?? b.name))));
|
|
4053
4053
|
}
|
|
4054
|
-
if (Array.isArray(sorts)) {
|
|
4055
|
-
|
|
4056
|
-
const sortsMap = new Map(sorts.map((s) => [s.name, s.dir]));
|
|
4057
|
-
this.sortedFields.update((prev) => prev.map((sf) => ({ ...sf, dir: sortsMap.get(sf.name) || sf.dir })));
|
|
4054
|
+
if (Array.isArray(sorts) && sorts.length) {
|
|
4055
|
+
this.setActiveSortsFromQueries(sorts);
|
|
4058
4056
|
}
|
|
4059
4057
|
// Don't override filters if they came from queryParams
|
|
4060
4058
|
if (Array.isArray(filters) && !this.hasQueryParamsFilters) {
|
|
@@ -4569,18 +4567,80 @@ class AXPEntityMasterListViewModel {
|
|
|
4569
4567
|
resetSorts() {
|
|
4570
4568
|
this.applyViewSorts();
|
|
4571
4569
|
}
|
|
4570
|
+
/**
|
|
4571
|
+
* Applies active sorts in the given order (click order, saved settings, or view defaults).
|
|
4572
|
+
*/
|
|
4573
|
+
setActiveSortsFromQueries(sorts) {
|
|
4574
|
+
const sortableByName = new Map(this.sortableFields().map((f) => [f.name, f]));
|
|
4575
|
+
this.sortedFields.set(sorts
|
|
4576
|
+
.filter((s) => s.dir && sortableByName.has(s.name))
|
|
4577
|
+
.map((s) => ({
|
|
4578
|
+
name: s.name,
|
|
4579
|
+
title: sortableByName.get(s.name).title,
|
|
4580
|
+
dir: s.dir,
|
|
4581
|
+
})));
|
|
4582
|
+
}
|
|
4572
4583
|
applyViewSorts() {
|
|
4573
|
-
const viewSorts = this.view().sorts;
|
|
4574
|
-
this.
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
+
const viewSorts = this.view().sorts ?? [];
|
|
4585
|
+
this.setActiveSortsFromQueries(viewSorts);
|
|
4586
|
+
}
|
|
4587
|
+
/**
|
|
4588
|
+
* Active sort direction for a column (synced with toolbar sort UI and dataSource).
|
|
4589
|
+
*/
|
|
4590
|
+
getColumnSortDirection(columnName) {
|
|
4591
|
+
const dir = this.sortedFields().find((sf) => sf.name === columnName)?.dir;
|
|
4592
|
+
return dir === 'asc' || dir === 'desc' ? dir : undefined;
|
|
4593
|
+
}
|
|
4594
|
+
/**
|
|
4595
|
+
* 1-based priority index when multiple columns are sorted (Ctrl+click order).
|
|
4596
|
+
*/
|
|
4597
|
+
getColumnSortIndex(columnName) {
|
|
4598
|
+
const index = this.sortedFields().findIndex((sf) => sf.name === columnName);
|
|
4599
|
+
return index >= 0 ? index + 1 : undefined;
|
|
4600
|
+
}
|
|
4601
|
+
/** True when active sorts still match the current view defaults (not yet customized). */
|
|
4602
|
+
isViewDefaultSorts(activeSorts) {
|
|
4603
|
+
const viewSorts = this.view().sorts ?? [];
|
|
4604
|
+
if (activeSorts.length !== viewSorts.length) {
|
|
4605
|
+
return false;
|
|
4606
|
+
}
|
|
4607
|
+
return activeSorts.every((s, i) => s.name === viewSorts[i]?.name && s.dir === viewSorts[i]?.dir);
|
|
4608
|
+
}
|
|
4609
|
+
/**
|
|
4610
|
+
* Toggles column sort (asc → desc → none). Without Ctrl, only one column is active.
|
|
4611
|
+
* With Ctrl/Cmd, multiple columns are sorted in click order (first clicked = primary).
|
|
4612
|
+
*/
|
|
4613
|
+
async toggleColumnSort(columnName, multiSort) {
|
|
4614
|
+
const fieldMeta = this.sortableFields().find((f) => f.name === columnName);
|
|
4615
|
+
if (!fieldMeta) {
|
|
4616
|
+
return;
|
|
4617
|
+
}
|
|
4618
|
+
let activeSorts = [...this.sortedFields()];
|
|
4619
|
+
const index = activeSorts.findIndex((sf) => sf.name === columnName);
|
|
4620
|
+
const currentDir = index >= 0 ? activeSorts[index].dir : undefined;
|
|
4621
|
+
const newDir = currentDir === 'asc' ? 'desc' : currentDir === 'desc' ? undefined : 'asc';
|
|
4622
|
+
if (!multiSort) {
|
|
4623
|
+
activeSorts = newDir ? [{ name: columnName, title: fieldMeta.title, dir: newDir }] : [];
|
|
4624
|
+
}
|
|
4625
|
+
else if (index >= 0) {
|
|
4626
|
+
const [item] = activeSorts.splice(index, 1);
|
|
4627
|
+
if (newDir) {
|
|
4628
|
+
// Re-click moves column to end so click order can override view/default order.
|
|
4629
|
+
activeSorts.push({ ...item, title: fieldMeta.title, dir: newDir });
|
|
4630
|
+
}
|
|
4631
|
+
}
|
|
4632
|
+
else if (newDir) {
|
|
4633
|
+
if (this.isViewDefaultSorts(activeSorts)) {
|
|
4634
|
+
activeSorts = [{ name: columnName, title: fieldMeta.title, dir: newDir }];
|
|
4635
|
+
}
|
|
4636
|
+
else {
|
|
4637
|
+
activeSorts.push({ name: columnName, title: fieldMeta.title, dir: newDir });
|
|
4638
|
+
}
|
|
4639
|
+
}
|
|
4640
|
+
this.sortedFields.set(activeSorts);
|
|
4641
|
+
this.lastAppliedSortKey = null;
|
|
4642
|
+
await this.saveSettings('sorts', activeSorts.map((s) => ({ name: s.name, dir: s.dir })));
|
|
4643
|
+
await this.applyFilterAndSort();
|
|
4584
4644
|
}
|
|
4585
4645
|
//****************** Commands ******************//
|
|
4586
4646
|
async executeCommand(commandName, data = null) {
|
|
@@ -4718,20 +4778,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
4718
4778
|
type: Injectable,
|
|
4719
4779
|
args: [{ providedIn: 'root' }]
|
|
4720
4780
|
}] });
|
|
4721
|
-
const AXPEntityListViewModelResolver = async (route, state, service = inject(AXPEntityListViewModelFactory)) => {
|
|
4781
|
+
const AXPEntityListViewModelResolver = async (route, state, service = inject(AXPEntityListViewModelFactory), router = inject(Router)) => {
|
|
4722
4782
|
const moduleName = route.parent?.paramMap.get('module');
|
|
4723
4783
|
const entityName = route.paramMap.get('entity');
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4784
|
+
try {
|
|
4785
|
+
const vm = await service.create(moduleName, entityName);
|
|
4786
|
+
// Check if filters are provided in query params
|
|
4787
|
+
const filtersParam = route.queryParamMap.get('filters');
|
|
4788
|
+
if (filtersParam) {
|
|
4789
|
+
const applied = vm.applyFiltersFromQueryParams(filtersParam);
|
|
4790
|
+
if (applied) {
|
|
4791
|
+
// Trigger filter and sort application
|
|
4792
|
+
await vm.applyFilterAndSort();
|
|
4793
|
+
}
|
|
4732
4794
|
}
|
|
4795
|
+
return vm;
|
|
4796
|
+
}
|
|
4797
|
+
catch (error) {
|
|
4798
|
+
if (error instanceof AXPNotFoundError) {
|
|
4799
|
+
return axpRedirectToNotFound(router);
|
|
4800
|
+
}
|
|
4801
|
+
throw error;
|
|
4733
4802
|
}
|
|
4734
|
-
return vm;
|
|
4735
4803
|
};
|
|
4736
4804
|
|
|
4737
4805
|
const AXPEntityDeletedEvent = createWorkFlowEvent('[Entity] Deleted');
|
|
@@ -5523,10 +5591,19 @@ class AXPEntityPreloadFiltersViewModel {
|
|
|
5523
5591
|
const AXPEntityPreloadFiltersViewModelResolver = async (route, state) => {
|
|
5524
5592
|
const injector = inject(Injector);
|
|
5525
5593
|
const entityRegistry = inject(AXPEntityDefinitionRegistryService);
|
|
5594
|
+
const router = inject(Router);
|
|
5526
5595
|
const moduleName = route.parent?.paramMap.get('module');
|
|
5527
5596
|
const entityName = route.paramMap.get('entity');
|
|
5528
|
-
|
|
5529
|
-
|
|
5597
|
+
try {
|
|
5598
|
+
const entity = await entityRegistry.resolve(moduleName, entityName);
|
|
5599
|
+
return new AXPEntityPreloadFiltersViewModel(injector, entity);
|
|
5600
|
+
}
|
|
5601
|
+
catch (error) {
|
|
5602
|
+
if (error instanceof AXPNotFoundError) {
|
|
5603
|
+
return axpRedirectToNotFound(router);
|
|
5604
|
+
}
|
|
5605
|
+
throw error;
|
|
5606
|
+
}
|
|
5530
5607
|
};
|
|
5531
5608
|
//#endregion
|
|
5532
5609
|
|
|
@@ -7101,9 +7178,12 @@ class AXPLayoutAdapterFactory {
|
|
|
7101
7178
|
async createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies) {
|
|
7102
7179
|
const entity = await entityResolver.resolve(moduleName, entityName);
|
|
7103
7180
|
if (!entity) {
|
|
7104
|
-
throw new
|
|
7181
|
+
throw new AXPNotFoundError(`Entity ${moduleName}.${entityName} not found`);
|
|
7105
7182
|
}
|
|
7106
7183
|
const rootContext = await this.loadRootContext(entity, id);
|
|
7184
|
+
if (axpIsEntityRecordNotFound(rootContext)) {
|
|
7185
|
+
throw new AXPNotFoundError(`Entity record ${moduleName}.${entityName}#${id} not found`);
|
|
7186
|
+
}
|
|
7107
7187
|
// Evaluate hidden expressions for related entities once, reuse across building and composing
|
|
7108
7188
|
const evaluatedRelatedEntities = await this.evaluateRelatedEntitiesHidden(entity?.relatedEntities ?? [], rootContext, dependencies);
|
|
7109
7189
|
// Build main and related pages using evaluated related entities
|
|
@@ -7274,7 +7354,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
7274
7354
|
}]
|
|
7275
7355
|
}], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }, { type: AXPMainEntityContentBuilder }, { type: AXPLayoutAdapterBuilder }, { type: i4$1.AXPFilterOperatorMiddlewareService }] });
|
|
7276
7356
|
|
|
7277
|
-
const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver = inject(AXPEntityDefinitionRegistryService), expressionEvaluator = inject(AXPExpressionEvaluatorService), session = inject(AXPSessionService), formatService = inject(AXFormatService), workflowService = inject(AXPWorkflowService), commandService = inject(AXPCommandService), layoutAdapterFactory = inject(AXPLayoutAdapterFactory)) => {
|
|
7357
|
+
const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver = inject(AXPEntityDefinitionRegistryService), expressionEvaluator = inject(AXPExpressionEvaluatorService), session = inject(AXPSessionService), formatService = inject(AXFormatService), workflowService = inject(AXPWorkflowService), commandService = inject(AXPCommandService), layoutAdapterFactory = inject(AXPLayoutAdapterFactory), router = inject(Router)) => {
|
|
7278
7358
|
const moduleName = route.parent?.paramMap.get('module');
|
|
7279
7359
|
const entityName = route.paramMap.get('entity');
|
|
7280
7360
|
const id = route.paramMap.get('id');
|
|
@@ -7286,7 +7366,15 @@ const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver =
|
|
|
7286
7366
|
workflowService,
|
|
7287
7367
|
commandService,
|
|
7288
7368
|
};
|
|
7289
|
-
|
|
7369
|
+
try {
|
|
7370
|
+
return await layoutAdapterFactory.createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies);
|
|
7371
|
+
}
|
|
7372
|
+
catch (error) {
|
|
7373
|
+
if (error instanceof AXPNotFoundError) {
|
|
7374
|
+
return axpRedirectToNotFound(router);
|
|
7375
|
+
}
|
|
7376
|
+
throw error;
|
|
7377
|
+
}
|
|
7290
7378
|
};
|
|
7291
7379
|
|
|
7292
7380
|
class AXPEntityPreloadFilterGuard {
|
|
@@ -16155,7 +16243,7 @@ function routesFacory() {
|
|
|
16155
16243
|
loadComponent: () => {
|
|
16156
16244
|
return config.viewers.root();
|
|
16157
16245
|
},
|
|
16158
|
-
canActivate: [
|
|
16246
|
+
canActivate: [...AXP_PROTECTED_ROUTE_GUARDS],
|
|
16159
16247
|
children: [
|
|
16160
16248
|
{
|
|
16161
16249
|
path: ':module',
|
|
@@ -16211,8 +16299,16 @@ function routesFacory() {
|
|
|
16211
16299
|
redirectTo: ':entity/list',
|
|
16212
16300
|
pathMatch: 'full',
|
|
16213
16301
|
},
|
|
16302
|
+
{
|
|
16303
|
+
path: '**',
|
|
16304
|
+
redirectTo: AXP_NOT_FOUND_ROUTE,
|
|
16305
|
+
},
|
|
16214
16306
|
],
|
|
16215
16307
|
},
|
|
16308
|
+
{
|
|
16309
|
+
path: '**',
|
|
16310
|
+
redirectTo: AXP_NOT_FOUND_ROUTE,
|
|
16311
|
+
},
|
|
16216
16312
|
],
|
|
16217
16313
|
},
|
|
16218
16314
|
];
|