Simplify/clarify Analytics API types and naming.
Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
+32
-32
@@ -50,7 +50,7 @@ describe('GoogleAnalytics', () => {
|
||||
});
|
||||
|
||||
describe('integration', () => {
|
||||
const domain = {
|
||||
const context = {
|
||||
componentName: 'App',
|
||||
pluginId: 'some-plugin',
|
||||
releaseNum: 1337,
|
||||
@@ -65,26 +65,26 @@ describe('GoogleAnalytics', () => {
|
||||
{
|
||||
type: 'dimension',
|
||||
index: 1,
|
||||
source: 'domain',
|
||||
attribute: 'pluginId',
|
||||
source: 'context',
|
||||
key: 'pluginId',
|
||||
},
|
||||
{
|
||||
type: 'dimension',
|
||||
index: 2,
|
||||
source: 'context',
|
||||
attribute: 'extraDimension',
|
||||
source: 'attributes',
|
||||
key: 'extraDimension',
|
||||
},
|
||||
{
|
||||
type: 'metric',
|
||||
index: 1,
|
||||
source: 'domain',
|
||||
attribute: 'releaseNum',
|
||||
source: 'context',
|
||||
key: 'releaseNum',
|
||||
},
|
||||
{
|
||||
type: 'metric',
|
||||
index: 2,
|
||||
source: 'context',
|
||||
attribute: 'extraMetric',
|
||||
source: 'attributes',
|
||||
key: 'extraMetric',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -95,9 +95,9 @@ describe('GoogleAnalytics', () => {
|
||||
it('tracks basic pageview', () => {
|
||||
const api = GoogleAnalytics.fromConfig(basicValidConfig);
|
||||
api.captureEvent({
|
||||
verb: 'navigate',
|
||||
noun: '/',
|
||||
domain,
|
||||
action: 'navigate',
|
||||
subject: '/',
|
||||
context,
|
||||
});
|
||||
|
||||
const [command, data] = ReactGA.testModeAPI.calls[1];
|
||||
@@ -115,17 +115,17 @@ describe('GoogleAnalytics', () => {
|
||||
const expectedLabel = 'on something';
|
||||
const expectedValue = 42;
|
||||
api.captureEvent({
|
||||
verb: expectedAction,
|
||||
noun: expectedLabel,
|
||||
action: expectedAction,
|
||||
subject: expectedLabel,
|
||||
value: expectedValue,
|
||||
domain,
|
||||
context,
|
||||
});
|
||||
|
||||
const [command, data] = ReactGA.testModeAPI.calls[1];
|
||||
expect(command).toBe('send');
|
||||
expect(data).toMatchObject({
|
||||
hitType: 'event',
|
||||
eventCategory: domain.componentName,
|
||||
eventCategory: context.componentName,
|
||||
eventAction: expectedAction,
|
||||
eventLabel: expectedLabel,
|
||||
eventValue: expectedValue,
|
||||
@@ -135,17 +135,17 @@ describe('GoogleAnalytics', () => {
|
||||
it('captures configured custom dimensions/metrics on pageviews', () => {
|
||||
const api = GoogleAnalytics.fromConfig(advancedConfig);
|
||||
api.captureEvent({
|
||||
verb: 'navigate',
|
||||
noun: '/a-page',
|
||||
domain,
|
||||
action: 'navigate',
|
||||
subject: '/a-page',
|
||||
context,
|
||||
});
|
||||
|
||||
// Expect a set command first.
|
||||
const [setCommand, setData] = ReactGA.testModeAPI.calls[1];
|
||||
expect(setCommand).toBe('set');
|
||||
expect(setData).toMatchObject({
|
||||
dimension1: domain.pluginId,
|
||||
metric1: domain.releaseNum,
|
||||
dimension1: context.pluginId,
|
||||
metric1: context.releaseNum,
|
||||
});
|
||||
|
||||
// Followed by a send command.
|
||||
@@ -164,26 +164,26 @@ describe('GoogleAnalytics', () => {
|
||||
const expectedLabel = 'some query';
|
||||
const expectedValue = 5;
|
||||
api.captureEvent({
|
||||
verb: expectedAction,
|
||||
noun: expectedLabel,
|
||||
action: expectedAction,
|
||||
subject: expectedLabel,
|
||||
value: expectedValue,
|
||||
context: {
|
||||
attributes: {
|
||||
extraDimension: false,
|
||||
extraMetric: 0,
|
||||
},
|
||||
domain,
|
||||
context,
|
||||
});
|
||||
|
||||
const [command, data] = ReactGA.testModeAPI.calls[1];
|
||||
expect(command).toBe('send');
|
||||
expect(data).toMatchObject({
|
||||
hitType: 'event',
|
||||
eventCategory: domain.componentName,
|
||||
eventCategory: context.componentName,
|
||||
eventAction: expectedAction,
|
||||
eventLabel: expectedLabel,
|
||||
eventValue: expectedValue,
|
||||
dimension1: domain.pluginId,
|
||||
metric1: domain.releaseNum,
|
||||
dimension1: context.pluginId,
|
||||
metric1: context.releaseNum,
|
||||
dimension2: false,
|
||||
metric2: 0,
|
||||
});
|
||||
@@ -193,12 +193,12 @@ describe('GoogleAnalytics', () => {
|
||||
const api = GoogleAnalytics.fromConfig(advancedConfig);
|
||||
|
||||
api.captureEvent({
|
||||
verb: 'verb',
|
||||
noun: 'noun',
|
||||
context: {
|
||||
action: 'verb',
|
||||
subject: 'noun',
|
||||
attributes: {
|
||||
extraMetric: 'not a number',
|
||||
},
|
||||
domain,
|
||||
context,
|
||||
});
|
||||
|
||||
const [, data] = ReactGA.testModeAPI.calls[1];
|
||||
|
||||
+21
-23
@@ -17,17 +17,17 @@
|
||||
import ReactGA from 'react-ga';
|
||||
import {
|
||||
AnalyticsApi,
|
||||
AnalyticsDomainValue,
|
||||
AnalyticsEventContext,
|
||||
DomainDecoratedAnalyticsEvent,
|
||||
AnalyticsContextValue,
|
||||
AnalyticsEventAttributes,
|
||||
AnalyticsEvent,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { Config } from '@backstage/config';
|
||||
|
||||
type CDM = {
|
||||
type: 'dimension' | 'metric';
|
||||
index: number;
|
||||
source: 'domain' | 'context';
|
||||
attribute: string;
|
||||
source: 'context' | 'attributes';
|
||||
key: string;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -79,7 +79,7 @@ export class GoogleAnalytics implements AnalyticsApi {
|
||||
type: c.getString('type') as CDM['type'],
|
||||
index: c.getNumber('index'),
|
||||
source: c.getString('source') as CDM['source'],
|
||||
attribute: c.getString('attribute'),
|
||||
key: c.getString('key'),
|
||||
};
|
||||
}) || [];
|
||||
|
||||
@@ -98,47 +98,45 @@ export class GoogleAnalytics implements AnalyticsApi {
|
||||
* applied as they should be (set on pageview, merged object on events).
|
||||
*/
|
||||
captureEvent({
|
||||
domain,
|
||||
verb,
|
||||
noun,
|
||||
value,
|
||||
context,
|
||||
}: DomainDecoratedAnalyticsEvent) {
|
||||
const customMetadata = this.getCustomDimensionMetrics(domain, context);
|
||||
action,
|
||||
subject,
|
||||
value,
|
||||
attributes,
|
||||
}: AnalyticsEvent) {
|
||||
const customMetadata = this.getCustomDimensionMetrics(context, attributes);
|
||||
|
||||
if (verb === 'navigate' && domain?.componentName === 'App') {
|
||||
if (action === 'navigate' && context?.componentName === 'App') {
|
||||
// Set any/all custom dimensions.
|
||||
if (Object.keys(customMetadata).length) {
|
||||
ReactGA.set(customMetadata);
|
||||
}
|
||||
|
||||
ReactGA.pageview(noun);
|
||||
ReactGA.pageview(subject);
|
||||
return;
|
||||
}
|
||||
|
||||
ReactGA.event({
|
||||
category: domain.componentName || 'App',
|
||||
action: verb,
|
||||
label: noun,
|
||||
category: context.componentName || 'App',
|
||||
action,
|
||||
label: subject,
|
||||
value,
|
||||
...customMetadata,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object of dimensions/metrics given an Analytics Domain and an
|
||||
* Returns an object of dimensions/metrics given an Analytics Context and an
|
||||
* Event Context, e.g. { dimension1: "some value", metric8: 42 }
|
||||
*/
|
||||
private getCustomDimensionMetrics(
|
||||
domain: AnalyticsDomainValue,
|
||||
context: AnalyticsEventContext = {},
|
||||
context: AnalyticsContextValue,
|
||||
attributes: AnalyticsEventAttributes = {},
|
||||
) {
|
||||
const dataArray = this.cdmConfig
|
||||
.map(cdm => {
|
||||
const value =
|
||||
cdm.source === 'domain'
|
||||
? domain[cdm.attribute]
|
||||
: context[cdm.attribute];
|
||||
cdm.source === 'context' ? context[cdm.key] : attributes[cdm.key];
|
||||
|
||||
// Never pass a non-numeric value on a metric.
|
||||
if (cdm.type === 'metric' && typeof value !== 'number') {
|
||||
|
||||
Reference in New Issue
Block a user