Skip to content

Commit ca36b32

Browse files
committed
Merge branch 'main' into ng-15
2 parents b078996 + a0e9f99 commit ca36b32

File tree

62 files changed

+2304
-766
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+2304
-766
lines changed

package-lock.json

+626-557
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+12-12
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"@types/d3-hierarchy": "^2.0.2",
4141
"@types/d3-transition": "1.1.5",
4242
"apollo-angular": "^5.0.0",
43-
"core-js": "^3.31.0",
43+
"core-js": "^3.32.0",
4444
"d3-array": "^2.12.0",
4545
"d3-axis": "^2.1.0",
4646
"d3-brush": "^1.1.6",
@@ -63,9 +63,9 @@
6363
"lodash-es": "^4.17.21",
6464
"mixpanel-browser": "^2.47.0",
6565
"ngx-color": "7.0.0",
66-
"rudder-sdk-js": "^2.36.0",
66+
"rudder-sdk-js": "^2.38.0",
6767
"rxjs": "~6.6.7",
68-
"tslib": "^2.5.3",
68+
"tslib": "^2.6.0",
6969
"uuid": "^8.3.2",
7070
"zone.js": "~0.11.8"
7171
},
@@ -97,27 +97,27 @@
9797
"@types/d3-zoom": "^1.7.5",
9898
"@types/highlight.js": "^10.1.0",
9999
"@types/jest": "^28.0.0",
100-
"@types/lodash-es": "^4.17.7",
101-
"@types/mixpanel-browser": "^2.38.2",
102-
"@types/node": "^18.16.19",
100+
"@types/lodash-es": "^4.17.8",
101+
"@types/mixpanel-browser": "^2.47.1",
102+
"@types/node": "^18.17.1",
103103
"@types/uuid": "^8.3.4",
104104
"@types/webpack-env": "^1.18.1",
105105
"@typescript-eslint/eslint-plugin": "5.57.1",
106-
"@typescript-eslint/parser": "5.59.9",
106+
"@typescript-eslint/parser": "5.62.0",
107107
"commitizen": "^4.3.0",
108108
"cz-conventional-changelog": "^3.3.0",
109-
"eslint": "^8.43.0",
109+
"eslint": "^8.46.0",
110110
"eslint-config-prettier": "^8.5.0",
111111
"eslint-plugin-import": "2.27.5",
112-
"eslint-plugin-jsdoc": "46.4.3",
112+
"eslint-plugin-jsdoc": "46.4.4",
113113
"eslint-plugin-no-null": "1.0.2",
114114
"eslint-plugin-prefer-arrow": "1.2.3",
115-
"eslint-plugin-unicorn": "47.0.0",
115+
"eslint-plugin-unicorn": "48.0.0",
116116
"husky": "^8.0.3",
117117
"jest": "^28.0.0",
118118
"jest-preset-angular": "^12.2.3",
119-
"jest-config": "^29.5.0",
120-
"jest-environment-jsdom": "^29.5.0",
119+
"jest-config": "^29.6.2",
120+
"jest-environment-jsdom": "^29.6.2",
121121
"jest-html-reporter": "^3.10.1",
122122
"jest-junit": "16.0.0",
123123
"lodash": "^4.17.21",
Loading

projects/assets-library/src/icons/icon-library.module.ts

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ const iconsRootPath = 'assets/icons';
9898
{ key: IconType.Spinner, url: `${iconsRootPath}/spinner.svg` },
9999
{ key: IconType.StatusCode, url: `${iconsRootPath}/status-code.svg` },
100100
{ key: IconType.StringAttribute, url: `${iconsRootPath}/string-attribute.svg` },
101+
{ key: IconType.TimeHistory, url: `${iconsRootPath}/time-history.svg` },
101102
{ key: IconType.TraceId, url: `${iconsRootPath}/trace-id.svg` },
102103
{ key: IconType.Trash, url: `${iconsRootPath}/trash.svg` },
103104
{ key: IconType.TriangleDown, url: `${iconsRootPath}/triangle-down.svg` },

projects/assets-library/src/icons/icon-registry.service.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ describe('Icon Registry Service', () => {
2525
'hypertrace',
2626
spectator.inject(DomSanitizer).bypassSecurityTrustResourceUrl('test-url')
2727
);
28+
expect(spectator.service.getRegisteredIcons()).toMatchObject([IconType.Hypertrace]);
2829
});
2930

3031
test('looks up ligature icons', () => {

projects/assets-library/src/icons/icon-registry.service.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ import { Observable } from 'rxjs';
88
export class IconRegistryService {
99
private static readonly SVG_ICON_PREFIX: string = 'svg:';
1010

11+
private readonly registeredIcons: Set<string> = new Set();
12+
1113
public constructor(private readonly matIconRegistry: MatIconRegistry, private readonly sanitizer: DomSanitizer) {}
1214

1315
public registerSvgIcon(iconInfo: SvgIconRegistrationInfo): void {
16+
this.registeredIcons.add(iconInfo.key);
1417
this.matIconRegistry.addSvgIcon(
1518
this.getIconNameWithoutPrefix(iconInfo.key),
1619
this.sanitizer.bypassSecurityTrustResourceUrl(iconInfo.url)
@@ -38,11 +41,15 @@ export class IconRegistryService {
3841
};
3942
}
4043

41-
private getIconNameWithoutPrefix(icon: string): string {
44+
public getIconNameWithoutPrefix(icon: string): string {
4245
return icon.startsWith(IconRegistryService.SVG_ICON_PREFIX)
4346
? icon.substring(IconRegistryService.SVG_ICON_PREFIX.length)
4447
: icon;
4548
}
49+
50+
public getRegisteredIcons(): string[] {
51+
return Array.from(this.registeredIcons.keys());
52+
}
4653
}
4754

4855
export type IconRenderInfo = LigatureIconRenderInfo | SvgIconRenderInfo;

projects/assets-library/src/icons/icon-type.ts

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ export const enum IconType {
122122
StatusCode = 'svg:status-code',
123123
StringAttribute = 'svg:string-attribute',
124124
Time = 'schedule',
125+
TimeHistory = 'svg:time-history',
125126
TraceId = 'svg:trace-id',
126127
Trash = 'svg:trash',
127128
TriangleDown = 'svg:triangle-down',

projects/common/src/external/external-url-navigator.test.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ describe('External URL navigator', () => {
1212
service: ExternalUrlNavigator,
1313
providers: [
1414
mockProvider(NavigationService, {
15-
canGoBackWithoutLeavingApp: jest.fn().mockReturnValue(true)
15+
canGoBackWithoutLeavingApp: jest.fn().mockReturnValue(true),
16+
firstNavigatedUrl: '/test-url'
1617
})
1718
]
1819
});
@@ -25,7 +26,8 @@ describe('External URL navigator', () => {
2526
const spectator = buildNavigator({
2627
providers: [
2728
mockProvider(NavigationService, {
28-
canGoBackWithoutLeavingApp: jest.fn().mockReturnValue(false)
29+
canGoBackWithoutLeavingApp: jest.fn().mockReturnValue(false),
30+
firstNavigatedUrl: '/external'
2931
})
3032
]
3133
});

projects/common/src/external/external-url-navigator.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export class ExternalUrlNavigator implements CanActivate {
1313
public constructor(private readonly navService: NavigationService) {}
1414

1515
public canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
16-
if (!this.navService.canGoBackWithoutLeavingApp()) {
16+
if (this.navService.firstNavigatedUrl.startsWith('/external')) {
1717
this.navService.navigateToErrorPage();
1818

1919
return of(false);

projects/common/src/navigation/navigation.service.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
UrlSegment,
1616
UrlTree
1717
} from '@angular/router';
18-
import { isArray, isString } from 'lodash-es';
18+
import { isArray, isEmpty, isString } from 'lodash-es';
1919
import { from, Observable, of } from 'rxjs';
2020
import { distinctUntilChanged, filter, map, share, skip, startWith, switchMap, take, tap } from 'rxjs/operators';
2121
import { isEqualIgnoreFunctions, throwIfNil } from '../utilities/lang/lang-utils';
@@ -32,6 +32,7 @@ export class NavigationService {
3232
private isFirstNavigation: boolean = true;
3333
private readonly globalQueryParams: Set<string> = new Set();
3434
private pendingQueryParams: QueryParamObject = {};
35+
public firstNavigatedUrl: string = '';
3536

3637
public constructor(
3738
private readonly router: Router,
@@ -42,6 +43,15 @@ export class NavigationService {
4243
) {
4344
this.event$(RoutesRecognized)
4445
.pipe(
46+
tap(event => {
47+
// In case of reloading a correct URL, we only have a single event
48+
// Due to that we are getting `this.isFirstNavigation = true` since
49+
// we're not reaching to .subscribe due to skip(1) and causing external navigation failure from the app
50+
// So we're storing the first navigated URL to check whether it is external URL or not.
51+
if (isEmpty(this.firstNavigatedUrl)) {
52+
this.firstNavigatedUrl = decodeURIComponent(event.url);
53+
}
54+
}),
4555
skip(1),
4656
filter(() => !this.getActiveNavigation()?.extras.skipLocationChange),
4757
take(1)

projects/common/src/time/time-duration.ts

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
import { parse, toSeconds } from 'iso8601-duration';
2+
import { indexOf, isNil } from 'lodash-es';
23
import { assertUnreachable } from '../utilities/lang/lang-utils';
34
import { TimeUnit } from './time-unit.type';
45

56
export class TimeDuration {
7+
private static readonly TIME_UNITS: ConvertibleTimeUnit[] = [
8+
TimeUnit.Year,
9+
TimeUnit.Month,
10+
TimeUnit.Week,
11+
TimeUnit.Day,
12+
TimeUnit.Hour,
13+
TimeUnit.Minute,
14+
TimeUnit.Second,
15+
TimeUnit.Millisecond
16+
];
617
private readonly millis: number;
718

819
public constructor(public readonly value: number, public readonly unit: TimeUnit) {
@@ -52,17 +63,10 @@ export class TimeDuration {
5263
return unitStringType === UnitStringType.Short ? this.toString() : this.toLongString();
5364
}
5465

55-
public getMostSignificantUnitOnly(): TimeDuration {
56-
const orderedUnits: ConvertibleTimeUnit[] = [
57-
TimeUnit.Year,
58-
TimeUnit.Month,
59-
TimeUnit.Week,
60-
TimeUnit.Day,
61-
TimeUnit.Hour,
62-
TimeUnit.Minute,
63-
TimeUnit.Second,
64-
TimeUnit.Millisecond
65-
];
66+
public getMostSignificantUnitOnly(maxSupportedUnit?: TimeUnit): TimeDuration {
67+
let orderedUnits: ConvertibleTimeUnit[] = isNil(maxSupportedUnit)
68+
? TimeDuration.TIME_UNITS
69+
: TimeDuration.TIME_UNITS.slice(indexOf(TimeDuration.TIME_UNITS, maxSupportedUnit));
6670

6771
const firstApplicableUnit = orderedUnits.find(unit => this.getAmountForUnit(unit) >= 1) || TimeUnit.Millisecond;
6872
const amountForUnit = Math.floor(this.getAmountForUnit(firstApplicableUnit));

projects/components/src/link/link.component.test.ts

+30-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { RouterLinkWithHref } from '@angular/router';
22
import { RouterTestingModule } from '@angular/router/testing';
3-
import { NavigationService, TrackDirective } from '@hypertrace/common';
3+
import {
4+
ExternalNavigationWindowHandling,
5+
NavigationParamsType,
6+
NavigationService,
7+
TrackDirective
8+
} from '@hypertrace/common';
49
import { createHostFactory, mockProvider, SpectatorHost } from '@ngneat/spectator/jest';
510
import { MockDirective } from 'ng-mocks';
611
import { of } from 'rxjs';
@@ -26,10 +31,12 @@ describe('Link component', () => {
2631

2732
const anchorElement = spectator.query('.ht-link');
2833
expect(anchorElement).toExist();
29-
expect(anchorElement).toHaveClass('ht-link disabled');
34+
expect(anchorElement).toHaveClass('ht-link internal disabled');
3035
});
3136

3237
test('Link should navigate correctly to external URLs', () => {
38+
window.open = jest.fn();
39+
3340
spectator = createHost(`<ht-link [paramsOrUrl]="paramsOrUrl"></ht-link>`, {
3441
hostProps: {
3542
paramsOrUrl: 'http://test.hypertrace.ai'
@@ -47,28 +54,30 @@ describe('Link component', () => {
4754
],
4855
extras: { skipLocationChange: true }
4956
})
50-
)
57+
),
58+
isExternalUrl: jest.fn().mockReturnValue(true)
5159
})
5260
]
5361
});
5462

55-
const anchorElement = spectator.query('.ht-link');
63+
let anchorElement = spectator.query('.ht-link.external') as HTMLAnchorElement;
5664
expect(anchorElement).toExist();
5765
expect(anchorElement).not.toHaveClass('disabled');
58-
const routerLinkDirective = spectator.query(RouterLinkWithHref);
59-
60-
expect(routerLinkDirective).toBeDefined();
61-
expect(routerLinkDirective?.routerLink).toEqual([
62-
'/external',
63-
{
64-
url: 'http://test.hypertrace.ai',
65-
navType: 'same_window'
66+
expect(anchorElement.href).toBe('http://test.hypertrace.ai/');
67+
spectator.click(anchorElement);
68+
expect(window.open).toHaveBeenLastCalledWith('http://test.hypertrace.ai', '_self');
69+
70+
// With new window
71+
spectator.setHostInput({
72+
paramsOrUrl: {
73+
navType: NavigationParamsType.External,
74+
url: '/test',
75+
windowHandling: ExternalNavigationWindowHandling.NewWindow
6676
}
67-
]);
68-
expect(routerLinkDirective!.skipLocationChange).toBeTruthy();
69-
expect(routerLinkDirective!.queryParams).toBeUndefined();
70-
expect(routerLinkDirective!.queryParamsHandling).toBeUndefined();
71-
expect(routerLinkDirective!.replaceUrl).toBeUndefined();
77+
});
78+
expect(anchorElement.href).toBe('http://localhost/test');
79+
spectator.click(anchorElement);
80+
expect(window.open).toHaveBeenLastCalledWith('/test', undefined);
7281
});
7382

7483
test('Link should navigate correctly to internal relative URLs', () => {
@@ -83,7 +92,7 @@ describe('Link component', () => {
8392
]
8493
});
8594

86-
const anchorElement = spectator.query('.ht-link');
95+
const anchorElement = spectator.query('.ht-link.internal');
8796
expect(anchorElement).toExist();
8897
expect(anchorElement).not.toHaveClass('disabled');
8998
const routerLinkDirective = spectator.query(RouterLinkWithHref);
@@ -108,7 +117,7 @@ describe('Link component', () => {
108117
]
109118
});
110119

111-
const anchorElement = spectator.query('.ht-link');
120+
const anchorElement = spectator.query('.ht-link.internal');
112121
expect(anchorElement).toExist();
113122
expect(anchorElement).not.toHaveClass('disabled');
114123
const routerLinkDirective = spectator.query(RouterLinkWithHref);
@@ -133,9 +142,9 @@ describe('Link component', () => {
133142
]
134143
});
135144

136-
const anchorElement = spectator.query('.ht-link');
145+
const anchorElement = spectator.query('.ht-link.internal');
137146
expect(anchorElement).toExist();
138-
expect(anchorElement).toHaveClass('ht-link disabled');
147+
expect(anchorElement).toHaveClass('ht-link internal disabled');
139148

140149
const routerLinkDirective = spectator.query(RouterLinkWithHref);
141150

0 commit comments

Comments
 (0)