@acorex/platform 21.0.0-next.67 → 21.0.0-next.70

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.
@@ -1,14 +1,14 @@
1
1
  import { AXToastService } from '@acorex/components/toast';
2
2
  import * as i6 from '@acorex/core/translation';
3
3
  import { AXTranslationService, AXTranslationModule, resolveMultiLanguageString, translateSync } from '@acorex/core/translation';
4
- import * as i4$4 from '@acorex/platform/common';
4
+ import * as i4$3 from '@acorex/platform/common';
5
5
  import { AXPEntityCommandScope, AXPSettingsService, AXPCommonSettings, AXPFilterOperatorMiddlewareService, isCardFieldBadgeDisplay, resolveCardFieldBadgeColor, getEntityInfo, resolveEnabledMasterListLayouts, resolveDefaultMasterListLayout, AXPRefreshEvent, AXPReloadEvent, AXPCleanNestedFilters, AXPFileTypeProviderService, AXPFileStorageService, AXPFileActionsService, AXPDefaultMultiLanguageConfigService, withDefaultMultiLanguageOnWidgetNodeTree, AXPEntityQueryType, AXPWorkflowNavigateAction, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER, AXPMenuItemsDataSourceDefinition } from '@acorex/platform/common';
6
6
  import * as i0 from '@angular/core';
7
7
  import { InjectionToken, inject, Injector, runInInjectionContext, Injectable, input, viewChild, signal, computed, ElementRef, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent, NgModule, ChangeDetectorRef, effect, Input, afterNextRender, untracked, ViewEncapsulation, viewChildren, linkedSignal, HostBinding, output, makeEnvironmentProviders } from '@angular/core';
8
8
  import { Subject, takeUntil } from 'rxjs';
9
9
  import { AXPLayoutBuilderService, LayoutBuilderModule } from '@acorex/platform/layout/builder';
10
10
  import * as i3 from '@acorex/platform/layout/widget-core';
11
- import { AXPWidgetsCatalog, AXPWidgetCoreModule, AXPPageStatus, AXPWidgetRegistryService, AXPColumnWidgetComponent, AXPValueWidgetComponent, AXPWidgetGroupEnum, createBooleanProperty, AXPWidgetRendererDirective, createStringProperty, createNumberProperty, AXP_WIDGETS_ADVANCE_SUB_MEDIA, AXP_WIDGETS_ADVANCE_CATEGORY, createSelectProperty, AXP_WIDGETS_EDITOR_CATEGORY, AXP_WIDGET_DEFINITION_PROVIDER } from '@acorex/platform/layout/widget-core';
11
+ import { AXPWidgetsCatalog, AXPWidgetCoreModule, AXPPageStatus, AXPWidgetRegistryService, AXPColumnWidgetComponent, AXPValueWidgetComponent, AXPWidgetGroupEnum, createBooleanProperty, AXPWidgetRendererDirective, AXPBaseWidgetComponent, AXPWidgetStatus, createStringProperty, createNumberProperty, AXP_WIDGETS_ADVANCE_SUB_MEDIA, AXP_WIDGETS_ADVANCE_CATEGORY, createSelectProperty, AXP_WIDGETS_EDITOR_CATEGORY, AXP_WIDGET_DEFINITION_PROVIDER } from '@acorex/platform/layout/widget-core';
12
12
  import { AXPSystemActionType, AXPDeviceService, AXPExpressionEvaluatorService, AXPBroadcastEventService, applyFilterArray, applySortArray, resolveActionLook, AXPDistributedEventListenerService, AXPPlatformScope, AXHighlightService, extractValue, setSmart, getChangedPaths, objectKeyValueTransforms, AXPHookService, AXPDataGenerator, AXPComponentSlotModule, AXPColumnWidthService, AXPModuleManifestRegistry, defaultColumnWidthProvider, AXP_COLUMN_WIDTH_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXPModuleManifestsDataSourceDefinition } from '@acorex/platform/core';
13
13
  import { cloneDeep, merge, get, castArray, set, orderBy, omit, isNil, isEmpty, isEqual as isEqual$1, isArray, isString } from 'lodash-es';
14
14
  import { transform, isEqual } from 'lodash';
@@ -25,8 +25,10 @@ import { AXFormatService } from '@acorex/core/format';
25
25
  import * as i5 from '@angular/common';
26
26
  import { CommonModule, AsyncPipe } from '@angular/common';
27
27
  import { AXPThemeLayoutBlockComponent, AXPPreloadFiltersComponent, AXP_PAGE_COMPONENT_PROVIDER, AXPStateMessageComponent, AXPColumnItemListComponent, AXPDataSelectorService, AXPPageComponentRegistryService } from '@acorex/platform/layout/components';
28
- import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageComponentInstanceRegistryService } from '@acorex/platform/layout/views';
28
+ import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageComponentRendererDirective, AXPPageComponentInstanceRegistryService } from '@acorex/platform/layout/views';
29
29
  import { AXDataSource } from '@acorex/cdk/common';
30
+ import { AXP_ENTITY_CRUD_SETUP } from '@acorex/platform/domain';
31
+ export { AXP_ENTITY_DEFINITION_CRUD_SERVICE } from '@acorex/platform/domain';
30
32
  import * as i1$3 from '@acorex/platform/workflow';
31
33
  import { AXPWorkflowService, ofType, createWorkFlowEvent, AXPWorkflowAction, AXPWorkflowEventService, AXPWorkflowModule } from '@acorex/platform/workflow';
32
34
  import { AXPLayoutThemeService } from '@acorex/platform/themes/shared';
@@ -35,8 +37,6 @@ import { AXDialogService } from '@acorex/components/dialog';
35
37
  import { AXLoadingDialogService } from '@acorex/components/loading-dialog';
36
38
  import { AXPopupService } from '@acorex/components/popup';
37
39
  import { AXPlatform } from '@acorex/core/platform';
38
- import { AXP_ENTITY_CRUD_SETUP } from '@acorex/platform/domain';
39
- export { AXP_ENTITY_DEFINITION_CRUD_SERVICE } from '@acorex/platform/domain';
40
40
  import * as i2$1 from '@acorex/components/badge';
41
41
  import { AXBadgeModule } from '@acorex/components/badge';
42
42
  import { AXCheckBoxModule } from '@acorex/components/check-box';
@@ -60,7 +60,7 @@ import { AXValidationModule } from '@acorex/core/validation';
60
60
  import { AXP_DISABLED_PROPERTY, AXP_ALLOW_CLEAR_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_DATA_PROPERTY_GROUP, AXP_ALLOW_MULTIPLE_PROPERTY, AXP_NAME_PROPERTY, AXP_READONLY_PROPERTY, AXP_PLACEHOLDER_PROPERTY, AXP_BEHAVIOR_PROPERTY_GROUP, AXPProviderSelectWidgetEditBase, AXP_ROW_EXPR_PREFIX, AXP_DOWNLOADABLE_PROPERTY, AXP_DESCRIPTION_PROPERTY } from '@acorex/platform/layout/widgets';
61
61
  import * as i2$2 from '@acorex/components/select-box';
62
62
  import { AXSelectBoxModule } from '@acorex/components/select-box';
63
- import * as i4$2 from '@acorex/components/dropdown';
63
+ import * as i3$3 from '@acorex/components/dropdown';
64
64
  import { AXDropdownModule } from '@acorex/components/dropdown';
65
65
  import * as i2$3 from '@acorex/components/tabs';
66
66
  import { AXTabsModule } from '@acorex/components/tabs';
@@ -71,7 +71,7 @@ import { AXTextBoxModule } from '@acorex/components/text-box';
71
71
  import { AXFileService } from '@acorex/core/file';
72
72
  import { AXUploaderZoneDirective } from '@acorex/cdk/uploader';
73
73
  import { AXUploaderModule } from '@acorex/components/uploader';
74
- import * as i4$3 from '@acorex/components/collapse';
74
+ import * as i4$2 from '@acorex/components/collapse';
75
75
  import { AXCollapseModule } from '@acorex/components/collapse';
76
76
 
77
77
  function ensureListActions(ctx) {
@@ -1248,6 +1248,8 @@ const ENTITY_FORM_STEP_WIZARD_NAME = 'entityFormStepWizard';
1248
1248
  const ENTITY_FORM_ACTION_FIRST_STEP_CONTINUE = 'entity-form-first-step-continue';
1249
1249
  /** Footer command: close dialog (data already saved per step). */
1250
1250
  const ENTITY_FORM_ACTION_DONE = 'entity-form-done';
1251
+ /** Footer command: sync page widgets then advance wizard. */
1252
+ const ENTITY_FORM_ACTION_NEXT_STEP = 'entity-form-next-step';
1251
1253
  //#endregion
1252
1254
  class AXPEntityFormBuilderService {
1253
1255
  constructor() {
@@ -1637,20 +1639,41 @@ class PropertyFilter {
1637
1639
  const sectionScaleFactors = normalizeLayoutFillRowGaps(renderedSections, (s) => s.layout, (s) => s.id);
1638
1640
  const filterEvalRoot = merge({}, this.initialContext, modelForRelatedEval);
1639
1641
  const listRelatedEntities = collectListRelatedEntitiesForFormWizard(entity, this.kind);
1640
- const useListWizard = listRelatedEntities.length > 0 && (this.kind === 'create' || this.kind === 'update');
1641
- const listWizardSteps = [];
1642
+ const pageWizardPages = collectPagesForFormWizard(entity, this.kind);
1643
+ const useFormWizard = (listRelatedEntities.length > 0 || pageWizardPages.length > 0) &&
1644
+ (this.kind === 'create' || this.kind === 'update');
1645
+ const wizardExtraSteps = [];
1642
1646
  for (const re of listRelatedEntities) {
1643
1647
  const [rm, en] = re.entity.split('.');
1644
1648
  const relDef = await this.entityRegistry.resolve(rm, en);
1645
- listWizardSteps.push({
1649
+ wizardExtraSteps.push({
1650
+ kind: 'related-list',
1651
+ order: re.layout?.order ?? 0,
1646
1652
  stepId: buildEntityFormRelatedStepId(re),
1647
1653
  title: (re.title ?? relDef?.title ?? re.entity),
1648
1654
  rel: re,
1649
1655
  });
1650
1656
  }
1651
- const prebuiltRelatedListConfigs = useListWizard
1652
- ? await Promise.all(listWizardSteps.map((s) => this.buildRelatedEntityListWidgetOptions(s.rel, filterEvalRoot)))
1657
+ for (const page of pageWizardPages) {
1658
+ wizardExtraSteps.push({
1659
+ kind: 'page',
1660
+ order: page.layout?.order ?? 0,
1661
+ stepId: buildEntityFormPageStepId(page),
1662
+ title: (page.title ?? page.componentKey),
1663
+ page,
1664
+ componentKey: page.componentKey,
1665
+ });
1666
+ }
1667
+ wizardExtraSteps.sort((a, b) => a.order - b.order);
1668
+ const pageWizardWidgetNames = wizardExtraSteps
1669
+ .filter((s) => s.kind === 'page')
1670
+ .map((s) => buildPageComponentWidgetName(s.page));
1671
+ const prebuiltRelatedListConfigs = useFormWizard
1672
+ ? await Promise.all(wizardExtraSteps
1673
+ .filter((s) => s.kind === 'related-list')
1674
+ .map((s) => this.buildRelatedEntityListWidgetOptions(s.rel, filterEvalRoot)))
1653
1675
  : [];
1676
+ let relatedListConfigIndex = 0;
1654
1677
  const mainFormGridArgs = {
1655
1678
  entity,
1656
1679
  finalSections,
@@ -1661,15 +1684,15 @@ class PropertyFilter {
1661
1684
  };
1662
1685
  const dialog = this.layoutBuilder.create().dialog((d) => {
1663
1686
  d.setTitle(title);
1664
- d.setSize(this.externalSize ?? (useListWizard ? 'lg' : calculatedSize));
1687
+ d.setSize(this.externalSize ?? (useFormWizard ? 'lg' : calculatedSize));
1665
1688
  d.setCloseButton(true);
1666
1689
  d.content((layout) => {
1667
1690
  const defaultMode = this.kind === 'single' ? 'view' : 'edit';
1668
1691
  layout.mode(this.externalMode ?? defaultMode);
1669
- if (useListWizard) {
1692
+ if (useFormWizard) {
1670
1693
  layout.stepWizard((w) => {
1671
1694
  w.name(ENTITY_FORM_STEP_WIZARD_NAME);
1672
- w.setLook('circular');
1695
+ w.setLook('arrow-minimal');
1673
1696
  w.setShowActions(false);
1674
1697
  const mainStepTitle = (entity.formats?.individual ||
1675
1698
  entity.title ||
@@ -1679,33 +1702,55 @@ class PropertyFilter {
1679
1702
  inner.grid((grid) => this.fillMainEntityFormGrid(grid, mainFormGridArgs));
1680
1703
  });
1681
1704
  });
1682
- listWizardSteps.forEach((step, idx) => {
1683
- const built = prebuiltRelatedListConfigs[idx];
1684
- w.step(step.stepId, step.title, (st) => {
1685
- st.content((inner) => {
1686
- // Step content uses root LayoutBuilder (no customWidget); wrap in flex like other roots.
1687
- inner.flex((flex) => {
1688
- flex.customWidget(AXPWidgetsCatalog.entityList, (iw) => {
1689
- iw.name(built.name);
1690
- if (built.defaultValue) {
1691
- iw.defaultValue(built.defaultValue);
1692
- }
1693
- iw.options(built.options);
1705
+ for (const wizardStep of wizardExtraSteps) {
1706
+ if (wizardStep.kind === 'related-list') {
1707
+ const built = prebuiltRelatedListConfigs[relatedListConfigIndex++];
1708
+ w.step(wizardStep.stepId, wizardStep.title, (st) => {
1709
+ st.content((inner) => {
1710
+ inner.flex((flex) => {
1711
+ flex.setDirection('column');
1712
+ flex.setAlignItems('stretch');
1713
+ flex.customWidget(AXPWidgetsCatalog.entityList, (iw) => {
1714
+ iw.name(built.name);
1715
+ if (built.defaultValue) {
1716
+ iw.defaultValue(built.defaultValue);
1717
+ }
1718
+ iw.options(built.options);
1719
+ });
1694
1720
  });
1695
1721
  });
1696
1722
  });
1697
- });
1698
- });
1723
+ }
1724
+ else {
1725
+ w.step(wizardStep.stepId, wizardStep.title, (st) => {
1726
+ st.content((inner) => {
1727
+ inner.flex((flex) => {
1728
+ flex.setDirection('column');
1729
+ flex.setAlignItems('stretch');
1730
+ flex.customWidget(AXPWidgetsCatalog.pageComponent, (iw) => {
1731
+ iw.name(buildPageComponentWidgetName(wizardStep.page));
1732
+ iw.options({
1733
+ componentKey: wizardStep.page.componentKey,
1734
+ field: wizardStep.page.field,
1735
+ pageOptions: wizardStep.page.options ?? {},
1736
+ showPageActions: true,
1737
+ });
1738
+ });
1739
+ });
1740
+ });
1741
+ });
1742
+ }
1743
+ }
1699
1744
  });
1700
1745
  }
1701
1746
  else {
1702
1747
  layout.grid((grid) => this.fillMainEntityFormGrid(grid, mainFormGridArgs));
1703
1748
  }
1704
1749
  });
1705
- if (this.externalActionsDelegate && !useListWizard) {
1750
+ if (this.externalActionsDelegate && !useFormWizard) {
1706
1751
  d.setActions(this.externalActionsDelegate);
1707
1752
  }
1708
- else if (useListWizard) {
1753
+ else if (useFormWizard) {
1709
1754
  d.setActions((ab) => configureEntityFormWizardFooterActions(ab, ENTITY_FORM_STEP_WIZARD_NAME, this.kind === 'create'
1710
1755
  ? '{{ ((typeof context.id === "string" && context.id.length > 0) || (typeof context.id === "number" && !isNaN(context.id)) || (typeof context._id === "string" && context._id.length > 0) || (typeof context._id === "number" && !isNaN(context._id))) ? "@general:entity-form.update-and-continue.title" : "@general:entity-form.create-and-continue.title" }}'
1711
1756
  : '@general:entity-form.save-and-continue.title'));
@@ -1718,8 +1763,8 @@ class PropertyFilter {
1718
1763
  .cancel('@general:actions.cancel.title')
1719
1764
  .submit(this.kind === 'create' ? '@general:actions.create.title' : '@general:actions.apply.title'));
1720
1765
  }
1721
- if (useListWizard && this.onActionHandler) {
1722
- d.onAction(this.createWizardOnActionWrapper(this.onActionHandler));
1766
+ if (useFormWizard && this.onActionHandler) {
1767
+ d.onAction(this.createWizardOnActionWrapper(this.onActionHandler, pageWizardWidgetNames));
1723
1768
  }
1724
1769
  else if (this.onActionHandler) {
1725
1770
  d.onAction(this.onActionHandler);
@@ -1883,12 +1928,25 @@ class PropertyFilter {
1883
1928
  return (await this.expressionEvaluator.evaluate(action, scope));
1884
1929
  }));
1885
1930
  }
1886
- createWizardOnActionWrapper(userHandler) {
1931
+ createWizardOnActionWrapper(userHandler, pageWizardWidgetNames = []) {
1887
1932
  return async (ref) => {
1888
1933
  const action = ref.action();
1889
1934
  if (action === ENTITY_FORM_ACTION_DONE) {
1935
+ await syncAllPageComponentWidgets(ref, pageWizardWidgetNames);
1936
+ if (hasPersistedRootId$1(ref.context())) {
1937
+ const out = (await userHandler(ref));
1938
+ if (out?.success === false) {
1939
+ return out;
1940
+ }
1941
+ return { success: true, data: out?.data ?? ref.context(), skipValidate: true };
1942
+ }
1890
1943
  return { success: true, data: ref.context(), skipValidate: true };
1891
1944
  }
1945
+ if (action === ENTITY_FORM_ACTION_NEXT_STEP) {
1946
+ await syncAllPageComponentWidgets(ref, pageWizardWidgetNames);
1947
+ await ref.invokeWidget?.(ENTITY_FORM_STEP_WIZARD_NAME, 'next', { setLoading: ref.setLoading });
1948
+ return { keepDialogOpen: true };
1949
+ }
1892
1950
  if (action === ENTITY_FORM_ACTION_FIRST_STEP_CONTINUE) {
1893
1951
  const out = (await userHandler(ref));
1894
1952
  if (out?.success === false) {
@@ -2201,6 +2259,37 @@ function collectListRelatedEntitiesForFormWizard(entity, kind) {
2201
2259
  isRelatedEntityIncludedOnMasterForm(re, kind, 'list'))
2202
2260
  .sort((a, b) => (a.layout?.order ?? 0) - (b.layout?.order ?? 0));
2203
2261
  }
2262
+ function isEntityPageIncludedOnMasterForm(page, kind) {
2263
+ if (kind !== 'create' && kind !== 'update') {
2264
+ return true;
2265
+ }
2266
+ if (kind === 'create') {
2267
+ return page.appearOn?.create === true;
2268
+ }
2269
+ return page.appearOn?.update === true;
2270
+ }
2271
+ function collectPagesForFormWizard(entity, kind) {
2272
+ return (entity.pages ?? [])
2273
+ .filter((page) => !page.hidden && isEntityPageIncludedOnMasterForm(page, kind))
2274
+ .sort((a, b) => (a.layout?.order ?? 0) - (b.layout?.order ?? 0));
2275
+ }
2276
+ function buildEntityFormPageStepId(page) {
2277
+ const safeKey = page.componentKey.replace(/[^a-zA-Z0-9._-]/g, '_');
2278
+ const fieldSuffix = page.field ? `-${page.field.replace(/[^a-zA-Z0-9._-]/g, '_')}` : '';
2279
+ return `page-${safeKey}${fieldSuffix}`;
2280
+ }
2281
+ function buildPageComponentWidgetName(page) {
2282
+ return `pageComponent_${buildEntityFormPageStepId(page)}`;
2283
+ }
2284
+ function hasPersistedRootId$1(context) {
2285
+ const raw = context?.id ?? context?._id;
2286
+ return (typeof raw === 'string' && raw.length > 0) || (typeof raw === 'number' && !Number.isNaN(raw));
2287
+ }
2288
+ async function syncAllPageComponentWidgets(ref, widgetNames) {
2289
+ for (const name of widgetNames) {
2290
+ await ref.invokeWidget?.(name, 'syncContext', {});
2291
+ }
2292
+ }
2204
2293
  function buildEntityFormRelatedStepId(re) {
2205
2294
  const safe = re.entity.replace(/[^a-zA-Z0-9._-]/g, '_');
2206
2295
  return `related-${safe}-${re.layout?.order ?? 0}`;
@@ -2224,9 +2313,10 @@ function configureEntityFormWizardFooterActions(ab, wizardName, firstStepContinu
2224
2313
  });
2225
2314
  ab.custom({
2226
2315
  title: '@general:actions.next.title',
2227
- command: `widget:${wizardName}.next`,
2316
+ command: { name: ENTITY_FORM_ACTION_NEXT_STEP },
2228
2317
  color: 'primary',
2229
2318
  position: 'suffix',
2319
+ predicateApiWidgetName: wizardName,
2230
2320
  hidden: '{{api.getStatus().isFirst || api.getStatus().isLast}}',
2231
2321
  });
2232
2322
  ab.custom({
@@ -3975,43 +4065,6 @@ var entityPreloadFiltersContainer_component = /*#__PURE__*/Object.freeze({
3975
4065
  AXPEntityPreloadFiltersContainerComponent: AXPEntityPreloadFiltersContainerComponent
3976
4066
  });
3977
4067
 
3978
- const AXP_DATA_SEEDER_TOKEN = new InjectionToken('AXP_DATA_SEEDER_TOKEN');
3979
- class AXPDataSeederService {
3980
- constructor() {
3981
- this.loaders = inject(AXP_DATA_SEEDER_TOKEN, { optional: true });
3982
- }
3983
- async seed() {
3984
- for (const loader of castArray(this.loaders)) {
3985
- if (!loader)
3986
- continue;
3987
- const seederName = loader.constructor?.name || 'UnknownSeeder';
3988
- const startTime = performance.now();
3989
- try {
3990
- await loader.seed();
3991
- }
3992
- catch (err) {
3993
- const message = err instanceof Error ? err.message : String(err);
3994
- console.error(`[AXPDataSeeder] Seeder "${seederName}" failed (continuing with next):`, message);
3995
- if (err instanceof Error && err.stack) {
3996
- console.error(err.stack);
3997
- }
3998
- // Optionally log to your system-log / app-log entity here if you have one (inject a writer and persist).
3999
- continue;
4000
- }
4001
- const duration = performance.now() - startTime;
4002
- if (duration > 3000) {
4003
- console.warn(`[AXPDataSeeder] Seeder "${seederName}" took ${duration.toFixed(2)}ms (>3000ms threshold)`);
4004
- }
4005
- }
4006
- }
4007
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDataSeederService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4008
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDataSeederService, providedIn: 'root' }); }
4009
- }
4010
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDataSeederService, decorators: [{
4011
- type: Injectable,
4012
- args: [{ providedIn: 'root' }]
4013
- }] });
4014
-
4015
4068
  /**
4016
4069
  * Data source definition provider that returns all entity names
4017
4070
  * from entity loaders' list() (const.ts in each module).
@@ -4101,6 +4154,139 @@ class AXPEntitiesListDataSourceDefinition {
4101
4154
  }
4102
4155
  }
4103
4156
 
4157
+ //#region ---- Imports ----
4158
+ //#endregion
4159
+ //#region ---- Constants ----
4160
+ const DEFAULT_RELATED_ORDER_STEP = 10;
4161
+ const DEFAULT_PLUGIN_ZONE_FLOOR = 100_000;
4162
+ /** Space per plugin slot so multiple fields in one slot do not cross into the next. */
4163
+ const PLUGIN_SLOT_SPAN = 10_000;
4164
+ const SUB_ORDER_STEP = 10;
4165
+ const PLUGIN_SLOT_INDEX = {
4166
+ 'meta-data-builder': 0,
4167
+ attachments: 1,
4168
+ documents: 2,
4169
+ comments: 3,
4170
+ history: 4,
4171
+ };
4172
+ //#endregion
4173
+ //#region ---- Helpers ----
4174
+ function shouldSkipPageForMax(page, skip) {
4175
+ if (!skip) {
4176
+ return false;
4177
+ }
4178
+ if (page.componentKey !== skip.componentKey) {
4179
+ return false;
4180
+ }
4181
+ if (skip.field !== undefined) {
4182
+ return page.field === skip.field;
4183
+ }
4184
+ return true;
4185
+ }
4186
+ function normalizeRelatedPageListDetailOrders(relatedEntities, step) {
4187
+ const pageTabRelated = (relatedEntities ?? []).filter((re) => re.layout?.type === 'page-list' || re.layout?.type === 'page-detail');
4188
+ let maxExplicit = 0;
4189
+ for (const re of pageTabRelated) {
4190
+ const o = re.layout?.order;
4191
+ if (typeof o === 'number' && Number.isFinite(o)) {
4192
+ maxExplicit = Math.max(maxExplicit, o);
4193
+ }
4194
+ }
4195
+ let cursor = maxExplicit;
4196
+ for (const re of pageTabRelated) {
4197
+ const layout = re.layout;
4198
+ if (!layout || layout.order != null) {
4199
+ continue;
4200
+ }
4201
+ cursor += step;
4202
+ re.layout = { ...layout, order: cursor };
4203
+ }
4204
+ let afterMax = 0;
4205
+ for (const re of pageTabRelated) {
4206
+ const o = re.layout?.order;
4207
+ if (typeof o === 'number' && Number.isFinite(o)) {
4208
+ afterMax = Math.max(afterMax, o);
4209
+ }
4210
+ }
4211
+ return afterMax;
4212
+ }
4213
+ /**
4214
+ * Ordinal within a slot for multi-field pages (attachments, meta-data-builder), stable by field name.
4215
+ */
4216
+ function subOrderWithinComponentSlot(pages, componentKey, skip, currentField) {
4217
+ const peerFieldKeys = (pages ?? [])
4218
+ .filter((p) => p.componentKey === componentKey && !shouldSkipPageForMax(p, skip))
4219
+ .map((p) => p.field ?? '');
4220
+ const keySet = new Set(peerFieldKeys);
4221
+ keySet.add(currentField ?? '');
4222
+ const sorted = [...keySet].sort((a, b) => a.localeCompare(b));
4223
+ const index = sorted.indexOf(currentField ?? '');
4224
+ return Math.max(0, index) * SUB_ORDER_STEP;
4225
+ }
4226
+ //#endregion
4227
+ //#region ---- Public API ----
4228
+ /**
4229
+ * Resolves `layout.order` for a built-in plugin detail tab (`entity.pages`).
4230
+ *
4231
+ * 1. Assigns finite `layout.order` values to related `page-list` / `page-detail` rows that omit
4232
+ * `order` (the composer otherwise treats them as +Infinity).
4233
+ * 2. Places plugin tabs in a fixed relative order: meta-data-builder → attachments → documents →
4234
+ * comments → history, after all related tabs.
4235
+ */
4236
+ function resolveEntityPluginDetailPageOrder(input, slot, options) {
4237
+ const relatedStep = options.relatedOrderStep ?? DEFAULT_RELATED_ORDER_STEP;
4238
+ const zoneFloor = options.pluginZoneFloor ?? DEFAULT_PLUGIN_ZONE_FLOOR;
4239
+ const { componentKey, skipPage, field } = options;
4240
+ const afterRelatedMax = normalizeRelatedPageListDetailOrders(input.relatedEntities, relatedStep);
4241
+ const pluginZoneStart = Math.max(afterRelatedMax + relatedStep, zoneFloor);
4242
+ const slotIndex = PLUGIN_SLOT_INDEX[slot];
4243
+ const subOrder = subOrderWithinComponentSlot(input.pages, componentKey, skipPage, field);
4244
+ return pluginZoneStart + slotIndex * PLUGIN_SLOT_SPAN + subOrder;
4245
+ }
4246
+ //#endregion
4247
+
4248
+ const AXP_DATA_SEEDER_TOKEN = new InjectionToken('AXP_DATA_SEEDER_TOKEN');
4249
+ class AXPDataSeederService {
4250
+ constructor() {
4251
+ this.loaders = inject(AXP_DATA_SEEDER_TOKEN, { optional: true });
4252
+ }
4253
+ async seed() {
4254
+ for (const loader of castArray(this.loaders)) {
4255
+ if (!loader)
4256
+ continue;
4257
+ const seederName = loader.constructor?.name || 'UnknownSeeder';
4258
+ const startTime = performance.now();
4259
+ try {
4260
+ await loader.seed();
4261
+ }
4262
+ catch (err) {
4263
+ const message = err instanceof Error ? err.message : String(err);
4264
+ console.error(`[AXPDataSeeder] Seeder "${seederName}" failed (continuing with next):`, message);
4265
+ if (err instanceof Error && err.stack) {
4266
+ console.error(err.stack);
4267
+ }
4268
+ // Optionally log to your system-log / app-log entity here if you have one (inject a writer and persist).
4269
+ continue;
4270
+ }
4271
+ const duration = performance.now() - startTime;
4272
+ if (duration > 3000) {
4273
+ console.warn(`[AXPDataSeeder] Seeder "${seederName}" took ${duration.toFixed(2)}ms (>3000ms threshold)`);
4274
+ }
4275
+ }
4276
+ }
4277
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDataSeederService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4278
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDataSeederService, providedIn: 'root' }); }
4279
+ }
4280
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDataSeederService, decorators: [{
4281
+ type: Injectable,
4282
+ args: [{ providedIn: 'root' }]
4283
+ }] });
4284
+
4285
+ /**
4286
+ * Re-export from domain to avoid circular dependency: layout/components must not depend on layout/entity.
4287
+ * Consumers that only need the token/interface can import from @acorex/platform/domain.
4288
+ */
4289
+
4104
4290
  class AXPEntityCommandTriggerViewModel {
4105
4291
  constructor(entity, action, isChild = false) {
4106
4292
  this.name = `${typeof action.command === 'string' ? action.command : action.command.name}&${action.name}`;
@@ -4504,136 +4690,24 @@ const AXPEntityEventsKeys = {
4504
4690
  };
4505
4691
 
4506
4692
  /**
4507
- * Resolves a stable row id from entity list row data.
4693
+ * Entity Event Dispatcher - A wrapper for entity-specific events
4694
+ * Handles pattern-based dispatching for entity operations with wildcard support
4508
4695
  */
4509
- function getEntityListRowId(data, key = 'id') {
4510
- const value = data[key];
4511
- if (value != null && value !== '') {
4512
- return String(value);
4696
+ class AXPEntityEventDispatcherService {
4697
+ constructor() {
4698
+ this.eventService = inject(AXPDistributedEventListenerService);
4513
4699
  }
4514
- return '';
4515
- }
4516
- /**
4517
- * Finds row data in a hierarchical grid tree (root rows and nested children).
4518
- */
4519
- function findEntityListRowDataInTree(items, id, key) {
4520
- for (const item of items) {
4521
- if (item && typeof item === 'object' && String(item[key]) === id) {
4522
- return item;
4523
- }
4524
- const rec = item;
4525
- const metaChildren = rec?.['__meta__']?.['children'];
4526
- const directChildren = rec?.['children'];
4527
- const childArr = Array.isArray(metaChildren)
4528
- ? metaChildren
4529
- : Array.isArray(directChildren)
4530
- ? directChildren
4531
- : null;
4532
- if (childArr?.length) {
4533
- const found = findEntityListRowDataInTree(childArr, id, key);
4534
- if (found) {
4535
- return found;
4536
- }
4537
- }
4538
- }
4539
- return null;
4540
- }
4541
- /**
4542
- * Restores expanded rows after data load (parents before children).
4543
- */
4544
- async function restoreEntityListExpandedRows(options) {
4545
- const pending = [...new Set(options.expandedRowIds.filter(Boolean))];
4546
- if (!pending.length) {
4547
- return;
4548
- }
4549
- let safety = 0;
4550
- const maxPasses = Math.max(pending.length * 3, 10);
4551
- while (pending.length > 0 && safety++ < maxPasses) {
4552
- const rows = options.getDisplayedRows();
4553
- let progressed = false;
4554
- for (let i = pending.length - 1; i >= 0; i--) {
4555
- const id = pending[i];
4556
- const item = findEntityListRowDataInTree(rows, id, options.rowKey);
4557
- if (!item) {
4558
- continue;
4559
- }
4560
- const meta = item['__meta__'];
4561
- if (meta?.['expanded'] !== true) {
4562
- await options.expandRow({ data: item });
4563
- }
4564
- pending.splice(i, 1);
4565
- progressed = true;
4566
- }
4567
- if (!progressed) {
4568
- break;
4569
- }
4570
- }
4571
- }
4572
-
4573
- /**
4574
- * Applies take/skip to the data source without triggering {@link AXDataSource.load}.
4575
- */
4576
- function applyDataSourcePagingWithoutLoad(dataSource, paging) {
4577
- const take = Math.max(1, paging.take);
4578
- const skip = Math.max(0, paging.skip);
4579
- const page = Math.floor(skip / take);
4580
- const ds = dataSource;
4581
- dataSource.config.pageSize = take;
4582
- if (ds._query) {
4583
- ds._query.take = take;
4584
- ds._query.skip = skip;
4585
- }
4586
- ds._page = page;
4587
- }
4588
- function getDataSourcePageIndex(dataSource) {
4589
- const ds = dataSource;
4590
- return ds._page ?? 0;
4591
- }
4592
- function normalizeListPaging(paging, defaultTake) {
4593
- const take = typeof paging?.take === 'number' && paging.take > 0 ? paging.take : defaultTake;
4594
- const skip = typeof paging?.skip === 'number' && paging.skip >= 0 ? paging.skip : 0;
4595
- return { take, skip };
4596
- }
4597
-
4598
- const AXPEntityListPersistenceModeDefault = 'persistent';
4599
- function normalizeEntityListPersistenceMode(value) {
4600
- if (value === 'none' || value === 'persistent' || value === 'route') {
4601
- return value;
4602
- }
4603
- return AXPEntityListPersistenceModeDefault;
4604
- }
4605
- function canPersistEntityListState(mode) {
4606
- return mode !== 'none';
4607
- }
4608
- /** `none` never reads list state from user settings. */
4609
- function shouldLoadEntityListStateFromStorage(mode) {
4610
- return mode !== 'none';
4611
- }
4612
- /** `route` clears stored list state when the route entity (module + name) changes. */
4613
- function shouldResetEntityListStateOnRouteEntry(mode) {
4614
- return mode === 'route';
4615
- }
4616
- const ENTITY_LIST_ROUTE_CONTEXT_SESSION_KEY = 'axp-entity-list-route-context';
4617
-
4618
- /**
4619
- * Entity Event Dispatcher - A wrapper for entity-specific events
4620
- * Handles pattern-based dispatching for entity operations with wildcard support
4621
- */
4622
- class AXPEntityEventDispatcherService {
4623
- constructor() {
4624
- this.eventService = inject(AXPDistributedEventListenerService);
4625
- }
4626
- async dispatchEntityEvent(operation, entityName, data) {
4627
- const enhancedData = {
4628
- ...data,
4629
- entityName,
4630
- operation,
4631
- timestamp: new Date(),
4632
- source: 'entity-dispatcher',
4633
- };
4634
- const eventKeysToDispatch = await this.getAllMatchingEventKeys(operation, entityName);
4635
- const dispatchPromises = eventKeysToDispatch.map((key) => this.eventService.dispatch(key, enhancedData));
4636
- await Promise.all(dispatchPromises);
4700
+ async dispatchEntityEvent(operation, entityName, data) {
4701
+ const enhancedData = {
4702
+ ...data,
4703
+ entityName,
4704
+ operation,
4705
+ timestamp: new Date(),
4706
+ source: 'entity-dispatcher',
4707
+ };
4708
+ const eventKeysToDispatch = await this.getAllMatchingEventKeys(operation, entityName);
4709
+ const dispatchPromises = eventKeysToDispatch.map((key) => this.eventService.dispatch(key, enhancedData));
4710
+ await Promise.all(dispatchPromises);
4637
4711
  }
4638
4712
  async getAllMatchingEventKeys(operation, entityName) {
4639
4713
  const eventKeys = new Set();
@@ -4715,6 +4789,118 @@ function getMasterInterfacePropertySortKey(interfaceRow, indexInMasterInterfaceL
4715
4789
  }
4716
4790
  //#endregion
4717
4791
 
4792
+ /**
4793
+ * Resolves a stable row id from entity list row data.
4794
+ */
4795
+ function getEntityListRowId(data, key = 'id') {
4796
+ const value = data[key];
4797
+ if (value != null && value !== '') {
4798
+ return String(value);
4799
+ }
4800
+ return '';
4801
+ }
4802
+ /**
4803
+ * Finds row data in a hierarchical grid tree (root rows and nested children).
4804
+ */
4805
+ function findEntityListRowDataInTree(items, id, key) {
4806
+ for (const item of items) {
4807
+ if (item && typeof item === 'object' && String(item[key]) === id) {
4808
+ return item;
4809
+ }
4810
+ const rec = item;
4811
+ const metaChildren = rec?.['__meta__']?.['children'];
4812
+ const directChildren = rec?.['children'];
4813
+ const childArr = Array.isArray(metaChildren)
4814
+ ? metaChildren
4815
+ : Array.isArray(directChildren)
4816
+ ? directChildren
4817
+ : null;
4818
+ if (childArr?.length) {
4819
+ const found = findEntityListRowDataInTree(childArr, id, key);
4820
+ if (found) {
4821
+ return found;
4822
+ }
4823
+ }
4824
+ }
4825
+ return null;
4826
+ }
4827
+ /**
4828
+ * Restores expanded rows after data load (parents before children).
4829
+ */
4830
+ async function restoreEntityListExpandedRows(options) {
4831
+ const pending = [...new Set(options.expandedRowIds.filter(Boolean))];
4832
+ if (!pending.length) {
4833
+ return;
4834
+ }
4835
+ let safety = 0;
4836
+ const maxPasses = Math.max(pending.length * 3, 10);
4837
+ while (pending.length > 0 && safety++ < maxPasses) {
4838
+ const rows = options.getDisplayedRows();
4839
+ let progressed = false;
4840
+ for (let i = pending.length - 1; i >= 0; i--) {
4841
+ const id = pending[i];
4842
+ const item = findEntityListRowDataInTree(rows, id, options.rowKey);
4843
+ if (!item) {
4844
+ continue;
4845
+ }
4846
+ const meta = item['__meta__'];
4847
+ if (meta?.['expanded'] !== true) {
4848
+ await options.expandRow({ data: item });
4849
+ }
4850
+ pending.splice(i, 1);
4851
+ progressed = true;
4852
+ }
4853
+ if (!progressed) {
4854
+ break;
4855
+ }
4856
+ }
4857
+ }
4858
+
4859
+ /**
4860
+ * Applies take/skip to the data source without triggering {@link AXDataSource.load}.
4861
+ */
4862
+ function applyDataSourcePagingWithoutLoad(dataSource, paging) {
4863
+ const take = Math.max(1, paging.take);
4864
+ const skip = Math.max(0, paging.skip);
4865
+ const page = Math.floor(skip / take);
4866
+ const ds = dataSource;
4867
+ dataSource.config.pageSize = take;
4868
+ if (ds._query) {
4869
+ ds._query.take = take;
4870
+ ds._query.skip = skip;
4871
+ }
4872
+ ds._page = page;
4873
+ }
4874
+ function getDataSourcePageIndex(dataSource) {
4875
+ const ds = dataSource;
4876
+ return ds._page ?? 0;
4877
+ }
4878
+ function normalizeListPaging(paging, defaultTake) {
4879
+ const take = typeof paging?.take === 'number' && paging.take > 0 ? paging.take : defaultTake;
4880
+ const skip = typeof paging?.skip === 'number' && paging.skip >= 0 ? paging.skip : 0;
4881
+ return { take, skip };
4882
+ }
4883
+
4884
+ const AXPEntityListPersistenceModeDefault = 'persistent';
4885
+ function normalizeEntityListPersistenceMode(value) {
4886
+ if (value === 'none' || value === 'persistent' || value === 'route') {
4887
+ return value;
4888
+ }
4889
+ return AXPEntityListPersistenceModeDefault;
4890
+ }
4891
+ function canPersistEntityListState(mode) {
4892
+ return mode !== 'none';
4893
+ }
4894
+ /** `none` never reads list state from user settings. */
4895
+ function shouldLoadEntityListStateFromStorage(mode) {
4896
+ return mode !== 'none';
4897
+ }
4898
+ /** `route` clears stored list state when the route entity (module + name) changes. */
4899
+ function shouldResetEntityListStateOnRouteEntry(mode) {
4900
+ return mode === 'route';
4901
+ }
4902
+ const ENTITY_LIST_ROUTE_CONTEXT_SESSION_KEY = 'axp-entity-list-route-context';
4903
+
4718
4904
  class AXPEntityCreateViewSectionViewModel {
4719
4905
  constructor(entity, section) {
4720
4906
  this.entity = entity;
@@ -7141,6 +7327,98 @@ const AXPEntityDetailViewModelResolver = (route, state, service = inject(AXPEnti
7141
7327
  return service.create(moduleName, entityName, id);
7142
7328
  };
7143
7329
 
7330
+ class AXPEntityPreloadFiltersViewModel {
7331
+ //#region ---- Constructor ----
7332
+ constructor(injector, config) {
7333
+ this.injector = injector;
7334
+ this.config = config;
7335
+ this.entityDef = cloneDeep(this.config);
7336
+ this.widgetResolver = this.injector.get(AXPWidgetRegistryService);
7337
+ //#endregion
7338
+ //#region ---- Computed Properties ----
7339
+ /**
7340
+ * Entity title
7341
+ */
7342
+ this.title = computed(() => {
7343
+ return this.entityDef.formats.plural ?? this.entityDef.title;
7344
+ }, ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
7345
+ /**
7346
+ * Entity description
7347
+ */
7348
+ this.description = computed(() => {
7349
+ return this.entityDef.interfaces?.master?.list?.description ?? null;
7350
+ }, ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
7351
+ /**
7352
+ * All filter definitions for properties with preload enabled
7353
+ */
7354
+ this.preloadFiltersDef = computed(() => {
7355
+ const props = this.entityDef.properties.filter((c) => c.options?.filter?.preload?.enabled);
7356
+ return props.map((e) => {
7357
+ const widgetConfig = this.widgetResolver.resolve(e.schema.interface?.type);
7358
+ const type = e.schema.interface?.type;
7359
+ // Merge validations with existing options
7360
+ const validations = e.options?.filter?.preload?.required
7361
+ ? [
7362
+ {
7363
+ rule: 'required',
7364
+ message: 'This field is required',
7365
+ options: {},
7366
+ },
7367
+ ]
7368
+ : [];
7369
+ const mergedOptions = {
7370
+ ...e.schema.interface?.options,
7371
+ validations,
7372
+ };
7373
+ return {
7374
+ title: e.title,
7375
+ field: e.name,
7376
+ operator: {
7377
+ type: 'contains',
7378
+ },
7379
+ widget: {
7380
+ ...e.schema.interface,
7381
+ path: e.name,
7382
+ type,
7383
+ options: mergedOptions,
7384
+ },
7385
+ filters: [],
7386
+ isParametric: false,
7387
+ icon: widgetConfig?.icon,
7388
+ filterType: {
7389
+ advance: false,
7390
+ inline: false,
7391
+ preload: e.options?.filter?.preload,
7392
+ },
7393
+ };
7394
+ });
7395
+ }, ...(ngDevMode ? [{ debugName: "preloadFiltersDef" }] : /* istanbul ignore next */ []));
7396
+ /**
7397
+ * Required filter definitions only
7398
+ */
7399
+ this.requiredFiltersDef = computed(() => {
7400
+ return this.preloadFiltersDef().filter((c) => c.filterType.preload?.required);
7401
+ }, ...(ngDevMode ? [{ debugName: "requiredFiltersDef" }] : /* istanbul ignore next */ []));
7402
+ }
7403
+ //#region ---- Methods ----
7404
+ /**
7405
+ * Serialize filter values to plain objects (remove signals, functions, etc.)
7406
+ */
7407
+ serializeFilters(filters) {
7408
+ return JSON.parse(JSON.stringify(filters));
7409
+ }
7410
+ }
7411
+ //#region ---- Resolver ----
7412
+ const AXPEntityPreloadFiltersViewModelResolver = async (route, state) => {
7413
+ const injector = inject(Injector);
7414
+ const entityRegistry = inject(AXPEntityDefinitionRegistryService);
7415
+ const moduleName = route.parent?.paramMap.get('module');
7416
+ const entityName = route.paramMap.get('entity');
7417
+ const entity = await entityRegistry.resolve(moduleName, entityName);
7418
+ return new AXPEntityPreloadFiltersViewModel(injector, entity);
7419
+ };
7420
+ //#endregion
7421
+
7144
7422
  //#endregion
7145
7423
  //#region ---- Quick search: schema-driven field paths ----
7146
7424
  const NON_TEXT_DATATYPES = new Set([
@@ -7285,98 +7563,6 @@ async function collectEntityQuickSearchFieldPaths(entity, resolveRelatedDefiniti
7285
7563
  }
7286
7564
  //#endregion
7287
7565
 
7288
- class AXPEntityPreloadFiltersViewModel {
7289
- //#region ---- Constructor ----
7290
- constructor(injector, config) {
7291
- this.injector = injector;
7292
- this.config = config;
7293
- this.entityDef = cloneDeep(this.config);
7294
- this.widgetResolver = this.injector.get(AXPWidgetRegistryService);
7295
- //#endregion
7296
- //#region ---- Computed Properties ----
7297
- /**
7298
- * Entity title
7299
- */
7300
- this.title = computed(() => {
7301
- return this.entityDef.formats.plural ?? this.entityDef.title;
7302
- }, ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
7303
- /**
7304
- * Entity description
7305
- */
7306
- this.description = computed(() => {
7307
- return this.entityDef.interfaces?.master?.list?.description ?? null;
7308
- }, ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
7309
- /**
7310
- * All filter definitions for properties with preload enabled
7311
- */
7312
- this.preloadFiltersDef = computed(() => {
7313
- const props = this.entityDef.properties.filter((c) => c.options?.filter?.preload?.enabled);
7314
- return props.map((e) => {
7315
- const widgetConfig = this.widgetResolver.resolve(e.schema.interface?.type);
7316
- const type = e.schema.interface?.type;
7317
- // Merge validations with existing options
7318
- const validations = e.options?.filter?.preload?.required
7319
- ? [
7320
- {
7321
- rule: 'required',
7322
- message: 'This field is required',
7323
- options: {},
7324
- },
7325
- ]
7326
- : [];
7327
- const mergedOptions = {
7328
- ...e.schema.interface?.options,
7329
- validations,
7330
- };
7331
- return {
7332
- title: e.title,
7333
- field: e.name,
7334
- operator: {
7335
- type: 'contains',
7336
- },
7337
- widget: {
7338
- ...e.schema.interface,
7339
- path: e.name,
7340
- type,
7341
- options: mergedOptions,
7342
- },
7343
- filters: [],
7344
- isParametric: false,
7345
- icon: widgetConfig?.icon,
7346
- filterType: {
7347
- advance: false,
7348
- inline: false,
7349
- preload: e.options?.filter?.preload,
7350
- },
7351
- };
7352
- });
7353
- }, ...(ngDevMode ? [{ debugName: "preloadFiltersDef" }] : /* istanbul ignore next */ []));
7354
- /**
7355
- * Required filter definitions only
7356
- */
7357
- this.requiredFiltersDef = computed(() => {
7358
- return this.preloadFiltersDef().filter((c) => c.filterType.preload?.required);
7359
- }, ...(ngDevMode ? [{ debugName: "requiredFiltersDef" }] : /* istanbul ignore next */ []));
7360
- }
7361
- //#region ---- Methods ----
7362
- /**
7363
- * Serialize filter values to plain objects (remove signals, functions, etc.)
7364
- */
7365
- serializeFilters(filters) {
7366
- return JSON.parse(JSON.stringify(filters));
7367
- }
7368
- }
7369
- //#region ---- Resolver ----
7370
- const AXPEntityPreloadFiltersViewModelResolver = async (route, state) => {
7371
- const injector = inject(Injector);
7372
- const entityRegistry = inject(AXPEntityDefinitionRegistryService);
7373
- const moduleName = route.parent?.paramMap.get('module');
7374
- const entityName = route.paramMap.get('entity');
7375
- const entity = await entityRegistry.resolve(moduleName, entityName);
7376
- return new AXPEntityPreloadFiltersViewModel(injector, entity);
7377
- };
7378
- //#endregion
7379
-
7380
7566
  //#region ---- Path / numeric helpers ----
7381
7567
  function getPath(obj, path) {
7382
7568
  if (obj == null || path.length === 0) {
@@ -7569,128 +7755,32 @@ async function filterSortEntityRows(entityName, request, adapters) {
7569
7755
  if (request.sort && request.sort.length) {
7570
7756
  result = applySortArray(result, request.sort);
7571
7757
  }
7572
- if (request.filter && isCategoryFilter(request.filter)) {
7573
- result = await applyRecursiveCategoryFilter(result, request.filter, entityName, adapters.getAllChildCategoryIds);
7574
- }
7575
- else {
7576
- result = applyFilterArray(result, request.filter ? [request.filter] : []);
7577
- }
7578
- if (isCategoryEntity(entityName)) {
7579
- result = await calculateChildrenCounts(result, entityName, adapters.getDirectChildCount);
7580
- }
7581
- return result;
7582
- }
7583
- /**
7584
- * Shared entity query logic: sort, filter (including recursive category filter), childrenCount, pagination.
7585
- */
7586
- async function runEntityQuery(entityName, request, adapters) {
7587
- const rows = await filterSortEntityRows(entityName, request, adapters);
7588
- const skip = request.skip ?? 0;
7589
- const take = request.take ?? 0;
7590
- return {
7591
- total: rows.length,
7592
- items: rows.slice(skip, skip + take),
7593
- };
7594
- }
7595
- //#endregion
7596
-
7597
- //#endregion
7598
-
7599
- //#region ---- Imports ----
7600
- //#endregion
7601
- //#region ---- Constants ----
7602
- const DEFAULT_RELATED_ORDER_STEP = 10;
7603
- const DEFAULT_PLUGIN_ZONE_FLOOR = 100_000;
7604
- /** Space per plugin slot so multiple fields in one slot do not cross into the next. */
7605
- const PLUGIN_SLOT_SPAN = 10_000;
7606
- const SUB_ORDER_STEP = 10;
7607
- const PLUGIN_SLOT_INDEX = {
7608
- 'meta-data-builder': 0,
7609
- attachments: 1,
7610
- documents: 2,
7611
- comments: 3,
7612
- history: 4,
7613
- };
7614
- //#endregion
7615
- //#region ---- Helpers ----
7616
- function shouldSkipPageForMax(page, skip) {
7617
- if (!skip) {
7618
- return false;
7619
- }
7620
- if (page.componentKey !== skip.componentKey) {
7621
- return false;
7622
- }
7623
- if (skip.field !== undefined) {
7624
- return page.field === skip.field;
7625
- }
7626
- return true;
7627
- }
7628
- function normalizeRelatedPageListDetailOrders(relatedEntities, step) {
7629
- const pageTabRelated = (relatedEntities ?? []).filter((re) => re.layout?.type === 'page-list' || re.layout?.type === 'page-detail');
7630
- let maxExplicit = 0;
7631
- for (const re of pageTabRelated) {
7632
- const o = re.layout?.order;
7633
- if (typeof o === 'number' && Number.isFinite(o)) {
7634
- maxExplicit = Math.max(maxExplicit, o);
7635
- }
7636
- }
7637
- let cursor = maxExplicit;
7638
- for (const re of pageTabRelated) {
7639
- const layout = re.layout;
7640
- if (!layout || layout.order != null) {
7641
- continue;
7642
- }
7643
- cursor += step;
7644
- re.layout = { ...layout, order: cursor };
7645
- }
7646
- let afterMax = 0;
7647
- for (const re of pageTabRelated) {
7648
- const o = re.layout?.order;
7649
- if (typeof o === 'number' && Number.isFinite(o)) {
7650
- afterMax = Math.max(afterMax, o);
7651
- }
7652
- }
7653
- return afterMax;
7654
- }
7655
- /**
7656
- * Ordinal within a slot for multi-field pages (attachments, meta-data-builder), stable by field name.
7657
- */
7658
- function subOrderWithinComponentSlot(pages, componentKey, skip, currentField) {
7659
- const peerFieldKeys = (pages ?? [])
7660
- .filter((p) => p.componentKey === componentKey && !shouldSkipPageForMax(p, skip))
7661
- .map((p) => p.field ?? '');
7662
- const keySet = new Set(peerFieldKeys);
7663
- keySet.add(currentField ?? '');
7664
- const sorted = [...keySet].sort((a, b) => a.localeCompare(b));
7665
- const index = sorted.indexOf(currentField ?? '');
7666
- return Math.max(0, index) * SUB_ORDER_STEP;
7758
+ if (request.filter && isCategoryFilter(request.filter)) {
7759
+ result = await applyRecursiveCategoryFilter(result, request.filter, entityName, adapters.getAllChildCategoryIds);
7760
+ }
7761
+ else {
7762
+ result = applyFilterArray(result, request.filter ? [request.filter] : []);
7763
+ }
7764
+ if (isCategoryEntity(entityName)) {
7765
+ result = await calculateChildrenCounts(result, entityName, adapters.getDirectChildCount);
7766
+ }
7767
+ return result;
7667
7768
  }
7668
- //#endregion
7669
- //#region ---- Public API ----
7670
7769
  /**
7671
- * Resolves `layout.order` for a built-in plugin detail tab (`entity.pages`).
7672
- *
7673
- * 1. Assigns finite `layout.order` values to related `page-list` / `page-detail` rows that omit
7674
- * `order` (the composer otherwise treats them as +Infinity).
7675
- * 2. Places plugin tabs in a fixed relative order: meta-data-builder → attachments → documents →
7676
- * comments → history, after all related tabs.
7770
+ * Shared entity query logic: sort, filter (including recursive category filter), childrenCount, pagination.
7677
7771
  */
7678
- function resolveEntityPluginDetailPageOrder(input, slot, options) {
7679
- const relatedStep = options.relatedOrderStep ?? DEFAULT_RELATED_ORDER_STEP;
7680
- const zoneFloor = options.pluginZoneFloor ?? DEFAULT_PLUGIN_ZONE_FLOOR;
7681
- const { componentKey, skipPage, field } = options;
7682
- const afterRelatedMax = normalizeRelatedPageListDetailOrders(input.relatedEntities, relatedStep);
7683
- const pluginZoneStart = Math.max(afterRelatedMax + relatedStep, zoneFloor);
7684
- const slotIndex = PLUGIN_SLOT_INDEX[slot];
7685
- const subOrder = subOrderWithinComponentSlot(input.pages, componentKey, skipPage, field);
7686
- return pluginZoneStart + slotIndex * PLUGIN_SLOT_SPAN + subOrder;
7772
+ async function runEntityQuery(entityName, request, adapters) {
7773
+ const rows = await filterSortEntityRows(entityName, request, adapters);
7774
+ const skip = request.skip ?? 0;
7775
+ const take = request.take ?? 0;
7776
+ return {
7777
+ total: rows.length,
7778
+ items: rows.slice(skip, skip + take),
7779
+ };
7687
7780
  }
7688
7781
  //#endregion
7689
7782
 
7690
- /**
7691
- * Re-export from domain to avoid circular dependency: layout/components must not depend on layout/entity.
7692
- * Consumers that only need the token/interface can import from @acorex/platform/domain.
7693
- */
7783
+ //#endregion
7694
7784
 
7695
7785
  /** Component key used when display is 'page'. Register a page component with this key via AXP_PAGE_COMPONENT_PROVIDER. */
7696
7786
  const ATTACHMENTS_PAGE_COMPONENT_KEY = 'entity-attachments-page';
@@ -7890,7 +7980,7 @@ class AXMAttachmentsPageComponentProvider {
7890
7980
  return [
7891
7981
  {
7892
7982
  key: ATTACHMENTS_PAGE_COMPONENT_KEY,
7893
- loader: () => import('./acorex-platform-layout-entity-attachments-page.component-BaTS183I.mjs').then((m) => m.AXMAttachmentsPageComponent),
7983
+ loader: () => import('./acorex-platform-layout-entity-attachments-page.component-D8iQnT-R.mjs').then((m) => m.AXMAttachmentsPageComponent),
7894
7984
  },
7895
7985
  ];
7896
7986
  }
@@ -13233,7 +13323,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
13233
13323
  ></ng-container>
13234
13324
  }
13235
13325
  </div>
13236
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "directive", type: i3.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i4$2.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13326
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "directive", type: i3.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i3$3.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13237
13327
  }
13238
13328
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityListWidgetViewComponent, decorators: [{
13239
13329
  type: Component,
@@ -13398,6 +13488,382 @@ const AXPEntityListWidget = {
13398
13488
  },
13399
13489
  };
13400
13490
 
13491
+ class AXPPageComponentWidgetViewComponent extends AXPBaseWidgetComponent {
13492
+ constructor() {
13493
+ super(...arguments);
13494
+ //#region ---- Services & Dependencies ----
13495
+ this.deviceService = inject(AXPDeviceService);
13496
+ this.pageRenderer = viewChild(AXPPageComponentRendererDirective, ...(ngDevMode ? [{ debugName: "pageRenderer" }] : /* istanbul ignore next */ []));
13497
+ //#endregion
13498
+ //#region ---- Computed Options ----
13499
+ this.componentKey = computed(() => this.options()['componentKey'], ...(ngDevMode ? [{ debugName: "componentKey" }] : /* istanbul ignore next */ []));
13500
+ this.pageConfig = computed(() => {
13501
+ const field = this.options()['field'];
13502
+ return typeof field === 'string' ? { field } : undefined;
13503
+ }, ...(ngDevMode ? [{ debugName: "pageConfig" }] : /* istanbul ignore next */ []));
13504
+ this.pageOptions = computed(() => this.options()['pageOptions'] ?? {}, ...(ngDevMode ? [{ debugName: "pageOptions" }] : /* istanbul ignore next */ []));
13505
+ this.rootContext = computed(() => this.contextService.snapshot(), ...(ngDevMode ? [{ debugName: "rootContext" }] : /* istanbul ignore next */ []));
13506
+ this.showPageActions = computed(() => this.options()['showPageActions'] ?? true, ...(ngDevMode ? [{ debugName: "showPageActions" }] : /* istanbul ignore next */ []));
13507
+ //#endregion
13508
+ //#region ---- Toolbar Actions ----
13509
+ this.toolbarPrimaryActions = signal([], ...(ngDevMode ? [{ debugName: "toolbarPrimaryActions" }] : /* istanbul ignore next */ []));
13510
+ this.toolbarSecondaryActions = signal([], ...(ngDevMode ? [{ debugName: "toolbarSecondaryActions" }] : /* istanbul ignore next */ []));
13511
+ /** Bumped when the embedded page finishes async mount so toolbar can bind to the live instance. */
13512
+ this.pageHostRevision = signal(0, ...(ngDevMode ? [{ debugName: "pageHostRevision" }] : /* istanbul ignore next */ []));
13513
+ /** Keeps the toolbar in sync when the embedded page calls `recompute()` (e.g. dirty state). */
13514
+ this.#syncPageActionsEffect = effect(() => {
13515
+ this.pageHostRevision();
13516
+ this.componentKey();
13517
+ const instance = this.resolvePageHost();
13518
+ if (!instance) {
13519
+ return;
13520
+ }
13521
+ instance.primaryMenuItems();
13522
+ instance.secondaryMenuItems();
13523
+ console.log({ primaryMenuItems: instance.primaryMenuItems(), secondaryMenuItems: instance.secondaryMenuItems() });
13524
+ untracked(() => this.syncActionsFromPageInstance(instance));
13525
+ }, ...(ngDevMode ? [{ debugName: "#syncPageActionsEffect" }] : /* istanbul ignore next */ []));
13526
+ }
13527
+ /** Keeps the toolbar in sync when the embedded page calls `recompute()` (e.g. dirty state). */
13528
+ #syncPageActionsEffect;
13529
+ //#endregion
13530
+ //#region ---- Lifecycle ----
13531
+ ngOnInit() {
13532
+ super.ngOnInit();
13533
+ const widgetName = this.name;
13534
+ if (widgetName) {
13535
+ this.layoutService.registerWidget(widgetName, this);
13536
+ }
13537
+ this.setStatus(AXPWidgetStatus.Rendered);
13538
+ }
13539
+ //#endregion
13540
+ //#region ---- Public API ----
13541
+ api() {
13542
+ const self = this;
13543
+ return {
13544
+ syncContext: () => {
13545
+ self.syncPageComponentIntoFormContext();
13546
+ },
13547
+ refreshPageActions: () => {
13548
+ self.refreshPageActions();
13549
+ },
13550
+ };
13551
+ }
13552
+ /** Re-reads toolbar actions from the mounted page component. */
13553
+ refreshPageActions() {
13554
+ const instance = this.resolvePageHost();
13555
+ if (!instance) {
13556
+ this.toolbarPrimaryActions.set([]);
13557
+ this.toolbarSecondaryActions.set([]);
13558
+ return;
13559
+ }
13560
+ this.syncActionsFromPageInstance(instance);
13561
+ }
13562
+ //#endregion
13563
+ //#region ---- UI Handlers ----
13564
+ handleComponentReady() {
13565
+ this.pageHostRevision.update((value) => value + 1);
13566
+ }
13567
+ async handleActionClick(item) {
13568
+ if (!item.command || (item.items?.length ?? 0) > 0) {
13569
+ return;
13570
+ }
13571
+ const instance = this.resolvePageHost();
13572
+ if (!instance) {
13573
+ return;
13574
+ }
13575
+ const command = normalizeExecuteCommand(item.command);
13576
+ await instance.execute(command);
13577
+ this.pageHostRevision.update((value) => value + 1);
13578
+ }
13579
+ //#endregion
13580
+ //#region ---- Context Sync ----
13581
+ /** Merges the mounted page component's wizard payload into the dialog form context. */
13582
+ syncPageComponentIntoFormContext() {
13583
+ const partial = this.resolvePageHost()?.getWizardStepContext?.();
13584
+ if (!partial) {
13585
+ return;
13586
+ }
13587
+ for (const [path, value] of Object.entries(partial)) {
13588
+ this.contextService.update(path, value);
13589
+ }
13590
+ }
13591
+ //#endregion
13592
+ //#region ---- Utility Methods ----
13593
+ resolvePageHost() {
13594
+ const instance = this.pageRenderer()?.getMountedPageInstance();
13595
+ return isPageToolbarHost(instance) ? instance : null;
13596
+ }
13597
+ syncActionsFromPageInstance(page) {
13598
+ const primary = page.primaryMenuItems();
13599
+ const secondary = page.secondaryMenuItems();
13600
+ this.toolbarPrimaryActions.set(splitToolbarPrimaryActions(primary));
13601
+ this.toolbarSecondaryActions.set(splitToolbarSecondaryActions(primary, secondary));
13602
+ }
13603
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPageComponentWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
13604
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPPageComponentWidgetViewComponent, isStandalone: true, selector: "axp-page-component-widget-view", host: { classAttribute: "ax-block ax-w-full ax-h-full ax-min-h-0" }, viewQueries: [{ propertyName: "pageRenderer", first: true, predicate: AXPPageComponentRendererDirective, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
13605
+ @if (showPageActions() && (toolbarPrimaryActions().length || toolbarSecondaryActions().length)) {
13606
+ <div class="ax-flex ax-flex-wrap ax-gap-2 ax-justify-end ax-mb-4">
13607
+ @for (action of toolbarPrimaryActions(); track action.title) {
13608
+ @if (action.visible !== false) {
13609
+ <ax-button
13610
+ [class.ax-sm]="deviceService.isSmall()"
13611
+ [iconOnly]="deviceService.isSmall()"
13612
+ [disabled]="action.disabled"
13613
+ [text]="(action.title | translate | async)!"
13614
+ [look]="'solid'"
13615
+ [color]="action.color ?? 'default'"
13616
+ (onClick)="handleActionClick(action)"
13617
+ >
13618
+ <ax-prefix>
13619
+ <i [class]="action.icon"></i>
13620
+ </ax-prefix>
13621
+ @if (action.items?.length) {
13622
+ <ax-dropdown-panel #panel>
13623
+ <ax-button-item-list>
13624
+ @for (sub of action.items; track sub.title) {
13625
+ @if (sub.visible !== false) {
13626
+ <ax-button-item
13627
+ [text]="(sub.title | translate | async)!"
13628
+ [color]="sub.color"
13629
+ [disabled]="sub.disabled"
13630
+ (onClick)="handleActionClick(sub)"
13631
+ >
13632
+ <ax-prefix>
13633
+ <i [class]="sub.icon"></i>
13634
+ </ax-prefix>
13635
+ </ax-button-item>
13636
+ @if (sub.break) {
13637
+ <ax-divider></ax-divider>
13638
+ }
13639
+ }
13640
+ }
13641
+ </ax-button-item-list>
13642
+ </ax-dropdown-panel>
13643
+ }
13644
+ </ax-button>
13645
+ }
13646
+ }
13647
+ @if (toolbarSecondaryActions().length) {
13648
+ <ax-button
13649
+ [class.ax-sm]="deviceService.isSmall()"
13650
+ [iconOnly]="deviceService.isSmall()"
13651
+ [text]="'@general:terms.interface.actions' | translate | async"
13652
+ [look]="deviceService.isSmall() ? 'blank' : 'solid'"
13653
+ [color]="'default'"
13654
+ >
13655
+ <ax-prefix>
13656
+ <i class="fa-solid fa-ellipsis-vertical"></i>
13657
+ </ax-prefix>
13658
+ <ax-dropdown-panel #panel>
13659
+ <ax-button-item-list>
13660
+ @for (item of toolbarSecondaryActions(); track item.title) {
13661
+ @if (item.visible !== false) {
13662
+ <ax-button-item
13663
+ [text]="(item.title | translate | async)!"
13664
+ [color]="item.color"
13665
+ [disabled]="item.disabled"
13666
+ (onClick)="handleActionClick(item)"
13667
+ >
13668
+ <ax-prefix>
13669
+ <i [class]="item.icon"></i>
13670
+ </ax-prefix>
13671
+ </ax-button-item>
13672
+ @if (item.break) {
13673
+ <ax-divider></ax-divider>
13674
+ }
13675
+ }
13676
+ }
13677
+ </ax-button-item-list>
13678
+ </ax-dropdown-panel>
13679
+ </ax-button>
13680
+ }
13681
+ </div>
13682
+ }
13683
+ <div
13684
+ class="ax-w-full ax-min-h-0"
13685
+ axp-page-component-renderer
13686
+ [componentKey]="componentKey()"
13687
+ [rootContext]="rootContext()"
13688
+ [pageConfig]="pageConfig()"
13689
+ [options]="pageOptions()"
13690
+ (componentReady)="handleComponentReady()"
13691
+ ></div>
13692
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "directive", type: AXPPageComponentRendererDirective, selector: "[axp-page-component-renderer]", inputs: ["componentKey", "rootContext", "pageConfig", "options"], outputs: ["componentReady"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i3$3.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13693
+ }
13694
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPageComponentWidgetViewComponent, decorators: [{
13695
+ type: Component,
13696
+ args: [{
13697
+ selector: 'axp-page-component-widget-view',
13698
+ host: {
13699
+ class: 'ax-block ax-w-full ax-h-full ax-min-h-0',
13700
+ },
13701
+ template: `
13702
+ @if (showPageActions() && (toolbarPrimaryActions().length || toolbarSecondaryActions().length)) {
13703
+ <div class="ax-flex ax-flex-wrap ax-gap-2 ax-justify-end ax-mb-4">
13704
+ @for (action of toolbarPrimaryActions(); track action.title) {
13705
+ @if (action.visible !== false) {
13706
+ <ax-button
13707
+ [class.ax-sm]="deviceService.isSmall()"
13708
+ [iconOnly]="deviceService.isSmall()"
13709
+ [disabled]="action.disabled"
13710
+ [text]="(action.title | translate | async)!"
13711
+ [look]="'solid'"
13712
+ [color]="action.color ?? 'default'"
13713
+ (onClick)="handleActionClick(action)"
13714
+ >
13715
+ <ax-prefix>
13716
+ <i [class]="action.icon"></i>
13717
+ </ax-prefix>
13718
+ @if (action.items?.length) {
13719
+ <ax-dropdown-panel #panel>
13720
+ <ax-button-item-list>
13721
+ @for (sub of action.items; track sub.title) {
13722
+ @if (sub.visible !== false) {
13723
+ <ax-button-item
13724
+ [text]="(sub.title | translate | async)!"
13725
+ [color]="sub.color"
13726
+ [disabled]="sub.disabled"
13727
+ (onClick)="handleActionClick(sub)"
13728
+ >
13729
+ <ax-prefix>
13730
+ <i [class]="sub.icon"></i>
13731
+ </ax-prefix>
13732
+ </ax-button-item>
13733
+ @if (sub.break) {
13734
+ <ax-divider></ax-divider>
13735
+ }
13736
+ }
13737
+ }
13738
+ </ax-button-item-list>
13739
+ </ax-dropdown-panel>
13740
+ }
13741
+ </ax-button>
13742
+ }
13743
+ }
13744
+ @if (toolbarSecondaryActions().length) {
13745
+ <ax-button
13746
+ [class.ax-sm]="deviceService.isSmall()"
13747
+ [iconOnly]="deviceService.isSmall()"
13748
+ [text]="'@general:terms.interface.actions' | translate | async"
13749
+ [look]="deviceService.isSmall() ? 'blank' : 'solid'"
13750
+ [color]="'default'"
13751
+ >
13752
+ <ax-prefix>
13753
+ <i class="fa-solid fa-ellipsis-vertical"></i>
13754
+ </ax-prefix>
13755
+ <ax-dropdown-panel #panel>
13756
+ <ax-button-item-list>
13757
+ @for (item of toolbarSecondaryActions(); track item.title) {
13758
+ @if (item.visible !== false) {
13759
+ <ax-button-item
13760
+ [text]="(item.title | translate | async)!"
13761
+ [color]="item.color"
13762
+ [disabled]="item.disabled"
13763
+ (onClick)="handleActionClick(item)"
13764
+ >
13765
+ <ax-prefix>
13766
+ <i [class]="item.icon"></i>
13767
+ </ax-prefix>
13768
+ </ax-button-item>
13769
+ @if (item.break) {
13770
+ <ax-divider></ax-divider>
13771
+ }
13772
+ }
13773
+ }
13774
+ </ax-button-item-list>
13775
+ </ax-dropdown-panel>
13776
+ </ax-button>
13777
+ }
13778
+ </div>
13779
+ }
13780
+ <div
13781
+ class="ax-w-full ax-min-h-0"
13782
+ axp-page-component-renderer
13783
+ [componentKey]="componentKey()"
13784
+ [rootContext]="rootContext()"
13785
+ [pageConfig]="pageConfig()"
13786
+ [options]="pageOptions()"
13787
+ (componentReady)="handleComponentReady()"
13788
+ ></div>
13789
+ `,
13790
+ changeDetection: ChangeDetectionStrategy.OnPush,
13791
+ imports: [
13792
+ AXPWidgetCoreModule,
13793
+ AXPPageComponentRendererDirective,
13794
+ AXButtonModule,
13795
+ AXDecoratorModule,
13796
+ AXDropdownModule,
13797
+ AXTranslationModule,
13798
+ AsyncPipe,
13799
+ ],
13800
+ }]
13801
+ }], propDecorators: { pageRenderer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPPageComponentRendererDirective), { isSignal: true }] }] } });
13802
+ function isPageToolbarHost(instance) {
13803
+ return (!!instance &&
13804
+ typeof instance === 'object' &&
13805
+ 'primaryMenuItems' in instance &&
13806
+ 'secondaryMenuItems' in instance &&
13807
+ typeof instance.execute === 'function');
13808
+ }
13809
+ function splitToolbarPrimaryActions(actions) {
13810
+ return actions.filter((action) => action.visible !== false && isHeaderZoneAction(action) && getActionPriority(action) === 'primary');
13811
+ }
13812
+ function splitToolbarSecondaryActions(primary, secondary) {
13813
+ const fromPrimary = primary.filter((action) => action.visible !== false && isHeaderZoneAction(action) && getActionPriority(action) === 'secondary');
13814
+ const fromSecondary = secondary.filter((action) => action.visible !== false && isHeaderZoneAction(action));
13815
+ return [...fromPrimary, ...fromSecondary];
13816
+ }
13817
+ function isHeaderZoneAction(action) {
13818
+ return action.zone === 'header';
13819
+ }
13820
+ function getActionPriority(action) {
13821
+ const priority = action.priority;
13822
+ return priority === 'secondary' ? 'secondary' : 'primary';
13823
+ }
13824
+ function normalizeExecuteCommand(command) {
13825
+ if (command == null) {
13826
+ return { name: '', options: {} };
13827
+ }
13828
+ if (typeof command === 'string') {
13829
+ return { name: command, options: {} };
13830
+ }
13831
+ return {
13832
+ name: command.name,
13833
+ options: command.options ?? {},
13834
+ };
13835
+ }
13836
+
13837
+ var pageComponentWidgetView_component = /*#__PURE__*/Object.freeze({
13838
+ __proto__: null,
13839
+ AXPPageComponentWidgetViewComponent: AXPPageComponentWidgetViewComponent
13840
+ });
13841
+
13842
+ const AXPPageComponentWidget = {
13843
+ name: 'page-component',
13844
+ title: 'Page Component',
13845
+ description: 'Renders a registered page component via page-component-renderer and exposes its toolbar actions',
13846
+ type: 'view',
13847
+ categories: [],
13848
+ groups: [AXPWidgetGroupEnum.FormElement],
13849
+ icon: 'fa-light fa-file-lines',
13850
+ properties: [AXP_NAME_PROPERTY],
13851
+ components: {
13852
+ view: {
13853
+ component: () => Promise.resolve().then(function () { return pageComponentWidgetView_component; }).then((c) => c.AXPPageComponentWidgetViewComponent),
13854
+ },
13855
+ edit: {
13856
+ component: () => Promise.resolve().then(function () { return pageComponentWidgetView_component; }).then((c) => c.AXPPageComponentWidgetViewComponent),
13857
+ },
13858
+ print: {
13859
+ component: () => Promise.resolve().then(function () { return pageComponentWidgetView_component; }).then((c) => c.AXPPageComponentWidgetViewComponent),
13860
+ },
13861
+ designer: {
13862
+ component: () => Promise.resolve().then(function () { return pageComponentWidgetView_component; }).then((c) => c.AXPPageComponentWidgetViewComponent),
13863
+ },
13864
+ },
13865
+ };
13866
+
13401
13867
  class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
13402
13868
  constructor() {
13403
13869
  super(...arguments);
@@ -19108,7 +19574,7 @@ class AXPFileUploaderWidgetEditComponent extends AXPValueWidgetComponent {
19108
19574
  (onRename)="handleFileRename($event)"
19109
19575
  ></axp-file-list>
19110
19576
  </div>
19111
- `, isInline: true, styles: [":host{border-color:rgba(var(--ax-comp-editor-border-color))}:host.axp-file-uploader-widget-edit--borderless{border:none!important}.__drag-over{background-color:rgba(var(--ax-sys-color-primary-50),.1);border:2px dashed rgb(var(--ax-sys-color-primary-500));border-radius:.375rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "directive", type: AXUploaderZoneDirective, selector: "[axUploaderZone]", inputs: ["multiple", "accept", "overlayTemplate", "disableBrowse", "disableDragDrop"], outputs: ["fileChange", "onChanged", "dragEnter", "dragLeave", "dragOver", "onFileUploadComplete", "onFilesUploadComplete"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i4$2.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXPComponentSlotModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i6.AXTranslatorDirective, selector: "[translate]" }, { kind: "component", type: AXPFileListComponent, selector: "axp-file-list", inputs: ["readonly", "fileEditable", "enableTitleDescription", "multiple", "files", "plugins", "excludePlugins", "capabilities"], outputs: ["onRemove", "onRevert", "onRename"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
19577
+ `, isInline: true, styles: [":host{border-color:rgba(var(--ax-comp-editor-border-color))}:host.axp-file-uploader-widget-edit--borderless{border:none!important}.__drag-over{background-color:rgba(var(--ax-sys-color-primary-50),.1);border:2px dashed rgb(var(--ax-sys-color-primary-500));border-radius:.375rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "directive", type: AXUploaderZoneDirective, selector: "[axUploaderZone]", inputs: ["multiple", "accept", "overlayTemplate", "disableBrowse", "disableDragDrop"], outputs: ["fileChange", "onChanged", "dragEnter", "dragLeave", "dragOver", "onFileUploadComplete", "onFilesUploadComplete"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i3$3.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXPComponentSlotModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i6.AXTranslatorDirective, selector: "[translate]" }, { kind: "component", type: AXPFileListComponent, selector: "axp-file-list", inputs: ["readonly", "fileEditable", "enableTitleDescription", "multiple", "files", "plugins", "excludePlugins", "capabilities"], outputs: ["onRemove", "onRevert", "onRename"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
19112
19578
  }
19113
19579
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPFileUploaderWidgetEditComponent, decorators: [{
19114
19580
  type: Component,
@@ -20166,7 +20632,7 @@ class AXPSelectorStructureWidgetEditComponent extends AXPValueWidgetComponent {
20166
20632
  } @else {
20167
20633
  <span class="ax-text-muted">{{ disabledHint() }}</span>
20168
20634
  }
20169
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i2$2.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "itemHeight", "maxVisibleItems", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed", "onItemSelected", "onItemClick"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i5$1.AXFormFieldComponent, selector: "ax-form-field", inputs: ["labelMode"] }, { kind: "ngmodule", type: AXCollapseModule }, { kind: "component", type: i4$3.AXCollapseComponent, selector: "ax-collapse", inputs: ["disabled", "look", "isCollapsed", "showHeader", "caption", "icon", "isLoading", "headerTemplate"], outputs: ["onClick", "isCollapsedChange"] }, { kind: "component", type: i4$3.AXCollapseGroupComponent, selector: "ax-collapse-group", inputs: ["look", "accordion", "activeIndex"], outputs: ["accordionChange", "activeIndexChange"] }, { kind: "ngmodule", type: AXLabelModule }, { kind: "component", type: i5$2.AXLabelComponent, selector: "ax-label", inputs: ["required", "for"], outputs: ["requiredChange"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i3.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i3.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "component", type: i7.AXTextBoxComponent, selector: "ax-text-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "maxLength", "allowNull", "type", "autoComplete", "look", "maskPattern", "customTokens", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onMaskChanged"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20635
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i2$2.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "itemHeight", "maxVisibleItems", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed", "onItemSelected", "onItemClick"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i5$1.AXFormFieldComponent, selector: "ax-form-field", inputs: ["labelMode"] }, { kind: "ngmodule", type: AXCollapseModule }, { kind: "component", type: i4$2.AXCollapseComponent, selector: "ax-collapse", inputs: ["disabled", "look", "isCollapsed", "showHeader", "caption", "icon", "isLoading", "headerTemplate"], outputs: ["onClick", "isCollapsedChange"] }, { kind: "component", type: i4$2.AXCollapseGroupComponent, selector: "ax-collapse-group", inputs: ["look", "accordion", "activeIndex"], outputs: ["accordionChange", "activeIndexChange"] }, { kind: "ngmodule", type: AXLabelModule }, { kind: "component", type: i5$2.AXLabelComponent, selector: "ax-label", inputs: ["required", "for"], outputs: ["requiredChange"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i3.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i3.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "component", type: i7.AXTextBoxComponent, selector: "ax-text-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "maxLength", "allowNull", "type", "autoComplete", "look", "maskPattern", "customTokens", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onMaskChanged"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$1.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20170
20636
  }
20171
20637
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPSelectorStructureWidgetEditComponent, decorators: [{
20172
20638
  type: Component,
@@ -20576,6 +21042,7 @@ const ENTITY_WIDGETS = [
20576
21042
  AXPLookupWidget,
20577
21043
  AXPSelectorStructureWidget,
20578
21044
  AXPEntityListWidget,
21045
+ AXPPageComponentWidget,
20579
21046
  AXPEntityCategoryWidget,
20580
21047
  AXPMultiSourceSelectorWidget,
20581
21048
  AXPEntityDefinitionProviderWidget,
@@ -22669,7 +23136,7 @@ class AXPLayoutAdapterFactory {
22669
23136
  const title = await dependencies.expressionEvaluator.evaluate(titleTemplate, scope);
22670
23137
  return title;
22671
23138
  }
22672
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutAdapterFactory, deps: [{ token: AXPRelatedEntityConverterFactory }, { token: AXPMainEntityContentBuilder }, { token: AXPLayoutAdapterBuilder }, { token: i4$4.AXPFilterOperatorMiddlewareService }], target: i0.ɵɵFactoryTarget.Injectable }); }
23139
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutAdapterFactory, deps: [{ token: AXPRelatedEntityConverterFactory }, { token: AXPMainEntityContentBuilder }, { token: AXPLayoutAdapterBuilder }, { token: i4$3.AXPFilterOperatorMiddlewareService }], target: i0.ɵɵFactoryTarget.Injectable }); }
22673
23140
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutAdapterFactory, providedIn: 'root' }); }
22674
23141
  }
22675
23142
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutAdapterFactory, decorators: [{
@@ -22677,7 +23144,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
22677
23144
  args: [{
22678
23145
  providedIn: 'root',
22679
23146
  }]
22680
- }], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }, { type: AXPMainEntityContentBuilder }, { type: AXPLayoutAdapterBuilder }, { type: i4$4.AXPFilterOperatorMiddlewareService }] });
23147
+ }], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }, { type: AXPMainEntityContentBuilder }, { type: AXPLayoutAdapterBuilder }, { type: i4$3.AXPFilterOperatorMiddlewareService }] });
22681
23148
 
22682
23149
  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)) => {
22683
23150
  const moduleName = route.parent?.paramMap.get('module');