@acorex/platform 20.2.4-next.9 → 20.3.0-next.0

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.
@@ -14,7 +14,7 @@ import { AXPPageStatus, AXPWidgetRegistryService, AXPWidgetsCatalog, AXPValueWid
14
14
  import { AXPLayoutThemeService } from '@acorex/platform/themes/shared';
15
15
  import { Subject, takeUntil } from 'rxjs';
16
16
  import { AXPSessionService, AXPAuthGuard } from '@acorex/platform/auth';
17
- import { AXPCommandService } from '@acorex/platform/runtime';
17
+ import { AXPCommandService, provideCommandSetups } from '@acorex/platform/runtime';
18
18
  import * as i8 from '@acorex/core/translation';
19
19
  import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
20
20
  import { AXDialogService } from '@acorex/components/dialog';
@@ -2576,6 +2576,10 @@ class AXPLayoutAdapterBuilder {
2576
2576
  this.adapter.pages = pages;
2577
2577
  return this;
2578
2578
  }
2579
+ setExitUrl(params) {
2580
+ this.adapter.exitUrl = `/${params.applicationName}/m/${params.moduleName}/e/${params.entityName}/list`;
2581
+ return this;
2582
+ }
2579
2583
  build() {
2580
2584
  return {
2581
2585
  name: `${this.entity?.module}.${this.entity?.name}`,
@@ -2586,6 +2590,7 @@ class AXPLayoutAdapterBuilder {
2586
2590
  execute: this.createExecuteFunction(),
2587
2591
  load: this.createLoadFunction(),
2588
2592
  pages: this.adapter.pages || [],
2593
+ exitUrl: this.adapter.exitUrl,
2589
2594
  };
2590
2595
  }
2591
2596
  createBreadcrumbs() {
@@ -3177,7 +3182,27 @@ class AXPMainEntityContentBuilder {
3177
3182
  const singleInterface = entity?.interfaces?.master?.single;
3178
3183
  // Accumulate groups from main and merge-detail related entities for validation/title lookup
3179
3184
  const allGroups = [...groups];
3185
+ // Create expression evaluator for actions
3186
+ const evaluateExpressions = dependencies?.expressionEvaluator
3187
+ ? this.createExpressionEvaluator(rootContext, dependencies.expressionEvaluator)
3188
+ : null;
3180
3189
  // Prepare merge-details structures (sections and properties per section)
3190
+ if (entity?.relatedEntities && evaluateExpressions) {
3191
+ // Only evaluate the 'hidden' property for each related entity
3192
+ entity.relatedEntities = await Promise.all(entity.relatedEntities.map(async (re) => {
3193
+ let hidden = re.hidden;
3194
+ if (hidden && typeof hidden === 'string') {
3195
+ try {
3196
+ const result = await evaluateExpressions({ hidden });
3197
+ hidden = result.hidden;
3198
+ }
3199
+ catch {
3200
+ // Keep original hidden if evaluation fails
3201
+ }
3202
+ }
3203
+ return { ...re, hidden };
3204
+ }));
3205
+ }
3181
3206
  const mergeDetailEntities = entity?.relatedEntities?.filter((re) => !re.hidden && re.layout?.type === 'merge-detail');
3182
3207
  const mainPropsByGroup = (entity?.properties ?? []).reduce((acc, p) => {
3183
3208
  if (!acc[p.groupId])
@@ -3408,10 +3433,6 @@ class AXPMainEntityContentBuilder {
3408
3433
  console.debug('[AXP] merge-details sorted sections', debugSections);
3409
3434
  }
3410
3435
  catch { }
3411
- // Create expression evaluator for actions
3412
- const evaluateExpressions = dependencies?.expressionEvaluator
3413
- ? this.createExpressionEvaluator(rootContext, dependencies.expressionEvaluator)
3414
- : null;
3415
3436
  const getVisiblePropertyByGroupId = async (groupId) => {
3416
3437
  return (mergedPropsByGroup[groupId] ?? []);
3417
3438
  };
@@ -3456,7 +3477,13 @@ class AXPMainEntityContentBuilder {
3456
3477
  },
3457
3478
  },
3458
3479
  },
3459
- load: async () => {
3480
+ load: async (params) => {
3481
+ if (params?.forceRefresh) {
3482
+ return {
3483
+ success: true,
3484
+ result: await dependencies.reloadRootContext(),
3485
+ };
3486
+ }
3460
3487
  return {
3461
3488
  success: true,
3462
3489
  result: rootContext,
@@ -3547,7 +3574,7 @@ class AXPMainEntityContentBuilder {
3547
3574
  title: allGroups.find((g) => g.id === s.id)?.title ?? '',
3548
3575
  collapsible: true,
3549
3576
  isOpen: !s.collapsed,
3550
- look: 'card'
3577
+ look: 'card',
3551
3578
  },
3552
3579
  children: [
3553
3580
  {
@@ -3736,22 +3763,24 @@ class AXPLayoutAdapterFactory {
3736
3763
  }
3737
3764
  const rootContext = await this.loadRootContext(entity, id);
3738
3765
  // Build main and related pages
3739
- const mainPage = await this.buildMainPage(entity, rootContext, dependencies);
3766
+ const mainPage = await this.buildMainPage(entity, rootContext, id, dependencies);
3740
3767
  const relatedPages = await this.buildRelatedPages(entity, rootContext, dependencies);
3741
3768
  // Compose ordered pages around the primary page
3742
3769
  const orderedPages = this.composePagesWithPositions(mainPage, relatedPages, entity);
3770
+ const applicationName = dependencies.session.application?.name ?? 'default';
3743
3771
  return this.layoutAdapterBuilder
3744
3772
  .setEntity(entity, rootContext)
3745
3773
  .setDependencies(dependencies)
3746
3774
  .setPages(orderedPages)
3775
+ .setExitUrl({ moduleName, entityName, applicationName })
3747
3776
  .build();
3748
3777
  }
3749
3778
  async loadRootContext(entity, id) {
3750
3779
  const fn = entity?.queries.byKey?.execute;
3751
3780
  return await fn(id);
3752
3781
  }
3753
- async buildMainPage(entity, rootContext, dependencies) {
3754
- return this.mainEntityContentBuilder.build(entity, rootContext, dependencies, await this.getRootTitle(entity, rootContext, dependencies));
3782
+ async buildMainPage(entity, rootContext, id, dependencies) {
3783
+ return this.mainEntityContentBuilder.build(entity, rootContext, { ...dependencies, reloadRootContext: () => this.loadRootContext(entity, id) }, await this.getRootTitle(entity, rootContext, dependencies));
3755
3784
  }
3756
3785
  async buildRelatedPages(entity, rootContext, dependencies) {
3757
3786
  const pages = [];
@@ -3877,6 +3906,57 @@ const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver =
3877
3906
  return await layoutAdapterFactory.createDetailsViewAdapter(entityResolver, moduleName, entityName, id, dependencies);
3878
3907
  };
3879
3908
 
3909
+ /**
3910
+ * Default widths for common text columns
3911
+ */
3912
+ const DEFAULT_COLUMN_WIDTHS = {
3913
+ title: '250px',
3914
+ description: '500px',
3915
+ note: '350px',
3916
+ notes: '350px',
3917
+ content: '500px'
3918
+ };
3919
+ /**
3920
+ * Factory to create a column width middleware using provided config map.
3921
+ * Sets width for columns defined in the map if not already defined on the column.
3922
+ */
3923
+ const columnWidthMiddlewareFactory = (widths) => {
3924
+ return (context) => {
3925
+ const columns = context.columns.list();
3926
+ if (!columns) {
3927
+ return;
3928
+ }
3929
+ columns.forEach((column) => {
3930
+ const desiredWidth = widths[column.name];
3931
+ if (desiredWidth && !column.options?.width) {
3932
+ const normalizedWidth = typeof desiredWidth === 'number' ? `${desiredWidth}px` : desiredWidth;
3933
+ context.columns.find(column.name).update((col) => ({
3934
+ ...col,
3935
+ options: {
3936
+ ...col.options,
3937
+ width: normalizedWidth
3938
+ }
3939
+ }));
3940
+ }
3941
+ });
3942
+ };
3943
+ };
3944
+ //#endregion
3945
+ //#region ---- Provider Registration ----
3946
+ /**
3947
+ * Helper to create a provider for the column width middleware.
3948
+ * By default it applies to all entities using the '*' pattern.
3949
+ */
3950
+ const createColumnWidthMiddlewareProvider = (widths, entityName = '*') => ({
3951
+ entityName,
3952
+ modifier: columnWidthMiddlewareFactory(widths)
3953
+ });
3954
+ /**
3955
+ * Default provider registered with the default map.
3956
+ */
3957
+ const columnWidthMiddlewareProvider = createColumnWidthMiddlewareProvider(DEFAULT_COLUMN_WIDTHS);
3958
+ //#endregion
3959
+
3880
3960
  class AXPEntityCommandSearchDefinitionProvider {
3881
3961
  async provide(context) {
3882
3962
  context.addDefinition('command', 'Commands', 'command', 'fa-solid fa-command', 1, {
@@ -5399,7 +5479,6 @@ class AXPLookupWidgetSelectorViewModel {
5399
5479
  const hasParentFilters = (this.options.parentFilters?.filters?.length ?? 0) > 0;
5400
5480
  // Construct the filters array based on the presence of filters
5401
5481
  const filters = [];
5402
- console.log(this.options.customFilter);
5403
5482
  if (this.options.customFilter) {
5404
5483
  const cleanedFilters = AXPCleanNestedFilters([this.options.customFilter]);
5405
5484
  if (cleanedFilters.length > 0) {
@@ -5683,6 +5762,13 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
5683
5762
  <ax-search-box>
5684
5763
  <ax-clear-button></ax-clear-button>
5685
5764
  </ax-search-box>
5765
+ @for (validation of validationRules(); track $index) {
5766
+ <ax-validation-rule
5767
+ [rule]="validation.rule"
5768
+ [message]="validation.options?.message"
5769
+ [options]="validation.options"
5770
+ ></ax-validation-rule>
5771
+ }
5686
5772
  @if (allowClear()) {
5687
5773
  <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5688
5774
  }
@@ -5751,6 +5837,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
5751
5837
  <ax-search-box>
5752
5838
  <ax-clear-button></ax-clear-button>
5753
5839
  </ax-search-box>
5840
+ @for (validation of validationRules(); track $index) {
5841
+ <ax-validation-rule
5842
+ [rule]="validation.rule"
5843
+ [message]="validation.options?.message"
5844
+ [options]="validation.options"
5845
+ ></ax-validation-rule>
5846
+ }
5754
5847
  @if (allowClear()) {
5755
5848
  <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5756
5849
  }
@@ -6813,57 +6906,6 @@ const AXPShowListViewWorkflow = {
6813
6906
  },
6814
6907
  };
6815
6908
 
6816
- /**
6817
- * Default widths for common text columns
6818
- */
6819
- const DEFAULT_COLUMN_WIDTHS = {
6820
- title: '250px',
6821
- description: '500px',
6822
- note: '350px',
6823
- notes: '350px',
6824
- content: '500px'
6825
- };
6826
- /**
6827
- * Factory to create a column width middleware using provided config map.
6828
- * Sets width for columns defined in the map if not already defined on the column.
6829
- */
6830
- const columnWidthMiddlewareFactory = (widths) => {
6831
- return (context) => {
6832
- const columns = context.columns.list();
6833
- if (!columns) {
6834
- return;
6835
- }
6836
- columns.forEach((column) => {
6837
- const desiredWidth = widths[column.name];
6838
- if (desiredWidth && !column.options?.width) {
6839
- const normalizedWidth = typeof desiredWidth === 'number' ? `${desiredWidth}px` : desiredWidth;
6840
- context.columns.find(column.name).update((col) => ({
6841
- ...col,
6842
- options: {
6843
- ...col.options,
6844
- width: normalizedWidth
6845
- }
6846
- }));
6847
- }
6848
- });
6849
- };
6850
- };
6851
- //#endregion
6852
- //#region ---- Provider Registration ----
6853
- /**
6854
- * Helper to create a provider for the column width middleware.
6855
- * By default it applies to all entities using the '*' pattern.
6856
- */
6857
- const createColumnWidthMiddlewareProvider = (widths, entityName = '*') => ({
6858
- entityName,
6859
- modifier: columnWidthMiddlewareFactory(widths)
6860
- });
6861
- /**
6862
- * Default provider registered with the default map.
6863
- */
6864
- const columnWidthMiddlewareProvider = createColumnWidthMiddlewareProvider(DEFAULT_COLUMN_WIDTHS);
6865
- //#endregion
6866
-
6867
6909
  function routesFacory() {
6868
6910
  const config = inject(AXP_ENTITY_CONFIG_TOKEN);
6869
6911
  let routes = [];
@@ -6902,6 +6944,12 @@ function routesFacory() {
6902
6944
  loadComponent: () => {
6903
6945
  return config.viewers.master.details();
6904
6946
  },
6947
+ runGuardsAndResolvers: (from, to) => {
6948
+ const entityChanged = from.params['module'] !== to.params['module'] || from.params['entity'] !== to.params['entity'];
6949
+ const idChanged = from.params['id'] !== to.params['id'];
6950
+ const refreshChanged = from.queryParams['_ts'] !== to.queryParams['_ts'];
6951
+ return entityChanged || idChanged || refreshChanged;
6952
+ },
6905
6953
  data: { reuse: false },
6906
6954
  },
6907
6955
  {
@@ -6957,6 +7005,12 @@ class AXPEntityModule {
6957
7005
  useValue: columnWidthMiddlewareProvider,
6958
7006
  multi: true,
6959
7007
  },
7008
+ provideCommandSetups([
7009
+ {
7010
+ key: 'Entity:OpenDetails',
7011
+ command: () => Promise.resolve().then(function () { return openEntityDetails_command; }).then((c) => c.AXPOpenEntityDetailsCommand)
7012
+ },
7013
+ ]),
6960
7014
  ], imports: [RouterModule,
6961
7015
  AXPWorkflowModule.forChild({
6962
7016
  actions: {
@@ -7060,10 +7114,65 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
7060
7114
  useValue: columnWidthMiddlewareProvider,
7061
7115
  multi: true,
7062
7116
  },
7117
+ provideCommandSetups([
7118
+ {
7119
+ key: 'Entity:OpenDetails',
7120
+ command: () => Promise.resolve().then(function () { return openEntityDetails_command; }).then((c) => c.AXPOpenEntityDetailsCommand)
7121
+ },
7122
+ ]),
7063
7123
  ],
7064
7124
  }]
7065
7125
  }], ctorParameters: () => [{ type: i1$4.AXPAppStartUpService }, { type: i0.Injector }] });
7066
7126
 
7127
+ //#endregion
7128
+ //#region ---- Entity Open Details Command ----
7129
+ /**
7130
+ * Generic command to open entity details view
7131
+ * Can be used by any entity to navigate to its detail page
7132
+ */
7133
+ class AXPOpenEntityDetailsCommand {
7134
+ constructor() {
7135
+ //#endregion
7136
+ //#region ---- Services & Dependencies ----
7137
+ this.navigation = inject(AXPWorkflowNavigateAction);
7138
+ this.sessionService = inject(AXPSessionService);
7139
+ }
7140
+ //#endregion
7141
+ //#region ---- Command Execution ----
7142
+ /**
7143
+ * Execute the command to navigate to entity details
7144
+ * @param input - Command input containing entity and data information
7145
+ */
7146
+ async execute(input) {
7147
+ const { entity, data } = input;
7148
+ if (!entity) {
7149
+ throw new Error('Entity name is required for opening details view');
7150
+ }
7151
+ if (!data?.id) {
7152
+ throw new Error('Entity ID is required for opening details view');
7153
+ }
7154
+ const [module, entityName] = entity.split('.');
7155
+ if (!module || !entityName) {
7156
+ throw new Error('Entity must be in format "ModuleName.EntityName"');
7157
+ }
7158
+ const url = `/${this.sessionService.application?.name}/m/${module}/e/${entityName}/${data.id}/new-view`;
7159
+ // Navigate to the entity details page
7160
+ window.location.href = url;
7161
+ return { success: true };
7162
+ }
7163
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPOpenEntityDetailsCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
7164
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPOpenEntityDetailsCommand, providedIn: 'root' }); }
7165
+ }
7166
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AXPOpenEntityDetailsCommand, decorators: [{
7167
+ type: Injectable,
7168
+ args: [{ providedIn: 'root' }]
7169
+ }] });
7170
+
7171
+ var openEntityDetails_command = /*#__PURE__*/Object.freeze({
7172
+ __proto__: null,
7173
+ AXPOpenEntityDetailsCommand: AXPOpenEntityDetailsCommand
7174
+ });
7175
+
7067
7176
  // #region Master
7068
7177
  function entityMasterCreateAction() {
7069
7178
  return {
@@ -7266,5 +7375,5 @@ const eventDispatchMiddleware = {
7266
7375
  * Generated bundle index. Do not edit.
7267
7376
  */
7268
7377
 
7269
- export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntityApplyUpdatesAction, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, DEFAULT_COLUMN_WIDTHS, actionExists, columnWidthMiddlewareFactory, columnWidthMiddlewareProvider, createColumnWidthMiddlewareProvider, createModifierContext, detectEntityChanges, ensureListActions, entityDetailsCreateActions, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware };
7378
+ export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntityApplyUpdatesAction, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityEventDispatcherService, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPOpenEntityDetailsCommand, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, DEFAULT_COLUMN_WIDTHS, actionExists, columnWidthMiddlewareFactory, columnWidthMiddlewareProvider, createColumnWidthMiddlewareProvider, createModifierContext, detectEntityChanges, ensureListActions, entityDetailsCreateActions, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware };
7270
7379
  //# sourceMappingURL=acorex-platform-layout-entity.mjs.map