@acorex/platform 20.8.21 → 20.8.23

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.
@@ -3,7 +3,7 @@ import { InjectionToken, inject, Injectable, Injector, makeEnvironmentProviders,
3
3
  import { kebabCase, merge, sortBy, cloneDeep, get, omit } from 'lodash-es';
4
4
  import { Router, ROUTES, RedirectCommand, RouterModule } from '@angular/router';
5
5
  import { AXPSessionService, AXPSessionStatus, AXPAuthGuard } from '@acorex/platform/auth';
6
- import { Subject, distinctUntilChanged, merge as merge$1, first, switchMap, from } from 'rxjs';
6
+ import { Subject, distinctUntilChanged, merge as merge$1, first, switchMap, from, map } from 'rxjs';
7
7
  import { AXPPlatformScope, AXPBroadcastEventService, objectKeyValueTransforms, AXPSystemActionType, AXPModuleManifestModule, AXPAppStartUpProvider, AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, AXPHookService, AXPDataGenerator, AXPModuleManifestRegistry } from '@acorex/platform/core';
8
8
  import { AXTranslationService } from '@acorex/core/translation';
9
9
  import { AXPWidgetsCatalog } from '@acorex/platform/layout/widget-core';
@@ -1042,12 +1042,20 @@ class AXPHomePageService {
1042
1042
  // TODO: check this for custom menu like :app/terms
1043
1043
  router.resetConfig(merged);
1044
1044
  }
1045
+ /**
1046
+ * Resolves the current user's home page as a router URL tree.
1047
+ */
1048
+ resolveHomeUrlTree() {
1049
+ const router = this.injector.get(Router);
1050
+ const current = this.getCurrent();
1051
+ const path = current.path.startsWith('/') ? current.path : `/${current.path}`;
1052
+ return router.parseUrl(path);
1053
+ }
1045
1054
  async navigateTo() {
1046
1055
  // wait for the router to be initialized
1047
1056
  setTimeout(() => {
1048
1057
  const router = this.injector.get(Router);
1049
- const current = this.getCurrent();
1050
- router.navigate([current.path], { onSameUrlNavigation: 'reload' });
1058
+ router.navigateByUrl(this.resolveHomeUrlTree(), { onSameUrlNavigation: 'reload' });
1051
1059
  }, 100);
1052
1060
  }
1053
1061
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXPHomePageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
@@ -1280,6 +1288,27 @@ class AXPNotFoundError extends Error {
1280
1288
 
1281
1289
  /** Canonical route path for the platform 404 page. */
1282
1290
  const AXP_NOT_FOUND_ROUTE = '/error/404';
1291
+ /**
1292
+ * Catch-all route that redirects unknown URLs to the platform 404 page.
1293
+ * Register this as the **last** route source in the application (after all app and module routes).
1294
+ */
1295
+ const AXP_NOT_FOUND_CATCH_ALL_ROUTE = {
1296
+ path: '**',
1297
+ redirectTo: AXP_NOT_FOUND_ROUTE,
1298
+ };
1299
+ /**
1300
+ * Registers the platform catch-all 404 route.
1301
+ * Must be the last `ROUTES` provider in `app.config` so custom app routes are matched first.
1302
+ */
1303
+ function AXPNotFoundCatchAllRoute() {
1304
+ return makeEnvironmentProviders([
1305
+ {
1306
+ provide: ROUTES,
1307
+ multi: true,
1308
+ useValue: [AXP_NOT_FOUND_CATCH_ALL_ROUTE],
1309
+ },
1310
+ ]);
1311
+ }
1283
1312
  /**
1284
1313
  * Returns true when an entity byKey query did not resolve a record.
1285
1314
  */
@@ -1293,6 +1322,15 @@ function axpRedirectToNotFound(router = inject(Router)) {
1293
1322
  return new RedirectCommand(router.parseUrl(AXP_NOT_FOUND_ROUTE));
1294
1323
  }
1295
1324
 
1325
+ /** Canonical route path for the platform 401 page. */
1326
+ const AXP_UNAUTHORIZED_ROUTE = '/error/401';
1327
+ /**
1328
+ * Creates an Angular redirect command to the platform 401 page.
1329
+ */
1330
+ function axpRedirectToUnauthorized(router = inject(Router)) {
1331
+ return new RedirectCommand(router.parseUrl(AXP_UNAUTHORIZED_ROUTE));
1332
+ }
1333
+
1296
1334
  const AXP_TOKEN_DEFINITION_PROVIDER = new InjectionToken('AXP_TOKEN_DEFINITION_PROVIDER', {
1297
1335
  factory: () => [],
1298
1336
  });
@@ -2373,10 +2411,10 @@ function axpMenuPathsMatch(itemPath, currentPath, trailingSegmentsToIgnore = DEF
2373
2411
  function axpFindMenuItemByRoute(items, currentPath, trailingSegmentsToIgnore = DEFAULT_TRAILING_SEGMENTS) {
2374
2412
  let bestMatch = null;
2375
2413
  let bestEffectiveLength = -1;
2376
- const visit = (menuItems) => {
2414
+ const visit = (menuItems, ancestors) => {
2377
2415
  for (const item of menuItems) {
2378
2416
  if (item.children?.length) {
2379
- visit(item.children);
2417
+ visit(item.children, [...ancestors, item]);
2380
2418
  }
2381
2419
  if (!item.path) {
2382
2420
  continue;
@@ -2395,11 +2433,11 @@ function axpFindMenuItemByRoute(items, currentPath, trailingSegmentsToIgnore = D
2395
2433
  }
2396
2434
  if (effectiveMenuLength > bestEffectiveLength) {
2397
2435
  bestEffectiveLength = effectiveMenuLength;
2398
- bestMatch = { item, isPartialMatch: matchResult.isPartial };
2436
+ bestMatch = { item, ancestors, isPartialMatch: matchResult.isPartial };
2399
2437
  }
2400
2438
  }
2401
2439
  };
2402
- visit(items);
2440
+ visit(items, []);
2403
2441
  return bestMatch;
2404
2442
  }
2405
2443
 
@@ -2509,6 +2547,18 @@ class AXPMenuVisibilityService {
2509
2547
  constructor() {
2510
2548
  this.sessionService = inject(AXPSessionService);
2511
2549
  }
2550
+ /**
2551
+ * Checks visibility for a menu branch, including ancestor policies.
2552
+ * Parent module features and permissions must pass before child routes are accessible.
2553
+ */
2554
+ isMenuBranchVisible(item, ancestors = []) {
2555
+ for (const menuItem of [...ancestors, item]) {
2556
+ if (!this.isItemVisible(menuItem)) {
2557
+ return false;
2558
+ }
2559
+ }
2560
+ return true;
2561
+ }
2512
2562
  /**
2513
2563
  * Checks if a menu item should be visible based on permissions and features.
2514
2564
  */
@@ -2601,19 +2651,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
2601
2651
  }] });
2602
2652
 
2603
2653
  const SKIP_ROUTE_PREFIXES = ['/auth', '/error'];
2604
- const SKIP_ROUTE_PATHS = new Set(['/404', '/401']);
2605
- //#region ---- Menu Route Permission Service ----
2654
+ const SKIP_ROUTE_PATHS = new Set(['/404', '/401', '/error/404', '/error/401']);
2655
+ //#region ---- Menu Route Access Service ----
2606
2656
  /**
2607
- * Resolves route access using the same permission and feature policies defined on menu items.
2657
+ * Resolves route access using menu policy, route metadata, permissions, and features.
2608
2658
  */
2609
- class AXPMenuRoutePermissionService {
2659
+ class AXPMenuRouteAccessService {
2610
2660
  constructor() {
2611
2661
  //#region ---- Services & Dependencies ----
2612
2662
  this.menuProvider = inject(AXPMenuProviderService);
2613
2663
  this.menuVisibility = inject(AXPMenuVisibilityService);
2614
2664
  this.sessionService = inject(AXPSessionService);
2615
- this.toastService = inject(AXToastService);
2616
- this.translationService = inject(AXTranslationService);
2617
2665
  }
2618
2666
  //#endregion
2619
2667
  //#region ---- Public Methods ----
@@ -2625,7 +2673,6 @@ class AXPMenuRoutePermissionService {
2625
2673
  return true;
2626
2674
  }
2627
2675
  if (!this.hasExplicitRouteAccess(route)) {
2628
- await this.showAccessDeniedToast();
2629
2676
  return false;
2630
2677
  }
2631
2678
  const menuItems = await this.menuProvider.items();
@@ -2633,16 +2680,15 @@ class AXPMenuRoutePermissionService {
2633
2680
  if (!menuMatch) {
2634
2681
  return true;
2635
2682
  }
2636
- if (this.menuVisibility.isItemVisible(menuMatch.item)) {
2683
+ if (this.menuVisibility.isMenuBranchVisible(menuMatch.item, menuMatch.ancestors)) {
2637
2684
  return true;
2638
2685
  }
2639
- await this.showAccessDeniedToast();
2640
2686
  return false;
2641
2687
  }
2642
2688
  //#endregion
2643
2689
  //#region ---- Utility Methods ----
2644
2690
  shouldSkip(route, url) {
2645
- if (this.hasRouteFlag(route, 'skipMenuPermissionGuard')) {
2691
+ if (this.hasRouteFlag(route, 'skipMenuRouteGuard')) {
2646
2692
  return true;
2647
2693
  }
2648
2694
  const normalizedUrl = this.normalizeUrl(url);
@@ -2695,41 +2741,35 @@ class AXPMenuRoutePermissionService {
2695
2741
  const path = url.split('?')[0]?.split('#')[0] ?? url;
2696
2742
  return path.startsWith('/') ? path : `/${path}`;
2697
2743
  }
2698
- async showAccessDeniedToast() {
2699
- const title = await this.translationService.translateAsync('@general:messages.network.forbidden.title');
2700
- const description = await this.translationService.translateAsync('@general:messages.network.forbidden.description');
2701
- this.toastService.show({
2702
- color: 'danger',
2703
- title,
2704
- content: description,
2705
- timeOut: 5000,
2706
- });
2707
- }
2708
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXPMenuRoutePermissionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2709
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXPMenuRoutePermissionService, providedIn: 'root' }); }
2744
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXPMenuRouteAccessService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2745
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXPMenuRouteAccessService, providedIn: 'root' }); }
2710
2746
  }
2711
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXPMenuRoutePermissionService, decorators: [{
2747
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXPMenuRouteAccessService, decorators: [{
2712
2748
  type: Injectable,
2713
2749
  args: [{ providedIn: 'root' }]
2714
2750
  }] });
2715
2751
 
2716
2752
  /**
2717
- * Blocks navigation when the target route matches a menu item the current user cannot access.
2718
- * Uses the same permission and feature policies applied to menu visibility.
2753
+
2754
+ * Blocks navigation when the target route is not accessible for the current user.
2755
+
2756
+ * Evaluates menu policy, permissions, and features.
2757
+
2719
2758
  */
2720
- const AXPMenuPermissionGuard = (route, state) => {
2759
+ const AXPMenuRouteGuard = (route, state) => {
2721
2760
  const sessionService = inject(AXPSessionService);
2722
- const menuRoutePermissionService = inject(AXPMenuRoutePermissionService);
2723
- return sessionService.isAuthorized$.pipe(first(), switchMap((isAuthorized) => {
2724
- if (!isAuthorized) {
2725
- return from(Promise.resolve(true));
2761
+ const menuRouteAccessService = inject(AXPMenuRouteAccessService);
2762
+ const router = inject(Router);
2763
+ return sessionService.isAuthorizedWithLoading$.pipe(first(), switchMap(() => from(menuRouteAccessService.canAccess(route, state.url))), map((isAllowed) => {
2764
+ if (isAllowed) {
2765
+ return true;
2726
2766
  }
2727
- return from(menuRoutePermissionService.canAccess(route, state.url));
2767
+ return router.parseUrl(AXP_UNAUTHORIZED_ROUTE);
2728
2768
  }));
2729
2769
  };
2730
2770
 
2731
- /** Standard guards for authenticated routes with menu-based permission enforcement. */
2732
- const AXP_PROTECTED_ROUTE_GUARDS = [AXPAuthGuard, AXPMenuPermissionGuard];
2771
+ /** Standard guards for authenticated routes with menu-based access enforcement. */
2772
+ const AXP_PROTECTED_ROUTE_GUARDS = [AXPAuthGuard, AXPMenuRouteGuard];
2733
2773
 
2734
2774
  class AXPMenuSearchDefinitionProvider {
2735
2775
  async provide(context) {
@@ -4577,5 +4617,5 @@ class AXPVersioningService {
4577
4617
  * Generated bundle index. Do not edit.
4578
4618
  */
4579
4619
 
4580
- export { ALL_DEFAULT_OPERATORS, AXMWorkflowErrorHandler, AXPAppVersionService, AXPCleanNestedFilters, AXPClipBoardService, AXPCommonModule, AXPCommonSettings, AXPCustomOperatorService, AXPCustomOperatorServiceImpl, AXPDataProvider, AXPDebugService, AXPDialogConfirmAction, AXPEntityCommandScope, AXPEntityQueryType, AXPErrorHandlerRegistryService, AXPExportService, AXPFileActionsService, AXPFileStorageService, AXPFileStorageStatus, AXPFileTypeProviderService, AXPFilterOperatorMiddlewareService, AXPFilterOperatorMiddlewareServiceImpl, AXPFooterTextSlotComponent, AXPGlobalErrorHandler, AXPHomePageModule, AXPHomePageService, AXPLockService, AXPMenuMiddlewareRegistry, AXPMenuPermissionGuard, AXPMenuProviderService, AXPMenuRoutePermissionService, AXPMenuSearchDefinitionProvider, AXPMenuSearchProvider, AXPMenuService, AXPMenuVisibilityService, AXPNavBarSlotComponent, AXPNavigateWorkflow, AXPNotFoundError, AXPPlatformDefaultConfigs, AXPRedirectEvent, AXPRefreshEvent, AXPRegionalSetting, AXPRelationshipCardinality, AXPRelationshipKind, AXPReloadAction, AXPReloadEvent, AXPSearchCommandProvider, AXPSearchDefinitionActionBuilder, AXPSearchDefinitionBuilder, AXPSearchDefinitionProviderContext, AXPSearchDefinitionProviderService, AXPSearchService, AXPSettingDefaultValuesAggregatorService, AXPSettingDefinitionGroupBuilder, AXPSettingDefinitionProviderContext, AXPSettingDefinitionProviderService, AXPSettingDefinitionSectionBuilder, AXPSettingsService, AXPStatusDefinitionProviderService, AXPStatusProvider, AXPStickyDirective, AXPSystemStatusType, AXPSystemStatuses, AXPToastAction, AXPTokenDefinitionService, AXPTokenEvaluatorScopeProvider, AXPVersioningService, AXPWorkflowNavigateAction, AXPWorkflowRouterNavigateAction, AXP_APP_VERSION_PROVIDER, AXP_FILE_ACTION_PROVIDER, AXP_FILE_TYPE_INFO_PROVIDER, AXP_HOME_PAGES, AXP_HOME_PAGE_DEFAULT_KEY, AXP_MENU_MIDDLEWARE, AXP_MENU_PROVIDER, AXP_NOT_FOUND_ROUTE, AXP_PLATFORM_CONFIG_TOKEN, AXP_PROTECTED_ROUTE_GUARDS, AXP_ROOT_CONFIG_TOKEN, AXP_SEARCH_DEFINITION_PROVIDER, AXP_SEARCH_PROVIDER, AXP_SETTING_DEFAULT_VALUES_PROVIDERS, AXP_SETTING_DEFINITION_PROVIDER, AXP_SETTING_VALUE_PROVIDER, AXP_STATUS_PROVIDERS, AXP_TOKEN_DEFINITION_PROVIDER, AXVChangeType, BETWEEN_OPER, BOOLEAN_OPERATORS, CONTAINS_OPER, DATE_OPERATORS, DEFAULT_DATE_FILTER_PRESETS, ENDS_WITH_OPER, ENVIRONMENT, EQ_OPER, GTE_OPER, GT_OPER, IN_OPER, IS_EMPTY_OPER, IS_NOT_EMPTY_OPER, LTE_OPER, LT_OPER, NOT_CONTAINS_OPER, NOT_EQ_OPER, NUMBER_OPERATORS, STARTS_WITH_OPER, STRING_OPERATORS, UploadFromComputerActionProvider, applyDateFilterPreset, axpFindMenuItemByRoute, axpIsEntityRecordNotFound, axpMenuPathsMatch, axpRedirectToNotFound, configPlatform, createAllQueryView, createMenuContext, createMenuMiddleware, createQueryView, findManualPresetIdByOperation, getEntityInfo, getStatusInfo, getSystemStatus, provideDynamicHomePage, provideMenuMiddleware, resolveDateFilterPresets, resolveStatusLook, systemStatusToDefinition };
4620
+ export { ALL_DEFAULT_OPERATORS, AXMWorkflowErrorHandler, AXPAppVersionService, AXPCleanNestedFilters, AXPClipBoardService, AXPCommonModule, AXPCommonSettings, AXPCustomOperatorService, AXPCustomOperatorServiceImpl, AXPDataProvider, AXPDebugService, AXPDialogConfirmAction, AXPEntityCommandScope, AXPEntityQueryType, AXPErrorHandlerRegistryService, AXPExportService, AXPFileActionsService, AXPFileStorageService, AXPFileStorageStatus, AXPFileTypeProviderService, AXPFilterOperatorMiddlewareService, AXPFilterOperatorMiddlewareServiceImpl, AXPFooterTextSlotComponent, AXPGlobalErrorHandler, AXPHomePageModule, AXPHomePageService, AXPLockService, AXPMenuMiddlewareRegistry, AXPMenuProviderService, AXPMenuRouteAccessService, AXPMenuRouteGuard, AXPMenuSearchDefinitionProvider, AXPMenuSearchProvider, AXPMenuService, AXPMenuVisibilityService, AXPNavBarSlotComponent, AXPNavigateWorkflow, AXPNotFoundCatchAllRoute, AXPNotFoundError, AXPPlatformDefaultConfigs, AXPRedirectEvent, AXPRefreshEvent, AXPRegionalSetting, AXPRelationshipCardinality, AXPRelationshipKind, AXPReloadAction, AXPReloadEvent, AXPSearchCommandProvider, AXPSearchDefinitionActionBuilder, AXPSearchDefinitionBuilder, AXPSearchDefinitionProviderContext, AXPSearchDefinitionProviderService, AXPSearchService, AXPSettingDefaultValuesAggregatorService, AXPSettingDefinitionGroupBuilder, AXPSettingDefinitionProviderContext, AXPSettingDefinitionProviderService, AXPSettingDefinitionSectionBuilder, AXPSettingsService, AXPStatusDefinitionProviderService, AXPStatusProvider, AXPStickyDirective, AXPSystemStatusType, AXPSystemStatuses, AXPToastAction, AXPTokenDefinitionService, AXPTokenEvaluatorScopeProvider, AXPVersioningService, AXPWorkflowNavigateAction, AXPWorkflowRouterNavigateAction, AXP_APP_VERSION_PROVIDER, AXP_FILE_ACTION_PROVIDER, AXP_FILE_TYPE_INFO_PROVIDER, AXP_HOME_PAGES, AXP_HOME_PAGE_DEFAULT_KEY, AXP_MENU_MIDDLEWARE, AXP_MENU_PROVIDER, AXP_NOT_FOUND_CATCH_ALL_ROUTE, AXP_NOT_FOUND_ROUTE, AXP_PLATFORM_CONFIG_TOKEN, AXP_PROTECTED_ROUTE_GUARDS, AXP_ROOT_CONFIG_TOKEN, AXP_SEARCH_DEFINITION_PROVIDER, AXP_SEARCH_PROVIDER, AXP_SETTING_DEFAULT_VALUES_PROVIDERS, AXP_SETTING_DEFINITION_PROVIDER, AXP_SETTING_VALUE_PROVIDER, AXP_STATUS_PROVIDERS, AXP_TOKEN_DEFINITION_PROVIDER, AXP_UNAUTHORIZED_ROUTE, AXVChangeType, BETWEEN_OPER, BOOLEAN_OPERATORS, CONTAINS_OPER, DATE_OPERATORS, DEFAULT_DATE_FILTER_PRESETS, ENDS_WITH_OPER, ENVIRONMENT, EQ_OPER, GTE_OPER, GT_OPER, IN_OPER, IS_EMPTY_OPER, IS_NOT_EMPTY_OPER, LTE_OPER, LT_OPER, NOT_CONTAINS_OPER, NOT_EQ_OPER, NUMBER_OPERATORS, STARTS_WITH_OPER, STRING_OPERATORS, UploadFromComputerActionProvider, applyDateFilterPreset, axpFindMenuItemByRoute, axpIsEntityRecordNotFound, axpMenuPathsMatch, axpRedirectToNotFound, axpRedirectToUnauthorized, configPlatform, createAllQueryView, createMenuContext, createMenuMiddleware, createQueryView, findManualPresetIdByOperation, getEntityInfo, getStatusInfo, getSystemStatus, provideDynamicHomePage, provideMenuMiddleware, resolveDateFilterPresets, resolveStatusLook, systemStatusToDefinition };
4581
4621
  //# sourceMappingURL=acorex-platform-common.mjs.map