Push Notifications - metrics
We report about permission for notifications in browser.
We report when service worker is
* polling
* creating notification
Google-Bug-Id: b/202288468
Release-Notes: skip
Change-Id: Ia4727257262f0465e29b2ddd3983f8a73ac16739
diff --git a/polygerrit-ui/app/constants/reporting.ts b/polygerrit-ui/app/constants/reporting.ts
index 0e00d07..ae4aad9 100644
--- a/polygerrit-ui/app/constants/reporting.ts
+++ b/polygerrit-ui/app/constants/reporting.ts
@@ -14,6 +14,8 @@
PLUGINS_INSTALLED = 'Plugins installed',
PLUGINS_FAILED = 'Some plugins failed to load',
USER_REFERRED_FROM = 'User referred from',
+ NOTIFICATION_PERMISSION = 'Notification Permission',
+ SERVICE_WORKER_UPDATE = 'Service worker update',
}
export enum Execution {
diff --git a/polygerrit-ui/app/elements/gr-app.ts b/polygerrit-ui/app/elements/gr-app.ts
index 0cec8dd..fc42240 100644
--- a/polygerrit-ui/app/elements/gr-app.ts
+++ b/polygerrit-ui/app/elements/gr-app.ts
@@ -65,9 +65,11 @@
this.finalizables.push(service);
provide(this, token, () => service);
}
+ // TODO(milutin): Move inside app dependencies.
if (!this.serviceWorkerInstaller) {
this.serviceWorkerInstaller = new ServiceWorkerInstaller(
appContext.flagsService,
+ appContext.reportingService,
appContext.userModel
);
}
diff --git a/polygerrit-ui/app/services/service-worker-installer.ts b/polygerrit-ui/app/services/service-worker-installer.ts
index 53cd325..ffc5be2 100644
--- a/polygerrit-ui/app/services/service-worker-installer.ts
+++ b/polygerrit-ui/app/services/service-worker-installer.ts
@@ -12,11 +12,14 @@
import {UserModel} from '../models/user/user-model';
import {AccountDetailInfo} from '../api/rest-api';
import {until} from '../utils/async-util';
+import {LifeCycle} from '../constants/reporting';
+import {ReportingService} from './gr-reporting/gr-reporting';
/** Type of incoming messages for ServiceWorker. */
export enum ServiceWorkerMessageType {
TRIGGER_NOTIFICATIONS = 'TRIGGER_NOTIFICATIONS',
USER_PREFERENCE_CHANGE = 'USER_PREFERENCE_CHANGE',
+ REPORTING = 'REPORTING',
}
export const TRIGGER_NOTIFICATION_UPDATES_MS = 5 * 60 * 1000;
@@ -30,6 +33,7 @@
constructor(
private readonly flagsService: FlagsService,
+ private readonly reportingService: ReportingService,
private readonly userModel: UserModel
) {
if (!this.flagsService.isEnabled(KnownExperimentId.PUSH_NOTIFICATIONS)) {
@@ -74,8 +78,19 @@
}
await registerServiceWorker('/service-worker.js');
const permission = await Notification.requestPermission();
+ this.reportingService.reportLifeCycle(LifeCycle.NOTIFICATION_PERMISSION, {
+ permission,
+ });
if (this.isPermitted(permission)) this.startTriggerTimer();
this.initialized = true;
+ // Assumption: service worker will send event only to 1 client.
+ navigator.serviceWorker.onmessage = event => {
+ if (event.data?.type === ServiceWorkerMessageType.REPORTING) {
+ this.reportingService.reportLifeCycle(LifeCycle.SERVICE_WORKER_UPDATE, {
+ eventName: event.data.eventName as string | undefined,
+ });
+ }
+ };
}
areNotificationsEnabled() {
diff --git a/polygerrit-ui/app/services/service-worker-installer_test.ts b/polygerrit-ui/app/services/service-worker-installer_test.ts
index e8fd233..d982dee 100644
--- a/polygerrit-ui/app/services/service-worker-installer_test.ts
+++ b/polygerrit-ui/app/services/service-worker-installer_test.ts
@@ -14,9 +14,10 @@
test('init', async () => {
const registerStub = sinon.stub(window.navigator.serviceWorker, 'register');
const flagsService = getAppContext().flagsService;
+ const reportingService = getAppContext().reportingService;
const userModel = getAppContext().userModel;
sinon.stub(flagsService, 'isEnabled').returns(true);
- new ServiceWorkerInstaller(flagsService, userModel);
+ new ServiceWorkerInstaller(flagsService, reportingService, userModel);
const prefs = {
...createDefaultPreferences(),
allow_browser_notifications: true,
diff --git a/polygerrit-ui/app/workers/service-worker-class.ts b/polygerrit-ui/app/workers/service-worker-class.ts
index 218744d..ee85c0e 100644
--- a/polygerrit-ui/app/workers/service-worker-class.ts
+++ b/polygerrit-ui/app/workers/service-worker-class.ts
@@ -133,6 +133,7 @@
// TODO(milutin): Add gerrit host icon
this.ctx.registration.showNotification(change.subject, {body, data});
+ this.sendReport('notify about 1 change');
}
private showNotificationForDashboard(numOfChangesToNotifyAbout: number) {
@@ -140,6 +141,7 @@
const dashboardUrl = createDashboardUrl({});
const data = {url: `${self.location.origin}${dashboardUrl}`};
this.ctx.registration.showNotification(title, {data});
+ this.sendReport(`notify about ${numOfChangesToNotifyAbout} changes`);
}
// private but used in test
@@ -154,6 +156,7 @@
const prevLatestUpdateTimestampMs = this.latestUpdateTimestampMs;
this.latestUpdateTimestampMs = Date.now();
await this.saveState();
+ this.sendReport('polling');
const changes = await this.getLatestAttentionSetChanges();
const latestAttentionChanges = filterAttentionChangesAfter(
changes,
@@ -173,4 +176,19 @@
const changes = payload.parsed as unknown as ParsedChangeInfo[] | undefined;
return changes ?? [];
}
+
+ /**
+ * Send report event to 1 client (last focused one). The client will use
+ * gr-reporting service to send event to metric event collectors.
+ */
+ async sendReport(eventName: string) {
+ const clientsArr = await this.ctx.clients.matchAll({type: 'window'});
+ const lastFocusedClient = clientsArr?.[0];
+ if (!lastFocusedClient) return;
+
+ lastFocusedClient.postMessage({
+ type: ServiceWorkerMessageType.REPORTING,
+ eventName,
+ });
+ }
}