diff --git a/projects/components/src/header/page/page-header.component.test.ts b/projects/components/src/header/page/page-header.component.test.ts index fd4f534c5..48787020d 100644 --- a/projects/components/src/header/page/page-header.component.test.ts +++ b/projects/components/src/header/page/page-header.component.test.ts @@ -1,3 +1,4 @@ +import { NavigationService, PreferenceService, SubscriptionLifecycle } from '@hypertrace/common'; import { createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/jest'; import { of } from 'rxjs'; import { BreadcrumbsService } from '../../breadcrumbs/breadcrumbs.service'; @@ -10,6 +11,9 @@ describe('Page Header Component', () => { component: PageHeaderComponent, shallow: true, providers: [ + mockProvider(NavigationService), + mockProvider(PreferenceService), + mockProvider(SubscriptionLifecycle), mockProvider(BreadcrumbsService, { breadcrumbs$: of([ { diff --git a/projects/components/src/header/page/page-header.component.ts b/projects/components/src/header/page/page-header.component.ts index 211b80e52..4d63c9354 100644 --- a/projects/components/src/header/page/page-header.component.ts +++ b/projects/components/src/header/page/page-header.component.ts @@ -1,7 +1,13 @@ -import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; -import { Breadcrumb } from '@hypertrace/common'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; +import { + Breadcrumb, + isNonEmptyString, + NavigationService, + PreferenceService, + SubscriptionLifecycle +} from '@hypertrace/common'; +import { Observable, of } from 'rxjs'; +import { first, map } from 'rxjs/operators'; import { BreadcrumbsService } from '../../breadcrumbs/breadcrumbs.service'; import { IconSize } from '../../icon/icon-size'; import { NavigableTab } from '../../tabs/navigable/navigable-tab'; @@ -10,6 +16,7 @@ import { NavigableTab } from '../../tabs/navigable/navigable-tab'; selector: 'ht-page-header', styleUrls: ['./page-header.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, + providers: [SubscriptionLifecycle], template: `
- + ` }) -export class PageHeaderComponent { +export class PageHeaderComponent implements OnInit { + @Input() + public persistenceId?: string; + @Input() public tabs?: NavigableTab[] = []; @@ -62,5 +72,47 @@ export class PageHeaderComponent { map(breadcrumbs => (breadcrumbs.length > 0 ? breadcrumbs[breadcrumbs.length - 1] : {})) ); - public constructor(protected readonly breadcrumbsService: BreadcrumbsService) {} + public constructor( + protected readonly navigationService: NavigationService, + protected readonly preferenceService: PreferenceService, + protected readonly subscriptionLifecycle: SubscriptionLifecycle, + protected readonly breadcrumbsService: BreadcrumbsService + ) {} + + public ngOnInit(): void { + this.subscriptionLifecycle.add( + this.getPreferences().subscribe(preferences => this.navigateIfPersistedActiveTab(preferences)) + ); + } + + private navigateIfPersistedActiveTab(preferences: PageHeaderPreferences): void { + if (isNonEmptyString(this.persistenceId) && isNonEmptyString(preferences.selectedTabPath)) { + this.navigationService.navigateWithinApp( + preferences.selectedTabPath, + this.navigationService.getCurrentActivatedRoute().parent! + ); + } + } + + public onTabChange(path?: string): void { + this.setPreferences(path); + } + + private getPreferences(): Observable { + return isNonEmptyString(this.persistenceId) + ? this.preferenceService.get(this.persistenceId, {}).pipe(first()) + : of({}); + } + + private setPreferences(selectedTabPath?: string): void { + if (isNonEmptyString(this.persistenceId)) { + this.preferenceService.set(this.persistenceId, { + selectedTabPath: selectedTabPath + }); + } + } +} + +interface PageHeaderPreferences { + selectedTabPath?: string; } diff --git a/projects/components/src/tabs/navigable/navigable-tab-group.component.ts b/projects/components/src/tabs/navigable/navigable-tab-group.component.ts index 5230ff0cd..8b0150a44 100644 --- a/projects/components/src/tabs/navigable/navigable-tab-group.component.ts +++ b/projects/components/src/tabs/navigable/navigable-tab-group.component.ts @@ -1,8 +1,16 @@ -import { AfterContentInit, ChangeDetectionStrategy, Component, ContentChildren, QueryList } from '@angular/core'; +import { + AfterContentInit, + ChangeDetectionStrategy, + Component, + ContentChildren, + EventEmitter, + Output, + QueryList +} from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Color, FeatureState, NavigationParams, NavigationParamsType, NavigationService } from '@hypertrace/common'; import { merge, Observable } from 'rxjs'; -import { map, startWith } from 'rxjs/operators'; +import { distinctUntilChanged, map, startWith, tap } from 'rxjs/operators'; import { NavigableTabComponent } from './navigable-tab.component'; @Component({ @@ -47,6 +55,9 @@ export class NavigableTabGroupComponent implements AfterContentInit { @ContentChildren(NavigableTabComponent) public tabs!: QueryList; + @Output() + public readonly tabChange: EventEmitter = new EventEmitter(); + public activeTab$?: Observable; public constructor( @@ -57,7 +68,9 @@ export class NavigableTabGroupComponent implements AfterContentInit { public ngAfterContentInit(): void { this.activeTab$ = merge(this.navigationService.navigation$, this.tabs.changes).pipe( startWith(undefined), - map(() => this.findActiveTab()) + map(() => this.findActiveTab()), + distinctUntilChanged(), + tap(activeTab => this.tabChange.emit(activeTab?.path)) ); }