diff --git a/package-lock.json b/package-lock.json index ac0bfbe74..8a0ff7c9b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -77,6 +77,7 @@ "@types/d3-zoom": "^1.7.5", "@types/jest": "^26.0.24", "@types/lodash-es": "^4.17.4", + "@types/mixpanel-browser": "^2.35.7", "@types/node": "^16.7.10", "@types/uuid": "^8.3.1", "@types/webpack-env": "^1.16.2", @@ -5875,6 +5876,12 @@ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, + "node_modules/@types/mixpanel-browser": { + "version": "2.35.7", + "resolved": "https://registry.npmjs.org/@types/mixpanel-browser/-/mixpanel-browser-2.35.7.tgz", + "integrity": "sha512-cisiRR1Fky5X1g9Z7tKliR8fB6V6TJ+7oa7Xca2AcYhtpOR8Otp4/pMdd9tLFPKqOLTWiD2S4gfN2zHFv7Z7KA==", + "dev": true + }, "node_modules/@types/mkdirp": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.1.tgz", @@ -34428,6 +34435,12 @@ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, + "@types/mixpanel-browser": { + "version": "2.35.7", + "resolved": "https://registry.npmjs.org/@types/mixpanel-browser/-/mixpanel-browser-2.35.7.tgz", + "integrity": "sha512-cisiRR1Fky5X1g9Z7tKliR8fB6V6TJ+7oa7Xca2AcYhtpOR8Otp4/pMdd9tLFPKqOLTWiD2S4gfN2zHFv7Z7KA==", + "dev": true + }, "@types/mkdirp": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.1.tgz", diff --git a/package.json b/package.json index 9fe73858d..27821296e 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "@angular/platform-browser-dynamic": "^12.2.1", "@angular/router": "^12.2.1", "@apollo/client": "^3.4.13", + "@fullstory/browser": "^1.4.9", "@hypertrace/hyperdash": "^1.2.1", "@hypertrace/hyperdash-angular": "^2.6.0", "@types/d3-hierarchy": "^2.0.0", @@ -62,12 +63,11 @@ "graphql-tag": "^2.12.5", "iso8601-duration": "^1.3.0", "lodash-es": "^4.17.21", + "mixpanel-browser": "^2.41.0", "rxjs": "~6.6.7", "tslib": "^2.3.1", "uuid": "^8.3.2", - "zone.js": "~0.11.4", - "@fullstory/browser": "^1.4.9", - "mixpanel-browser": "^2.41.0" + "zone.js": "~0.11.4" }, "devDependencies": { "@angular-builders/jest": "^11.2.0", @@ -92,6 +92,7 @@ "@types/d3-zoom": "^1.7.5", "@types/jest": "^26.0.24", "@types/lodash-es": "^4.17.4", + "@types/mixpanel-browser": "^2.35.7", "@types/node": "^16.7.10", "@types/uuid": "^8.3.1", "@types/webpack-env": "^1.16.2", diff --git a/projects/common/src/public-api.ts b/projects/common/src/public-api.ts index aae6ba442..a18f2bd6d 100644 --- a/projects/common/src/public-api.ts +++ b/projects/common/src/public-api.ts @@ -98,6 +98,17 @@ export * from './utilities/rxjs/subscription-lifeycle.service'; export * from './utilities/types/angular-change-object'; export * from './utilities/types/types'; +// Telemetry +export * from './telemetry/user-telemetry.module'; +export * from './telemetry/track/user-telemetry-tracking.module'; +export * from './telemetry/track/track.directive'; +export * from './telemetry/user-telemetry.service'; +export * from './telemetry/telemetry'; +export { FullStoryTelemetry } from './telemetry/providers/fullstory/full-story-provider'; +export { FreshPaintTelemetry } from './telemetry/providers/freshpaint/freshpaint-provider'; +export { MixPanelTelemetry } from './telemetry/providers/mixpanel/mixpanel-provider'; +export { TrackDirective } from './telemetry/track/track.directive'; + // Time export * from './time/fixed-time-range'; export * from './time/interval-duration.service'; diff --git a/projects/common/src/telemetry/providers/freshpaint/load-snippet/index.js b/projects/common/src/telemetry/providers/freshpaint/load-snippet/index.js index 59f89bedb..0a4cf061c 100644 --- a/projects/common/src/telemetry/providers/freshpaint/load-snippet/index.js +++ b/projects/common/src/telemetry/providers/freshpaint/load-snippet/index.js @@ -1,6 +1,6 @@ // tslint:disable -export const loadFreshPaint = () => { +const loadFreshPaint = () => { if (window.freshpaint) { return window.freshpaint; } @@ -79,3 +79,7 @@ export const loadFreshPaint = () => { return freshpaint; }; + +module.exports = { + loadFreshPaint +}; diff --git a/projects/common/src/telemetry/providers/google-analytics/load-snippet/index.js b/projects/common/src/telemetry/providers/google-analytics/load-snippet/index.js index 69a8b6f0f..920a20cf2 100644 --- a/projects/common/src/telemetry/providers/google-analytics/load-snippet/index.js +++ b/projects/common/src/telemetry/providers/google-analytics/load-snippet/index.js @@ -1,6 +1,6 @@ // tslint:disable -export const loadGA = () => { +const loadGA = () => { /** * Creates a temporary global ga object and loads analytics.js. * Parameters o, a, and m are all used internally. They could have been @@ -49,3 +49,7 @@ export const loadGA = () => { return ga; }; + +module.exports = { + loadGA +}; diff --git a/projects/common/src/telemetry/track/user-telemetry-tracking.module.ts b/projects/common/src/telemetry/track/user-telemetry-tracking.module.ts new file mode 100644 index 000000000..08ae6ddf1 --- /dev/null +++ b/projects/common/src/telemetry/track/user-telemetry-tracking.module.ts @@ -0,0 +1,10 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { TrackDirective } from './track.directive'; + +@NgModule({ + imports: [CommonModule], + declarations: [TrackDirective], + exports: [TrackDirective] +}) +export class UserTelemetryTrackingModule {} diff --git a/projects/common/src/telemetry/user-telemetry-impl.service.ts b/projects/common/src/telemetry/user-telemetry-impl.service.ts index 83eb269e4..5339888ac 100644 --- a/projects/common/src/telemetry/user-telemetry-impl.service.ts +++ b/projects/common/src/telemetry/user-telemetry-impl.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Injector } from '@angular/core'; +import { Injectable, Injector, Optional } from '@angular/core'; import { NavigationEnd, Router } from '@angular/router'; import { filter } from 'rxjs/operators'; import { Dictionary } from '../utilities/types/types'; @@ -9,7 +9,7 @@ import { UserTelemetryService } from './user-telemetry.service'; export class UserTelemetryImplService extends UserTelemetryService { private telemetryProviders: UserTelemetryInternalConfig[] = []; - public constructor(private readonly injector: Injector, private readonly router: Router) { + public constructor(private readonly injector: Injector, @Optional() private readonly router?: Router) { super(); this.setupAutomaticPageTracking(); } @@ -69,7 +69,7 @@ export class UserTelemetryImplService extends UserTelemetryService { } private setupAutomaticPageTracking(): void { - this.router.events + this.router?.events .pipe(filter((event): event is NavigationEnd => event instanceof NavigationEnd)) .subscribe(route => this.trackPageEvent(`Visited: ${route.url}`, { url: route.url })); } diff --git a/projects/common/src/telemetry/user-telemetry.module.ts b/projects/common/src/telemetry/user-telemetry.module.ts index 30aa00ab6..c2ec8f2a0 100644 --- a/projects/common/src/telemetry/user-telemetry.module.ts +++ b/projects/common/src/telemetry/user-telemetry.module.ts @@ -4,7 +4,12 @@ import { UserTelemetryRegistrationConfig } from './telemetry'; import { UserTelemetryImplService } from './user-telemetry-impl.service'; import { UserTelemetryService } from './user-telemetry.service'; +const USER_TELEMETRY_PROVIDER_TOKENS = new InjectionToken[][]>( + 'USER_TELEMETRY_PROVIDER_TOKENS' +); + @NgModule() +// tslint:disable:no-unnecessary-class export class UserTelemetryModule { public constructor( @Inject(USER_TELEMETRY_PROVIDER_TOKENS) providerConfigs: UserTelemetryRegistrationConfig[][], @@ -35,7 +40,3 @@ export class UserTelemetryModule { }; } } - -const USER_TELEMETRY_PROVIDER_TOKENS = new InjectionToken[][]>( - 'USER_TELEMETRY_PROVIDER_TOKENS' -); diff --git a/projects/components/src/breadcrumbs/breadcrumbs.component.test.ts b/projects/components/src/breadcrumbs/breadcrumbs.component.test.ts index d13c86f34..09c0a81a8 100644 --- a/projects/components/src/breadcrumbs/breadcrumbs.component.test.ts +++ b/projects/components/src/breadcrumbs/breadcrumbs.component.test.ts @@ -1,7 +1,9 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { RouterTestingModule } from '@angular/router/testing'; import { IconLibraryTestingModule } from '@hypertrace/assets-library'; -import { NavigationService } from '@hypertrace/common'; +import { NavigationService, TrackDirective } from '@hypertrace/common'; import { byText, createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/jest'; +import { MockDirective } from 'ng-mocks'; import { EMPTY } from 'rxjs'; import { BreadcrumbsComponent } from './breadcrumbs.component'; import { BreadcrumbsModule } from './breadcrumbs.module'; @@ -13,7 +15,8 @@ describe('BreadcrumbsComponent', () => { const createHost = createHostFactory({ declareComponent: false, component: BreadcrumbsComponent, - imports: [BreadcrumbsModule, HttpClientTestingModule, IconLibraryTestingModule], + imports: [BreadcrumbsModule, HttpClientTestingModule, IconLibraryTestingModule, RouterTestingModule], + declarations: [MockDirective(TrackDirective)], providers: [ mockProvider(NavigationService, { navigation$: EMPTY, diff --git a/projects/components/src/breadcrumbs/breadcrumbs.component.ts b/projects/components/src/breadcrumbs/breadcrumbs.component.ts index 70664d354..cce32bd1a 100644 --- a/projects/components/src/breadcrumbs/breadcrumbs.component.ts +++ b/projects/components/src/breadcrumbs/breadcrumbs.component.ts @@ -15,6 +15,8 @@ import { IconSize } from '../icon/icon-size'; [ngClass]="{ navigable: breadcrumb.url !== undefined }" *ngFor="let breadcrumb of this.breadcrumbs; last as isLast; first as isFirst" [htTooltip]="this.tooltipMap.get(breadcrumb)" + [htTrack] + [htTrackLabel]="breadcrumb.label" > { const createHost = createHostFactory({ component: ButtonComponent, imports: [ButtonModule, RouterTestingModule], + declarations: [MockDirective(TrackDirective)], providers: [], declareComponent: false }); diff --git a/projects/components/src/button/button.component.ts b/projects/components/src/button/button.component.ts index fcfd663f7..b350bfd3e 100644 --- a/projects/components/src/button/button.component.ts +++ b/projects/components/src/button/button.component.ts @@ -10,7 +10,7 @@ import { ButtonRole, ButtonSize, ButtonStyle } from './button'; changeDetection: ChangeDetectionStrategy.OnPush, template: ` -