From 405702ba8b04d6065b609897a5dbbe2480ebe739 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 26 Jan 2024 09:22:21 +0100 Subject: [PATCH] feat: add api backward compatibility for more analytics modules Signed-off-by: Camila Belo --- plugins/analytics-module-ga/package.json | 1 + .../AnalyticsApi/GoogleAnalytics.test.ts | 59 +++++++++++++++++++ .../AnalyticsApi/GoogleAnalytics.ts | 19 ++++-- .../package.json | 1 + .../AnalyticsApi/NewRelicBrowser.ts | 15 ++++- yarn.lock | 2 + 6 files changed, 89 insertions(+), 8 deletions(-) diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index 3d367a5889..cabff881ad 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -32,6 +32,7 @@ "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "react-ga": "^3.3.0" }, "peerDependencies": { diff --git a/plugins/analytics-module-ga/src/apis/implementations/AnalyticsApi/GoogleAnalytics.test.ts b/plugins/analytics-module-ga/src/apis/implementations/AnalyticsApi/GoogleAnalytics.test.ts index 65e9256aa8..1380f9c715 100644 --- a/plugins/analytics-module-ga/src/apis/implementations/AnalyticsApi/GoogleAnalytics.test.ts +++ b/plugins/analytics-module-ga/src/apis/implementations/AnalyticsApi/GoogleAnalytics.test.ts @@ -508,4 +508,63 @@ describe('GoogleAnalytics', () => { expect(lastData.queueTime).toBeUndefined(); }); }); + + describe('api backward compatibility', () => { + it('continue working with legacy App category', () => { + const api = GoogleAnalytics.fromConfig(basicValidConfig); + + expect(api.captureEvent).toBeDefined(); + + api.captureEvent({ + action: 'navigate', + subject: '/', + context, + }); + + const [command, data] = ReactGA.testModeAPI.calls[1]; + expect(command).toBe('send'); + expect(data).toMatchObject({ + hitType: 'pageview', + page: '/', + }); + }); + + it('use lowercase app as the new default category', () => { + const api = GoogleAnalytics.fromConfig(basicValidConfig); + + expect(api.captureEvent).toBeDefined(); + + api.captureEvent({ + action: 'navigate', + subject: '/', + context: { ...context, extensionId: '', extension: '' }, + }); + + const [command, data] = ReactGA.testModeAPI.calls[1]; + expect(command).toBe('send'); + expect(data).toMatchObject({ + hitType: 'pageview', + page: '/', + }); + }); + + it('prioritize new context extension id over old extension property', () => { + const api = GoogleAnalytics.fromConfig(basicValidConfig); + + expect(api.captureEvent).toBeDefined(); + + api.captureEvent({ + action: 'navigate', + subject: '/', + context: { ...context, extensionId: 'app', extension: '' }, + }); + + const [command, data] = ReactGA.testModeAPI.calls[1]; + expect(command).toBe('send'); + expect(data).toMatchObject({ + hitType: 'pageview', + page: '/', + }); + }); + }); }); diff --git a/plugins/analytics-module-ga/src/apis/implementations/AnalyticsApi/GoogleAnalytics.ts b/plugins/analytics-module-ga/src/apis/implementations/AnalyticsApi/GoogleAnalytics.ts index 17c5b26be1..045bc94f3a 100644 --- a/plugins/analytics-module-ga/src/apis/implementations/AnalyticsApi/GoogleAnalytics.ts +++ b/plugins/analytics-module-ga/src/apis/implementations/AnalyticsApi/GoogleAnalytics.ts @@ -22,6 +22,11 @@ import { AnalyticsEventAttributes, IdentityApi, } from '@backstage/core-plugin-api'; +import { + AnalyticsApi as NewAnalyticsApi, + AnalyticsEvent as NewAnalyticsEvent, + AnalyticsContextValue as NewAnalyticsContextValue, +} from '@backstage/frontend-plugin-api'; import { Config } from '@backstage/config'; import { DeferredCapture } from '../../../util'; import { @@ -40,7 +45,7 @@ type CustomDimensionOrMetricConfig = { * Google Analytics API provider for the Backstage Analytics API. * @public */ -export class GoogleAnalytics implements AnalyticsApi { +export class GoogleAnalytics implements AnalyticsApi, NewAnalyticsApi { private readonly cdmConfig: CustomDimensionOrMetricConfig[]; private customUserIdTransform?: (userEntityRef: string) => Promise; private readonly capture: DeferredCapture; @@ -157,11 +162,15 @@ export class GoogleAnalytics implements AnalyticsApi { * pageview and the rest as custom events. All custom dimensions/metrics are * applied as they should be (set on pageview, merged object on events). */ - captureEvent(event: AnalyticsEvent) { + captureEvent(event: AnalyticsEvent | NewAnalyticsEvent) { const { context, action, subject, value, attributes } = event; const customMetadata = this.getCustomDimensionMetrics(context, attributes); - if (action === 'navigate' && context.extension === 'App') { + const extensionId = context.extensionId || context.extension; + const category = extensionId ? String(extensionId) : 'app'; + + // The legacy default extension was 'App' and the new one is 'app' + if (action === 'navigate' && category.toLocaleLowerCase() === 'app') { this.capture.pageview(subject, customMetadata); return; } @@ -184,7 +193,7 @@ export class GoogleAnalytics implements AnalyticsApi { } this.capture.event({ - category: context.extension || 'App', + category, action, label: subject, value, @@ -197,7 +206,7 @@ export class GoogleAnalytics implements AnalyticsApi { * Event Attributes, e.g. { dimension1: "some value", metric8: 42 } */ private getCustomDimensionMetrics( - context: AnalyticsContextValue, + context: AnalyticsContextValue | NewAnalyticsContextValue, attributes: AnalyticsEventAttributes = {}, ) { const customDimensionsMetrics: { [x: string]: string | number | boolean } = diff --git a/plugins/analytics-module-newrelic-browser/package.json b/plugins/analytics-module-newrelic-browser/package.json index 0815b62b6c..44610dd026 100644 --- a/plugins/analytics-module-newrelic-browser/package.json +++ b/plugins/analytics-module-newrelic-browser/package.json @@ -26,6 +26,7 @@ "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@newrelic/browser-agent": "^1.236.0" }, "peerDependencies": { diff --git a/plugins/analytics-module-newrelic-browser/src/apis/implementations/AnalyticsApi/NewRelicBrowser.ts b/plugins/analytics-module-newrelic-browser/src/apis/implementations/AnalyticsApi/NewRelicBrowser.ts index f2f35b5765..ba04aea322 100644 --- a/plugins/analytics-module-newrelic-browser/src/apis/implementations/AnalyticsApi/NewRelicBrowser.ts +++ b/plugins/analytics-module-newrelic-browser/src/apis/implementations/AnalyticsApi/NewRelicBrowser.ts @@ -19,6 +19,10 @@ import { IdentityApi, AnalyticsEvent, } from '@backstage/core-plugin-api'; +import { + AnalyticsApi as NewAnalyicsApi, + AnalyticsEvent as NewAnalyticsEvent, +} from '@backstage/frontend-plugin-api'; import { BrowserAgent } from '@newrelic/browser-agent/loaders/browser-agent'; import type { setAPI } from '@newrelic/browser-agent/loaders/api/api'; @@ -37,7 +41,7 @@ type NewRelicBrowserOptions = { * New Relic Browser API provider for the Backstage Analytics API. * @public */ -export class NewRelicBrowser implements AnalyticsApi { +export class NewRelicBrowser implements AnalyticsApi, NewAnalyicsApi { private readonly agent: NewRelicAPI; private constructor( @@ -121,9 +125,14 @@ export class NewRelicBrowser implements AnalyticsApi { ); } - captureEvent(event: AnalyticsEvent) { + captureEvent(event: AnalyticsEvent | NewAnalyticsEvent) { const { context, action, subject, value, attributes } = event; - if (action === 'navigate' && context.extension === 'App') { + + const extensionId = context.extensionId || context.extension; + const category = extensionId ? String(extensionId) : 'app'; + + // The legacy default extension was 'App' and the new one is 'app' + if (action === 'navigate' && category.toLocaleLowerCase() === 'app') { const interaction = this.agent.interaction(); interaction.setName(subject); if (value) { diff --git a/yarn.lock b/yarn.lock index efac8bb495..41ceb79882 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4336,6 +4336,7 @@ __metadata: "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^14.0.0 @@ -4357,6 +4358,7 @@ __metadata: "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@newrelic/browser-agent": ^1.236.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^14.0.0