Skip to content

Commit ab55e02

Browse files
committed
Merge branch 'user-telemetry-2' into user-telemetry-3
2 parents a93db20 + 8abcc0a commit ab55e02

16 files changed

+958
-580
lines changed

package-lock.json

Lines changed: 442 additions & 363 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,13 @@
3636
"@angular/platform-browser": "^12.2.1",
3737
"@angular/platform-browser-dynamic": "^12.2.1",
3838
"@angular/router": "^12.2.1",
39-
"@apollo/client": "^3.4.9",
40-
"@fullstory/browser": "^1.4.9",
41-
"mixpanel-browser": "^2.41.0",
39+
"@apollo/client": "^3.4.13",
4240
"@hypertrace/hyperdash": "^1.2.1",
4341
"@hypertrace/hyperdash-angular": "^2.6.0",
4442
"@types/d3-hierarchy": "^2.0.0",
4543
"@types/d3-transition": "1.1.5",
4644
"apollo-angular": "^2.6.0",
47-
"core-js": "^3.16.3",
45+
"core-js": "^3.18.0",
4846
"d3-array": "^2.12.0",
4947
"d3-axis": "^2.1.0",
5048
"d3-brush": "^1.1.6",
@@ -75,7 +73,7 @@
7573
"@angular/cli": "12.2.1",
7674
"@angular/compiler-cli": "~12.2.1",
7775
"@angular/language-service": "~12.2.1",
78-
"@commitlint/cli": "^12.1.4",
76+
"@commitlint/cli": "^13.1.0",
7977
"@commitlint/config-conventional": "^13.1.0",
8078
"@compodoc/compodoc": "^1.1.14",
8179
"@ngneat/spectator": "^8.0.4",
@@ -109,7 +107,7 @@
109107
"ng-packagr": "^12.2.1",
110108
"prettier": "^2.2.1",
111109
"pretty-quick": "^3.1.1",
112-
"ts-node": "~10.0.0",
110+
"ts-node": "~10.2.1",
113111
"tslint": "~6.1.3",
114112
"tslint-config-prettier": "^1.18.0",
115113
"typescript": "~4.3.5",
Lines changed: 3 additions & 0 deletions
Loading

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ const iconsRootPath = 'assets/icons';
7878
{ key: IconType.Search, url: `${iconsRootPath}/search.svg` },
7979
{ key: IconType.SidebarCollapse, url: `${iconsRootPath}/sidebar-collapse.svg` },
8080
{ key: IconType.SidebarExpand, url: `${iconsRootPath}/sidebar-expand.svg` },
81+
{ key: IconType.SidebarLeft, url: `${iconsRootPath}/sidebar-left.svg` },
8182
{ key: IconType.Sort, url: `${iconsRootPath}/sort.svg` },
8283
{ key: IconType.Slack, url: `${iconsRootPath}/slack.svg` },
8384
{ key: IconType.Spinner, url: `${iconsRootPath}/spinner.svg` },

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ export const enum IconType {
9999
Share = 'share',
100100
SidebarCollapse = 'svg:sidebar-collapse',
101101
SidebarExpand = 'svg:sidebar-expand',
102+
SidebarLeft = 'svg:sidebar-left',
102103
Slack = 'svg:slack',
103104
Sort = 'svg:sort',
104105
SpanId = 'bookmark_border',

projects/common/package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@
2020
"zone.js": "~0.11.4",
2121
"lodash-es": "^4.17.21",
2222
"d3-interpolate": "^2.0.1",
23-
"d3-color": "^1.4.0",
24-
"@fullstory/browser": "^1.4.9",
25-
"mixpanel-browser": "^2.41.0"
23+
"d3-color": "^1.4.0"
2624
},
2725
"devDependencies": {
2826
"@hypertrace/test-utils": "^0.0.0"
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { createServiceFactory, mockProvider } from '@ngneat/spectator/jest';
2+
import { UserTelemetryImplService } from '../user-telemetry-impl.service';
3+
import { TelemetryGlobalErrorHandler } from './telemetry-global-error-handler';
4+
5+
describe('Telemetry Global Error Handler ', () => {
6+
const createService = createServiceFactory({
7+
service: TelemetryGlobalErrorHandler,
8+
providers: [
9+
mockProvider(UserTelemetryImplService, {
10+
trackErrorEvent: jest.fn()
11+
})
12+
]
13+
});
14+
15+
test('should delegate to telemetry provider after registration', () => {
16+
const spectator = createService();
17+
try {
18+
spectator.service.handleError(new Error('Test error'));
19+
} catch (_) {
20+
// NoOP
21+
}
22+
23+
expect(spectator.inject(UserTelemetryImplService).trackErrorEvent).toHaveBeenCalledWith(
24+
'Test error',
25+
expect.objectContaining({
26+
message: 'Test error',
27+
name: 'Error',
28+
isError: true
29+
})
30+
);
31+
});
32+
});

projects/common/src/telemetry/error-handler/telemetry-global-error-handler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { LocationStrategy, PathLocationStrategy } from '@angular/common';
22
import { ErrorHandler, Injectable, Injector } from '@angular/core';
3-
import { UserTelemetryInternalService } from '../user-telemetry-internal.service';
3+
import { UserTelemetryImplService } from '../user-telemetry-impl.service';
44

55
@Injectable()
66
export class TelemetryGlobalErrorHandler implements ErrorHandler {
77
public constructor(private readonly injector: Injector) {}
88

99
public handleError(error: Error): Error {
10-
const telemetryService = this.injector.get(UserTelemetryInternalService);
10+
const telemetryService = this.injector.get(UserTelemetryImplService);
1111

1212
const location = this.injector.get(LocationStrategy);
1313
const message = error.message ?? error.toString();
Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
1-
import { InjectionToken, ProviderToken } from '@angular/core';
1+
import { ProviderToken } from '@angular/core';
22
import { Dictionary } from './../utilities/types/types';
3-
export interface UserTraits extends Dictionary<unknown> {
4-
email?: string;
5-
companyName?: string;
6-
name?: string;
7-
displayName?: string;
8-
}
93

10-
export interface UserTelemetryRegistrationConfig<InitConfig> {
11-
telemetryProvider: ProviderToken<UserTelemetryProvider<InitConfig>>;
12-
initConfig: InitConfig;
4+
export interface UserTelemetryRegistrationConfig<TInitConfig> {
5+
telemetryProvider: ProviderToken<UserTelemetryProvider<TInitConfig>>;
6+
initConfig: TInitConfig;
137
enablePageTracking: boolean;
148
enableEventTracking: boolean;
159
enableErrorTracking: boolean;
1610
}
1711

18-
export interface UserTelemetryProvider<InitConfig = unknown> {
19-
initialize(config: InitConfig): void;
12+
export interface UserTelemetryProvider<TInitConfig = unknown> {
13+
initialize(config: TInitConfig): void;
2014
identify(userTraits: UserTraits): void;
2115
trackEvent?(name: string, eventData: Dictionary<unknown>): void;
2216
trackPage?(url: string, eventData: Dictionary<unknown>): void;
@@ -28,6 +22,14 @@ export interface TelemetryProviderConfig {
2822
orgId: string;
2923
}
3024

31-
export const USER_TELEMETRY_PROVIDER_TOKENS = new InjectionToken<UserTelemetryRegistrationConfig<unknown>[][]>(
32-
'USER_TELEMETRY_PROVIDER_TOKENS'
33-
);
25+
export interface UserTraits extends Dictionary<unknown> {
26+
email?: string;
27+
companyName?: string;
28+
name?: string;
29+
displayName?: string;
30+
}
31+
32+
export const enum TrackUserEventsType {
33+
Click = 'click',
34+
ContextMenu = 'context-menu'
35+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { CommonModule } from '@angular/common';
2+
import { fakeAsync } from '@angular/core/testing';
3+
import { createDirectiveFactory, mockProvider, SpectatorDirective } from '@ngneat/spectator/jest';
4+
import { UserTelemetryImplService } from '../user-telemetry-impl.service';
5+
import { TrackDirective } from './track.directive';
6+
7+
describe('Track directive', () => {
8+
let spectator: SpectatorDirective<TrackDirective>;
9+
10+
const createDirective = createDirectiveFactory<TrackDirective>({
11+
directive: TrackDirective,
12+
imports: [CommonModule],
13+
providers: [
14+
mockProvider(UserTelemetryImplService, {
15+
trackEvent: jest.fn()
16+
})
17+
]
18+
});
19+
20+
test('propagates events with default config', fakeAsync(() => {
21+
spectator = createDirective(
22+
`
23+
<div class="content" [htTrack] [htTrackLabel]="label">Test Content</div>
24+
`,
25+
{
26+
hostProps: {
27+
events: ['click'],
28+
label: 'Content'
29+
}
30+
}
31+
);
32+
33+
const telemetryService = spectator.inject(UserTelemetryImplService);
34+
35+
spectator.click(spectator.element);
36+
spectator.tick();
37+
38+
expect(telemetryService.trackEvent).toHaveBeenCalledWith(
39+
'click: Content',
40+
expect.objectContaining({ type: 'click' })
41+
);
42+
}));
43+
44+
test('propagates events with custom config', fakeAsync(() => {
45+
spectator = createDirective(
46+
`
47+
<div class="content" [htTrack]="events" [htTrackLabel]="label">Test Content</div>
48+
`,
49+
{
50+
hostProps: {
51+
events: ['mouseover'],
52+
label: 'Content'
53+
}
54+
}
55+
);
56+
57+
const telemetryService = spectator.inject(UserTelemetryImplService);
58+
59+
spectator.dispatchMouseEvent(spectator.element, 'mouseover');
60+
spectator.tick();
61+
62+
expect(telemetryService.trackEvent).toHaveBeenCalledWith(
63+
'mouseover: Content',
64+
expect.objectContaining({ type: 'mouseover' })
65+
);
66+
}));
67+
});

0 commit comments

Comments
 (0)