-
Notifications
You must be signed in to change notification settings - Fork 11
Open in new tab #856
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open in new tab #856
Changes from 9 commits
85adc37
20087d1
6dfa494
aa34791
b9e31b7
4266e8b
6169311
101e0ce
532fe1f
65f9181
98f65cd
f7107cc
f59b14f
8ff748c
b5d74ba
b856073
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,11 @@ | ||
| import { Injectable } from '@angular/core'; | ||
| import { Params } from '@angular/router'; | ||
| import { isEmpty } from 'lodash-es'; | ||
| import { EMPTY, ReplaySubject } from 'rxjs'; | ||
| import { catchError, defaultIfEmpty, filter, map, switchMap, take } from 'rxjs/operators'; | ||
| import { NavigationService } from '../navigation/navigation.service'; | ||
| import { ReplayObservable } from '../utilities/rxjs/rxjs-utils'; | ||
| import { getQueryParamStringFromObject } from '../utilities/url/url-utilities'; | ||
| import { FixedTimeRange } from './fixed-time-range'; | ||
| import { RelativeTimeRange } from './relative-time-range'; | ||
| import { TimeDuration } from './time-duration'; | ||
|
|
@@ -30,15 +32,22 @@ export class TimeRangeService { | |
| } | ||
|
|
||
| public getShareableCurrentUrl(): string { | ||
| const timeRangeParamValue = this.navigationService.getQueryParameter(TimeRangeService.TIME_RANGE_QUERY_PARAM, ''); | ||
| const timeRangeParam = `${TimeRangeService.TIME_RANGE_QUERY_PARAM}=${timeRangeParamValue}`; | ||
| const timeRangeParam = getQueryParamStringFromObject(this.getTimeRangeParams()); | ||
| const timeRange = this.getCurrentTimeRange(); | ||
| const fixedTimeRange: FixedTimeRange = TimeRangeService.toFixedTimeRange(timeRange.startTime, timeRange.endTime); | ||
| const newTimeRangeParam = `${TimeRangeService.TIME_RANGE_QUERY_PARAM}=${fixedTimeRange.toUrlString()}`; | ||
|
|
||
| return this.navigationService.getAbsoluteCurrentUrl().replace(timeRangeParam, newTimeRangeParam); | ||
| } | ||
|
|
||
| public getTimeRangeParams(): Params { | ||
|
||
| const timeRangeParamValue = this.navigationService.getQueryParameter(TimeRangeService.TIME_RANGE_QUERY_PARAM, ''); | ||
|
|
||
| return { | ||
| [TimeRangeService.TIME_RANGE_QUERY_PARAM]: timeRangeParamValue | ||
| }; | ||
| } | ||
|
|
||
| public getTimeRangeAndChanges(): ReplayObservable<TimeRange> { | ||
| return this.timeRangeSubject$.asObservable(); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { Params } from '@angular/router'; | ||
| import { getQueryParamStringFromObject } from './url-utilities'; | ||
|
|
||
| describe('getQueryParamStringFromObject', () => { | ||
| test('should return string from a string dictionary', () => { | ||
| const params: Params = {}; | ||
| expect(getQueryParamStringFromObject(params)).toBe(''); | ||
| params.a = 'value_1'; | ||
| expect(getQueryParamStringFromObject(params)).toBe('a=value_1'); | ||
| params.b = 'value_2'; | ||
| expect(getQueryParamStringFromObject(params)).toBe(`a=value_1&b=value_2`); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import { HttpParams } from '@angular/common/http'; | ||
| import { Params } from '@angular/router'; | ||
|
|
||
| export const getQueryParamStringFromObject = (params: Params): string => | ||
|
||
| new HttpParams({ fromObject: params }).toString(); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,46 +1,23 @@ | ||
| import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; | ||
| import { IconType } from '@hypertrace/assets-library'; | ||
| import { | ||
| ExternalNavigationWindowHandling, | ||
| NavigationParamsType, | ||
| NavigationService, | ||
| TimeRangeService | ||
| } from '@hypertrace/common'; | ||
| import { ButtonSize, ButtonStyle } from '../button/button'; | ||
| import { ExternalNavigationParamsNew } from '@hypertrace/common'; | ||
| import { IconSize } from '../icon/icon-size'; | ||
|
|
||
| @Component({ | ||
| selector: 'ht-open-in-new-tab', | ||
| changeDetection: ChangeDetectionStrategy.OnPush, | ||
| template: ` | ||
| <div class="open-in-new-tab" htTooltip="Open in a new tab"> | ||
| <ht-button | ||
| class="open-in-new-tab-button" | ||
| display="${ButtonStyle.Outlined}" | ||
| [size]="this.size" | ||
| icon="${IconType.OpenInNewTab}" | ||
| (click)="this.openInNewTab()" | ||
| ></ht-button> | ||
| <div *ngIf="this.paramsOrUrl" class="open-in-new-tab" htTooltip="Open in a new tab"> | ||
| <ht-link [paramsOrUrl]="this.paramsOrUrl"> | ||
| <ht-icon icon="${IconType.OpenInNewTab}" [size]="this.iconSize"></ht-icon> | ||
| </ht-link> | ||
| </div> | ||
| ` | ||
| }) | ||
| export class OpenInNewTabComponent { | ||
| @Input() | ||
| public size?: ButtonSize = ButtonSize.Small; | ||
| public paramsOrUrl?: ExternalNavigationParamsNew | string; | ||
|
||
|
|
||
| @Input() | ||
| public url?: string; | ||
|
|
||
| public constructor( | ||
| private readonly navigationService: NavigationService, | ||
| private readonly timeRangeService: TimeRangeService | ||
| ) {} | ||
|
|
||
| public openInNewTab(): void { | ||
| this.navigationService.navigate({ | ||
| navType: NavigationParamsType.External, | ||
| windowHandling: ExternalNavigationWindowHandling.NewWindow, | ||
| // Use input url if available. Else construct a shareable URL for the page | ||
| url: this.url ?? this.timeRangeService.getShareableCurrentUrl() | ||
| }); | ||
| } | ||
| public iconSize: IconSize = IconSize.Medium; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,13 @@ | ||
| import { CommonModule } from '@angular/common'; | ||
| import { NgModule } from '@angular/core'; | ||
| import { ButtonModule } from '../button/button.module'; | ||
| import { IconModule } from '../icon/icon.module'; | ||
| import { LinkModule } from '../link/link.module'; | ||
| import { TooltipModule } from '../tooltip/tooltip.module'; | ||
| import { OpenInNewTabComponent } from './open-in-new-tab.component'; | ||
|
|
||
| @NgModule({ | ||
| declarations: [OpenInNewTabComponent], | ||
| exports: [OpenInNewTabComponent], | ||
| imports: [CommonModule, ButtonModule, TooltipModule] | ||
| imports: [CommonModule, TooltipModule, LinkModule, IconModule] | ||
| }) | ||
| export class OpenInNewTabModule {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be better to let angular do any url building for us (such as url tree). This would break if we passed it a a url that contained query params, since it wouldn't merge. Say
http://website.com?param1=valueand a second param via query params{ param2=value }, we'd gethttp://website.com?param1=value?param2=valueinstead ofhttp://website.com?param1=value¶m2=value.I think you can combine
router.parseUrl,router.serializeUrland mayberouter.createUrlTreeto get all the right behavior here.