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))
);
}