@acorex/platform 20.9.1 → 20.9.2
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-layout-builder.mjs +6 -3
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +143 -18
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +20 -0
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs +23 -4
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-default.mjs +2 -2
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/package.json +1 -1
- package/types/acorex-platform-layout-builder.d.ts +1 -1
- package/types/acorex-platform-layout-entity.d.ts +3 -1
- package/types/acorex-platform-layout-widgets.d.ts +7 -1
|
@@ -10,11 +10,11 @@ import * as i1$3 from '@acorex/platform/workflow';
|
|
|
10
10
|
import { AXPWorkflowEventService, AXPWorkflowService, ofType, createWorkFlowEvent, AXPWorkflowAction, AXPWorkflowModule } from '@acorex/platform/workflow';
|
|
11
11
|
import * as i0 from '@angular/core';
|
|
12
12
|
import { InjectionToken, inject, Injector, runInInjectionContext, Injectable, ChangeDetectorRef, input, signal, computed, effect, ChangeDetectionStrategy, Component, ElementRef, NgModule, viewChild, Input, afterNextRender, untracked, ViewEncapsulation, viewChildren, linkedSignal, HostBinding, output, EnvironmentInjector, makeEnvironmentProviders } from '@angular/core';
|
|
13
|
-
import { cloneDeep, merge, get, castArray, set, orderBy, isNil, isEmpty, isEqual, isObjectLike, isArray, has, isString } from 'lodash-es';
|
|
13
|
+
import { cloneDeep, merge, get, castArray, set, orderBy, defaultTo, isNil, isEmpty, isEqual, isObjectLike, isArray, has, isString } from 'lodash-es';
|
|
14
14
|
import { Subject, filter, takeUntil } from 'rxjs';
|
|
15
15
|
import { AXPWidgetsCatalog, resolveActionLook, AXPPlatformScope, extractValue, setSmart, getChangedPaths, isSelectionValueEqual, AXPDataGenerator, AXPSystemActionType } from '@acorex/platform/contracts';
|
|
16
16
|
import { AXPLayoutBuilderService, LayoutBuilderModule } from '@acorex/platform/layout/builder';
|
|
17
|
-
import { AXPDeviceService, AXPExpressionEvaluatorService, AXPContextEvalFactory, AXPBroadcastEventService, applyFilterArray, applySortArray, AXPDistributedEventListenerService, AXHighlightService, AXPDebugService, AXPContextStore, FORM_DIRTY_TRACE_NS, objectKeyValueTransforms, setupPopupFooterKeyboardShortcuts, AXPHookService, AXPComponentSlotModule,
|
|
17
|
+
import { AXPDeviceService, AXPExpressionEvaluatorService, AXPContextEvalFactory, AXPBroadcastEventService, applyFilterArray, applySortArray, AXPDistributedEventListenerService, AXHighlightService, AXPColumnWidthService, AXPDebugService, AXPContextStore, FORM_DIRTY_TRACE_NS, objectKeyValueTransforms, setupPopupFooterKeyboardShortcuts, AXPHookService, AXPComponentSlotModule, AXPModuleManifestRegistry, defaultColumnWidthProvider, AXP_COLUMN_WIDTH_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXPModuleManifestsDataSourceDefinition } from '@acorex/platform/core';
|
|
18
18
|
import { AXPSessionService, AXPPermissionDefinitionsDataSourceDefinition } from '@acorex/platform/auth';
|
|
19
19
|
import { Router, NavigationStart, ActivatedRoute, RouterModule, ROUTES } from '@angular/router';
|
|
20
20
|
import { defineCommand, AXP_COMMAND_DEFINITION_CATEGORY_ENTITY } from '@acorex/platform/runtime-contracts';
|
|
@@ -1385,9 +1385,6 @@ class PropertyFilter {
|
|
|
1385
1385
|
});
|
|
1386
1386
|
}
|
|
1387
1387
|
wizardExtraSteps.sort((a, b) => a.order - b.order);
|
|
1388
|
-
const pageWizardWidgetNames = wizardExtraSteps
|
|
1389
|
-
.filter((s) => s.kind === 'page')
|
|
1390
|
-
.map((s) => buildPageComponentWidgetName(s.page));
|
|
1391
1388
|
const prebuiltRelatedListConfigs = useFormWizard
|
|
1392
1389
|
? await Promise.all(wizardExtraSteps
|
|
1393
1390
|
.filter((s) => s.kind === 'related-list')
|
|
@@ -1485,7 +1482,7 @@ class PropertyFilter {
|
|
|
1485
1482
|
.submit(this.kind === 'create' ? '@general:actions.create.title' : '@general:actions.apply.title'));
|
|
1486
1483
|
}
|
|
1487
1484
|
if (useFormWizard && this.onActionHandler) {
|
|
1488
|
-
d.onAction(this.createWizardOnActionWrapper(this.onActionHandler
|
|
1485
|
+
d.onAction(this.createWizardOnActionWrapper(this.onActionHandler));
|
|
1489
1486
|
}
|
|
1490
1487
|
else if (this.onActionHandler) {
|
|
1491
1488
|
d.onAction(this.onActionHandler);
|
|
@@ -1649,11 +1646,14 @@ class PropertyFilter {
|
|
|
1649
1646
|
return (await this.expressionEvaluator.evaluate(action, scope));
|
|
1650
1647
|
}));
|
|
1651
1648
|
}
|
|
1652
|
-
createWizardOnActionWrapper(userHandler
|
|
1649
|
+
createWizardOnActionWrapper(userHandler) {
|
|
1653
1650
|
return async (ref) => {
|
|
1654
1651
|
const action = ref.action();
|
|
1655
1652
|
if (action === ENTITY_FORM_ACTION_DONE) {
|
|
1656
|
-
await
|
|
1653
|
+
const pageContinue = await continueActiveEntityFormPageStep(ref);
|
|
1654
|
+
if (!pageContinue.success) {
|
|
1655
|
+
return { keepDialogOpen: true };
|
|
1656
|
+
}
|
|
1657
1657
|
if (hasPersistedRootId$1(ref.context())) {
|
|
1658
1658
|
const out = (await userHandler(ref));
|
|
1659
1659
|
if (out?.success === false) {
|
|
@@ -1664,7 +1664,10 @@ class PropertyFilter {
|
|
|
1664
1664
|
return { success: true, data: ref.context(), skipValidate: true };
|
|
1665
1665
|
}
|
|
1666
1666
|
if (action === ENTITY_FORM_ACTION_NEXT_STEP) {
|
|
1667
|
-
await
|
|
1667
|
+
const pageContinue = await continueActiveEntityFormPageStep(ref);
|
|
1668
|
+
if (!pageContinue.success) {
|
|
1669
|
+
return { keepDialogOpen: true };
|
|
1670
|
+
}
|
|
1668
1671
|
await ref.invokeWidget?.(ENTITY_FORM_STEP_WIZARD_NAME, 'next', { setLoading: ref.setLoading });
|
|
1669
1672
|
return { keepDialogOpen: true };
|
|
1670
1673
|
}
|
|
@@ -1673,7 +1676,7 @@ class PropertyFilter {
|
|
|
1673
1676
|
if (out?.success === false) {
|
|
1674
1677
|
return out;
|
|
1675
1678
|
}
|
|
1676
|
-
const item = out?.data?.item ?? out?.data ?? {};
|
|
1679
|
+
const item = normalizeWizardPersistedRecordPatch(out?.data?.item ?? out?.data ?? {});
|
|
1677
1680
|
ref.patchContext?.(merge({}, ref.context(), item));
|
|
1678
1681
|
await ref.invokeWidget?.(ENTITY_FORM_STEP_WIZARD_NAME, 'next', { setLoading: ref.setLoading });
|
|
1679
1682
|
return merge({}, out, { keepDialogOpen: true });
|
|
@@ -2042,10 +2045,27 @@ function hasPersistedRootId$1(context) {
|
|
|
2042
2045
|
const raw = context?.id ?? context?._id;
|
|
2043
2046
|
return (typeof raw === 'string' && raw.length > 0) || (typeof raw === 'number' && !Number.isNaN(raw));
|
|
2044
2047
|
}
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
+
function normalizeWizardPersistedRecordPatch(data) {
|
|
2049
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
2050
|
+
return {};
|
|
2051
|
+
}
|
|
2052
|
+
const record = { ...data };
|
|
2053
|
+
const rawId = record['id'] ?? record['_id'];
|
|
2054
|
+
if (rawId != null && record['id'] == null) {
|
|
2055
|
+
record['id'] = rawId;
|
|
2056
|
+
}
|
|
2057
|
+
return record;
|
|
2058
|
+
}
|
|
2059
|
+
async function continueActiveEntityFormPageStep(ref) {
|
|
2060
|
+
const status = (await ref.invokeWidget?.(ENTITY_FORM_STEP_WIZARD_NAME, 'getStatus', {}));
|
|
2061
|
+
const stepId = status?.currentStep?.id;
|
|
2062
|
+
if (!stepId?.startsWith('page-')) {
|
|
2063
|
+
return { success: true };
|
|
2048
2064
|
}
|
|
2065
|
+
const result = (await ref.invokeWidget?.(`pageComponent_${stepId}`, 'continueWizardStep', {
|
|
2066
|
+
setLoading: ref.setLoading,
|
|
2067
|
+
}));
|
|
2068
|
+
return { success: result?.success !== false };
|
|
2049
2069
|
}
|
|
2050
2070
|
function buildEntityFormRelatedStepId(re) {
|
|
2051
2071
|
const safe = re.entity.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
@@ -4374,6 +4394,7 @@ class AXPEntityListViewColumnViewModel {
|
|
|
4374
4394
|
this.title = this.column.title ?? this.property.title;
|
|
4375
4395
|
this.visible = this.column?.options?.visible ?? true;
|
|
4376
4396
|
this.sortEnabled = this.property.options?.sort?.enabled;
|
|
4397
|
+
this.width = this.column?.options?.width;
|
|
4377
4398
|
this.node = computed(() => {
|
|
4378
4399
|
const widget = this.property.schema.interface;
|
|
4379
4400
|
return {
|
|
@@ -5787,10 +5808,11 @@ class AXPEntityMasterListViewModel {
|
|
|
5787
5808
|
if (columns && columnVisibilityMap && columnWidthsMap) {
|
|
5788
5809
|
this.columns.update((prev) => prev
|
|
5789
5810
|
.map((c) => {
|
|
5811
|
+
const columnKey = c.column?.options?.dataPath ?? c.name;
|
|
5790
5812
|
return {
|
|
5791
5813
|
...c,
|
|
5792
|
-
width: columnWidthsMap.get(c.column?.options?.
|
|
5793
|
-
visible: columnVisibilityMap.get(
|
|
5814
|
+
width: defaultTo(columnWidthsMap.get(columnKey), c.column?.options?.width),
|
|
5815
|
+
visible: columnVisibilityMap.get(columnKey) ?? c.visible,
|
|
5794
5816
|
};
|
|
5795
5817
|
}) // Update visibility
|
|
5796
5818
|
.sort((a, b) => columns.findIndex((col) => col.name === (a.column?.options?.dataPath ?? a.name)) -
|
|
@@ -12033,6 +12055,26 @@ function mapEntityColumnToWidgetColumn(entity, column) {
|
|
|
12033
12055
|
widget,
|
|
12034
12056
|
};
|
|
12035
12057
|
}
|
|
12058
|
+
/**
|
|
12059
|
+
* Applies entity column width (explicit or resolved via {@link AXPColumnWidthService}) to data-list columns.
|
|
12060
|
+
*/
|
|
12061
|
+
function applyDataListColumnWidths(columns, columnWidthService) {
|
|
12062
|
+
return columns.map((column) => {
|
|
12063
|
+
const existingWidth = column.width ?? column.widget?.options?.width;
|
|
12064
|
+
if (existingWidth) {
|
|
12065
|
+
return existingWidth === column.width ? column : { ...column, width: String(existingWidth) };
|
|
12066
|
+
}
|
|
12067
|
+
const columnWithWidth = {
|
|
12068
|
+
name: column.name,
|
|
12069
|
+
widget: column.widget ? { type: column.widget.type } : undefined,
|
|
12070
|
+
};
|
|
12071
|
+
const resolvedWidth = columnWidthService.resolveWidth(columnWithWidth);
|
|
12072
|
+
if (!resolvedWidth) {
|
|
12073
|
+
return column;
|
|
12074
|
+
}
|
|
12075
|
+
return { ...column, width: resolvedWidth };
|
|
12076
|
+
});
|
|
12077
|
+
}
|
|
12036
12078
|
//#endregion
|
|
12037
12079
|
//#region ---- Include/Exclude Utilities ----
|
|
12038
12080
|
/**
|
|
@@ -12063,6 +12105,7 @@ class AXPEntityListTableService {
|
|
|
12063
12105
|
this.commandService = inject(AXPCommandService);
|
|
12064
12106
|
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
12065
12107
|
this.settings = inject(AXPSettingsService);
|
|
12108
|
+
this.columnWidthService = inject(AXPColumnWidthService);
|
|
12066
12109
|
this.evaluateExpressions = async (options, data) => {
|
|
12067
12110
|
if (!options) {
|
|
12068
12111
|
return {};
|
|
@@ -12164,7 +12207,7 @@ class AXPEntityListTableService {
|
|
|
12164
12207
|
else {
|
|
12165
12208
|
baseColumns = getVisibleProperties(entity).map((prop) => mapPropertyToWidgetColumn(prop));
|
|
12166
12209
|
}
|
|
12167
|
-
return applyIncludeExclude(baseColumns, includeColumns, excludeColumns);
|
|
12210
|
+
return applyDataListColumnWidths(applyIncludeExclude(baseColumns, includeColumns, excludeColumns), this.columnWidthService);
|
|
12168
12211
|
}
|
|
12169
12212
|
/**
|
|
12170
12213
|
* Map EntityTableColumn to ListWidgetColumn
|
|
@@ -12483,6 +12526,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
12483
12526
|
this.commandService = inject(AXPCommandService);
|
|
12484
12527
|
this.eventService = inject(AXPBroadcastEventService);
|
|
12485
12528
|
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
12529
|
+
this.columnWidthService = inject(AXPColumnWidthService);
|
|
12486
12530
|
this.route = inject(ActivatedRoute);
|
|
12487
12531
|
this.isMounted = signal(false, ...(ngDevMode ? [{ debugName: "isMounted" }] : /* istanbul ignore next */ []));
|
|
12488
12532
|
this.entity = signal(null, ...(ngDevMode ? [{ debugName: "entity" }] : /* istanbul ignore next */ []));
|
|
@@ -13039,7 +13083,9 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
13039
13083
|
})
|
|
13040
13084
|
.filter((c) => c != null);
|
|
13041
13085
|
// Apply updated columns to the list widget and refresh
|
|
13042
|
-
listInstance.setOptions({
|
|
13086
|
+
listInstance.setOptions({
|
|
13087
|
+
columns: applyDataListColumnWidths(updatedColumns, this.columnWidthService),
|
|
13088
|
+
});
|
|
13043
13089
|
}
|
|
13044
13090
|
async ngOnInit() {
|
|
13045
13091
|
super.ngOnInit();
|
|
@@ -13406,6 +13452,8 @@ class AXPPageComponentWidgetViewComponent extends AXPBaseWidgetComponent {
|
|
|
13406
13452
|
super(...arguments);
|
|
13407
13453
|
//#region ---- Services & Dependencies ----
|
|
13408
13454
|
this.deviceService = inject(AXPDeviceService);
|
|
13455
|
+
this.toastService = inject(AXToastService);
|
|
13456
|
+
this.translationService = inject(AXTranslationService);
|
|
13409
13457
|
this.pageRenderer = viewChild(AXPPageComponentRendererDirective, ...(ngDevMode ? [{ debugName: "pageRenderer" }] : /* istanbul ignore next */ []));
|
|
13410
13458
|
//#endregion
|
|
13411
13459
|
//#region ---- Computed Options ----
|
|
@@ -13433,7 +13481,6 @@ class AXPPageComponentWidgetViewComponent extends AXPBaseWidgetComponent {
|
|
|
13433
13481
|
}
|
|
13434
13482
|
instance.primaryMenuItems();
|
|
13435
13483
|
instance.secondaryMenuItems();
|
|
13436
|
-
console.log({ primaryMenuItems: instance.primaryMenuItems(), secondaryMenuItems: instance.secondaryMenuItems() });
|
|
13437
13484
|
untracked(() => this.syncActionsFromPageInstance(instance));
|
|
13438
13485
|
}, ...(ngDevMode ? [{ debugName: "#syncPageActionsEffect" }] : /* istanbul ignore next */ []));
|
|
13439
13486
|
}
|
|
@@ -13457,6 +13504,15 @@ class AXPPageComponentWidgetViewComponent extends AXPBaseWidgetComponent {
|
|
|
13457
13504
|
syncContext: () => {
|
|
13458
13505
|
self.syncPageComponentIntoFormContext();
|
|
13459
13506
|
},
|
|
13507
|
+
continueWizardStep: async (callback) => {
|
|
13508
|
+
callback?.setLoading?.(true);
|
|
13509
|
+
try {
|
|
13510
|
+
return await self.runWizardStepContinue();
|
|
13511
|
+
}
|
|
13512
|
+
finally {
|
|
13513
|
+
callback?.setLoading?.(false);
|
|
13514
|
+
}
|
|
13515
|
+
},
|
|
13460
13516
|
refreshPageActions: () => {
|
|
13461
13517
|
self.refreshPageActions();
|
|
13462
13518
|
},
|
|
@@ -13490,6 +13546,66 @@ class AXPPageComponentWidgetViewComponent extends AXPBaseWidgetComponent {
|
|
|
13490
13546
|
this.pageHostRevision.update((value) => value + 1);
|
|
13491
13547
|
}
|
|
13492
13548
|
//#endregion
|
|
13549
|
+
//#region ---- Wizard Step Continue ----
|
|
13550
|
+
/**
|
|
13551
|
+
* Persists the active page step when dirty (footer save action), then merges wizard context.
|
|
13552
|
+
* Used by entity create/update step wizard footer Next/Done.
|
|
13553
|
+
*/
|
|
13554
|
+
async runWizardStepContinue() {
|
|
13555
|
+
const instance = this.resolvePageHost();
|
|
13556
|
+
if (!instance) {
|
|
13557
|
+
return { success: true };
|
|
13558
|
+
}
|
|
13559
|
+
const dirty = instance.hasUnsavedChanges?.() ?? false;
|
|
13560
|
+
if (dirty) {
|
|
13561
|
+
const command = this.resolveWizardContinueCommand(instance);
|
|
13562
|
+
if (command.name) {
|
|
13563
|
+
const result = await instance.execute(command);
|
|
13564
|
+
if (isExecuteCommandFailure(result)) {
|
|
13565
|
+
await this.showExecuteFailureToast(result);
|
|
13566
|
+
return { success: false };
|
|
13567
|
+
}
|
|
13568
|
+
}
|
|
13569
|
+
}
|
|
13570
|
+
this.syncPageComponentIntoFormContext();
|
|
13571
|
+
this.pageHostRevision.update((value) => value + 1);
|
|
13572
|
+
return { success: true };
|
|
13573
|
+
}
|
|
13574
|
+
resolveWizardContinueCommand(instance) {
|
|
13575
|
+
const explicit = instance.getWizardStepContinueCommand?.();
|
|
13576
|
+
if (explicit?.name) {
|
|
13577
|
+
return explicit;
|
|
13578
|
+
}
|
|
13579
|
+
const actions = [...instance.primaryMenuItems(), ...instance.secondaryMenuItems()];
|
|
13580
|
+
const continueAction = actions.find((action) => action.visible !== false &&
|
|
13581
|
+
isFooterZoneAction(action) &&
|
|
13582
|
+
getActionPriority(action) === 'primary' &&
|
|
13583
|
+
action.command);
|
|
13584
|
+
return continueAction ? normalizeExecuteCommand(continueAction.command) : { name: '', options: {} };
|
|
13585
|
+
}
|
|
13586
|
+
async showExecuteFailureToast(result) {
|
|
13587
|
+
const rawText = result.message?.text;
|
|
13588
|
+
let content;
|
|
13589
|
+
if (typeof rawText === 'string') {
|
|
13590
|
+
content = rawText.startsWith('@') ? await this.translationService.translateAsync(rawText) : rawText;
|
|
13591
|
+
}
|
|
13592
|
+
else if (rawText) {
|
|
13593
|
+
content = this.translationService.resolve(rawText);
|
|
13594
|
+
}
|
|
13595
|
+
else {
|
|
13596
|
+
content = await this.translationService.translateAsync('@general:messages.generic.error.description');
|
|
13597
|
+
}
|
|
13598
|
+
this.toastService.show({
|
|
13599
|
+
color: 'danger',
|
|
13600
|
+
title: await this.translationService.translateAsync('@general:messages.generic.error.title'),
|
|
13601
|
+
content,
|
|
13602
|
+
location: 'bottom-center',
|
|
13603
|
+
closeButton: true,
|
|
13604
|
+
timeOut: 5000,
|
|
13605
|
+
timeOutProgress: true,
|
|
13606
|
+
});
|
|
13607
|
+
}
|
|
13608
|
+
//#endregion
|
|
13493
13609
|
//#region ---- Context Sync ----
|
|
13494
13610
|
/** Merges the mounted page component's wizard payload into the dialog form context. */
|
|
13495
13611
|
syncPageComponentIntoFormContext() {
|
|
@@ -13730,6 +13846,15 @@ function splitToolbarSecondaryActions(primary, secondary) {
|
|
|
13730
13846
|
function isHeaderZoneAction(action) {
|
|
13731
13847
|
return action.zone === 'header';
|
|
13732
13848
|
}
|
|
13849
|
+
function isFooterZoneAction(action) {
|
|
13850
|
+
return action.zone === 'footer';
|
|
13851
|
+
}
|
|
13852
|
+
function isExecuteCommandFailure(result) {
|
|
13853
|
+
return (!!result &&
|
|
13854
|
+
typeof result === 'object' &&
|
|
13855
|
+
'success' in result &&
|
|
13856
|
+
result.success === false);
|
|
13857
|
+
}
|
|
13733
13858
|
function getActionPriority(action) {
|
|
13734
13859
|
const priority = action.priority;
|
|
13735
13860
|
return priority === 'secondary' ? 'secondary' : 'primary';
|