diff --git a/projects/common/src/navigation/navigation.service.test.ts b/projects/common/src/navigation/navigation.service.test.ts index 90ca857e2..2e08eb5b6 100644 --- a/projects/common/src/navigation/navigation.service.test.ts +++ b/projects/common/src/navigation/navigation.service.test.ts @@ -1,6 +1,8 @@ import { Location } from '@angular/common'; import { Router, UrlSegment } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; +import { IconType } from '@hypertrace/assets-library'; +import { NavItemType } from '@hypertrace/components'; import { patchRouterNavigateForTest } from '@hypertrace/test-utils'; import { createServiceFactory, mockProvider, SpectatorService } from '@ngneat/spectator/jest'; import { @@ -47,6 +49,7 @@ describe('Navigation Service', () => { RouterTestingModule.withRoutes([ { path: 'root', + data: { features: ['test-feature'] }, children: [firstChildRouteConfig, secondChildRouteConfig] } ]) @@ -285,4 +288,34 @@ describe('Navigation Service', () => { ); } }); + + test('decorating navItem with features work as expected', () => { + expect( + spectator.service.decorateNavItem( + { + type: NavItemType.Header, + label: 'Label' + }, + spectator.service.getCurrentActivatedRoute() + ) + ).toEqual({ type: NavItemType.Header, label: 'Label' }); + + expect( + spectator.service.decorateNavItem( + { + type: NavItemType.Link, + label: 'Label', + icon: IconType.None, + matchPaths: ['root'] + }, + spectator.service.rootRoute() + ) + ).toEqual({ + type: NavItemType.Link, + label: 'Label', + icon: IconType.None, + matchPaths: ['root'], + features: ['test-feature'] + }); + }); }); diff --git a/projects/common/src/navigation/navigation.service.ts b/projects/common/src/navigation/navigation.service.ts index 1ad2de08f..1414a74f4 100644 --- a/projects/common/src/navigation/navigation.service.ts +++ b/projects/common/src/navigation/navigation.service.ts @@ -13,6 +13,8 @@ import { UrlSegment, UrlTree } from '@angular/router'; +import { NavItemConfig, NavItemType } from '@hypertrace/components'; +import { uniq } from 'lodash-es'; import { from, Observable, of } from 'rxjs'; import { distinctUntilChanged, filter, map, share, skip, startWith, switchMap, take } from 'rxjs/operators'; import { isEqualIgnoreFunctions, throwIfNil } from '../utilities/lang/lang-utils'; @@ -229,6 +231,26 @@ export class NavigationService { return this.findRouteConfig(path, childRoutes ? childRoutes : []); } + public decorateNavItem(navItem: NavItemConfig, activatedRoute: ActivatedRoute): NavItemConfig { + if (navItem.type !== NavItemType.Link) { + return { ...navItem }; + } + const features = navItem.matchPaths + .map(path => this.getRouteConfig([path], activatedRoute)) + .filter((maybeRoute): maybeRoute is HtRoute => maybeRoute !== undefined) + .flatMap(route => this.getFeaturesForRoute(route)) + .concat(navItem.features || []); + + return { + ...navItem, + features: uniq(features) + }; + } + + private getFeaturesForRoute(route: HtRoute): string[] { + return (route.data && route.data.features) || []; + } + public rootRoute(): ActivatedRoute { return this.router.routerState.root; } diff --git a/src/app/shared/navigation/navigation.component.test.ts b/src/app/shared/navigation/navigation.component.test.ts index 873ca3618..7ffe5b976 100644 --- a/src/app/shared/navigation/navigation.component.test.ts +++ b/src/app/shared/navigation/navigation.component.test.ts @@ -18,7 +18,8 @@ describe('NavigationComponent', () => { data: { features: ['example-feature'] } - }) + }), + decorateNavItem: jest.fn().mockImplementation(navItem => ({ ...navItem, features: ['example-feature'] })) }), mockProvider(ActivatedRoute), mockProvider(PreferenceService, { get: jest.fn().mockReturnValue(of(false)) }) diff --git a/src/app/shared/navigation/navigation.component.ts b/src/app/shared/navigation/navigation.component.ts index 8e696b005..6c9aed540 100644 --- a/src/app/shared/navigation/navigation.component.ts +++ b/src/app/shared/navigation/navigation.component.ts @@ -1,10 +1,9 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { IconType } from '@hypertrace/assets-library'; -import { HtRoute, NavigationService, PreferenceService } from '@hypertrace/common'; +import { NavigationService, PreferenceService } from '@hypertrace/common'; import { NavItemConfig, NavItemType } from '@hypertrace/components'; import { ObservabilityIconType } from '@hypertrace/observability'; -import { uniq } from 'lodash-es'; import { Observable } from 'rxjs'; @Component({ @@ -79,31 +78,13 @@ export class NavigationComponent { private readonly preferenceService: PreferenceService, private readonly activatedRoute: ActivatedRoute ) { - this.navItems = this.navItemDefinitions.map(definition => this.decorateNavItem(definition)); + this.navItems = this.navItemDefinitions.map(definition => + this.navigationService.decorateNavItem(definition, this.activatedRoute) + ); this.isCollapsed$ = this.preferenceService.get(NavigationComponent.COLLAPSED_PREFERENCE, false); } public onViewToggle(collapsed: boolean): void { this.preferenceService.set(NavigationComponent.COLLAPSED_PREFERENCE, collapsed); } - - private decorateNavItem(navItem: NavItemConfig): NavItemConfig { - if (navItem.type !== NavItemType.Link) { - return { ...navItem }; - } - const features = navItem.matchPaths - .map(path => this.navigationService.getRouteConfig([path], this.activatedRoute)) - .filter((maybeRoute): maybeRoute is HtRoute => maybeRoute !== undefined) - .flatMap(route => this.getFeaturesForRoute(route)) - .concat(navItem.features || []); - - return { - ...navItem, - features: uniq(features) - }; - } - - private getFeaturesForRoute(route: HtRoute): string[] { - return (route.data && route.data.features) || []; - } }