1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-12 06:23:38 +00:00

feat: add analytics service & directive

This commit is contained in:
William Martin
2024-12-09 11:13:51 -05:00
parent 69800d01ab
commit 1d492083e0
8 changed files with 91 additions and 1 deletions

View File

@@ -1,11 +1,12 @@
import { DOCUMENT } from "@angular/common";
import { Component, Inject, NgZone, OnDestroy, OnInit } from "@angular/core";
import { Component, inject, Inject, NgZone, OnDestroy, OnInit } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { NavigationEnd, Router } from "@angular/router";
import * as jq from "jquery";
import { Subject, filter, firstValueFrom, map, takeUntil, timeout, catchError, of } from "rxjs";
import { CollectionService } from "@bitwarden/admin-console/common";
import { AnalyticsService } from "@bitwarden/angular/analytics/analytics.service";
import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service";
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
import { SearchService } from "@bitwarden/common/abstractions/search.service";
@@ -60,6 +61,8 @@ export class AppComponent implements OnDestroy, OnInit {
private isIdle = false;
private destroy$ = new Subject<void>();
private analyticsService = inject(AnalyticsService);
loading = false;
constructor(
@@ -267,6 +270,8 @@ export class AppComponent implements OnDestroy, OnInit {
new DisableSendPolicy(),
new SendOptionsPolicy(),
]);
void this.analyticsService.init();
}
ngOnDestroy() {

View File

@@ -299,6 +299,8 @@ const devServer =
https://api.fastmail.com
https://api.forwardemail.net
http://localhost:5000
https://plausible.io/api/event
;object-src
'self'
blob:

View File

@@ -0,0 +1,48 @@
import { inject, Injectable } from "@angular/core";
import Plausible from "plausible-tracker";
// import { firstValueFrom } from "rxjs";
import { ANALYTICS, GlobalStateProvider, KeyDefinition } from "@bitwarden/common/platform/state";
const ANALYTICS_ENABLED_KEY_DEF = new KeyDefinition<boolean>(ANALYTICS, "analytics_enabled", {
deserializer: (s) => s,
});
@Injectable({ providedIn: "root" })
export class AnalyticsService {
private plausible: ReturnType<typeof Plausible>;
private plausibleCleanup?: () => any;
private readonly _enabledState = inject(GlobalStateProvider).get(ANALYTICS_ENABLED_KEY_DEF);
readonly enabled$ = this._enabledState.state$;
async init() {
this.plausible = Plausible({
domain: "bitwarden",
trackLocalhost: true,
hashMode: true,
});
// TODO: uncomment when a toggle is added to settings page
// const enabled = await firstValueFrom(this._enabledState.state$);
// if (!enabled) {
// return;
// }
await this.enable();
}
async enable() {
await this._enabledState.update((_prevState) => true);
this.plausibleCleanup = this.plausible.enableAutoPageviews();
}
async disable() {
await this._enabledState.update((_prevState) => false);
this?.plausibleCleanup();
}
trackEvent(eventName: string) {
this.plausible.trackEvent(eventName);
}
}

View File

@@ -0,0 +1,22 @@
import { Directive, HostListener, inject, Input } from "@angular/core";
import { AnalyticsService } from "./analytics.service";
@Directive({
selector: "[track-event]",
standalone: true,
})
export class TrackEventDirective {
private analyticsService = inject(AnalyticsService);
@Input({
alias: "track-event",
required: true,
})
eventName!: string;
@HostListener("click")
handleClick() {
this.analyticsService.trackEvent(this.eventName);
}
}

View File

@@ -27,6 +27,7 @@ import {
TypographyModule,
} from "@bitwarden/components";
import { TrackEventDirective } from "./analytics/track-event.directive";
import { TwoFactorIconComponent } from "./auth/components/two-factor-icon.component";
import { DeprecatedCalloutComponent } from "./components/callout.component";
import { A11yInvalidDirective } from "./directives/a11y-invalid.directive";
@@ -81,6 +82,7 @@ import { IconComponent } from "./vault/components/icon.component";
IconModule,
LinkModule,
IconModule,
TrackEventDirective,
],
declarations: [
A11yInvalidDirective,

View File

@@ -124,6 +124,7 @@ export const TASK_SCHEDULER_DISK = new StateDefinition("taskScheduler", "disk");
// Design System
export const POPUP_STYLE_DISK = new StateDefinition("popupStyle", "disk");
export const ANALYTICS = new StateDefinition("analytics", "disk");
// Secrets Manager

9
package-lock.json generated
View File

@@ -62,6 +62,7 @@
"open": "8.4.2",
"papaparse": "5.4.1",
"patch-package": "8.0.0",
"plausible-tracker": "^0.3.9",
"popper.js": "1.16.1",
"proper-lockfile": "4.1.2",
"qrcode-parser": "2.1.3",
@@ -27174,6 +27175,14 @@
"node": ">=4"
}
},
"node_modules/plausible-tracker": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/plausible-tracker/-/plausible-tracker-0.3.9.tgz",
"integrity": "sha512-hMhneYm3GCPyQon88SZrVJx+LlqhM1kZFQbuAgXPoh/Az2YvO1B6bitT9qlhpiTdJlsT5lsr3gPmzoVjb5CDXA==",
"engines": {
"node": ">=10"
}
},
"node_modules/plist": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",

View File

@@ -191,6 +191,7 @@
"open": "8.4.2",
"papaparse": "5.4.1",
"patch-package": "8.0.0",
"plausible-tracker": "^0.3.9",
"popper.js": "1.16.1",
"proper-lockfile": "4.1.2",
"qrcode-parser": "2.1.3",