Skip to content

Commit

Permalink
Merge pull request #192 from bcgov/DEVX1881-CreateEvent
Browse files Browse the repository at this point in the history
Create SelfDescribingEvent for Wizard usage
  • Loading branch information
oomIRL authored Dec 11, 2024
2 parents 52ae426 + 5a45e9a commit eba8493
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 109 deletions.
5 changes: 4 additions & 1 deletion plugins/analytics-module-snowplow/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,23 @@
"postpack": "backstage-cli package postpack"
},
"dependencies": {
"@backstage/config": "^1.2.0",
"@backstage/core-components": "^0.15.1",
"@backstage/core-plugin-api": "^1.10.0",
"@backstage/theme": "^0.6.0",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.61",
"@snowplow/browser-plugin-link-click-tracking": "^3.15.0",
"@snowplow/browser-plugin-site-tracking": "^3.23.1",
"@snowplow/browser-tracker": "^3.15.0",
"react-use": "^17.2.4"
},
"peerDependencies": {
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.28.2",
"@backstage/config": "^1.2.0",
"@backstage/core-app-api": "^1.15.1",
"@backstage/dev-utils": "^1.1.2",
"@backstage/test-utils": "^1.7.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,127 +1,164 @@
import { Config } from '@backstage/config';
import { AnalyticsApi, AnalyticsEvent } from '@backstage/core-plugin-api';
import {
AnalyticsApi,
AnalyticsEvent,
} from '@backstage/core-plugin-api';
import { newTracker, trackPageView, enableActivityTracking } from '@snowplow/browser-tracker';
import { LinkClickTrackingPlugin, trackLinkClick } from '@snowplow/browser-plugin-link-click-tracking';
import { SiteTrackingPlugin, trackSiteSearch } from '@snowplow/browser-plugin-site-tracking';
newTracker,
trackPageView,
enableActivityTracking,
trackSelfDescribingEvent,
} from '@snowplow/browser-tracker';
import {
LinkClickTrackingPlugin as linkClickTrackingPlugin,
trackLinkClick,
} from '@snowplow/browser-plugin-link-click-tracking';
import {
SiteTrackingPlugin as siteTrackingPlugin,
trackSiteSearch,
} from '@snowplow/browser-plugin-site-tracking';

export class SnowplowAnalytics implements AnalyticsApi {
private readonly enabled: boolean;
private readonly baseUrl: string;
private readonly debounceTime: number;
private cancelProc: NodeJS.Timeout | null;
private readonly enabled: boolean;
private readonly baseUrl: string;
private readonly debounceTime: number;
private cancelProc: NodeJS.Timeout | null;

private constructor(options: {
enabled: boolean,
baseUrl: string,
trackerId: string,
endpoint: string,
appId: string,
cookieLifetime: number,
debounceTime: number
}) {
const {
enabled,
baseUrl,
trackerId,
endpoint,
appId,
cookieLifetime,
debounceTime
} = options;
private constructor(options: {
enabled: boolean;
baseUrl: string;
trackerId: string;
endpoint: string;
appId: string;
cookieLifetime: number;
debounceTime: number;
}) {
const {
enabled,
baseUrl,
trackerId,
endpoint,
appId,
cookieLifetime,
debounceTime,
} = options;

this.enabled = enabled;
this.baseUrl = baseUrl;
this.cancelProc = null;
this.debounceTime = debounceTime;

// create the Snowplow tracker
if (this.enabled) {
newTracker(trackerId, endpoint, {
appId: appId,
cookieLifetime: cookieLifetime,
platform: "web",
contexts: {
webPage: true
},
plugins: [LinkClickTrackingPlugin(), SiteTrackingPlugin()]
});
this.enabled = enabled;
this.baseUrl = baseUrl;
this.cancelProc = null;
this.debounceTime = debounceTime;

enableActivityTracking({
minimumVisitLength: 30,
heartbeatDelay: 30
});
}
}

static fromConfig(config: Config): SnowplowAnalytics {
const enabled = config.getBoolean('app.analytics.snowplow.enabled');
const baseUrl = config.getString('app.baseUrl');
const endpoint = config.getString('app.analytics.snowplow.collectorUrl');
const appId = config.getOptionalString('app.analytics.snowplow.appId') || 'Snowplow_standalone_OCIO' ;
const trackerId = config.getOptionalString('app.analytics.snowplow.trackerId') || 'rt';
const cookieLifetime = config.getOptionalNumber('app.analytics.snowplow.cookieLifetime') ?? 86400 * 548;
const debounceTime = config.getOptionalNumber('app.analytics.snowplow.debounceTime') ?? 3000;
// create the Snowplow tracker
if (this.enabled) {
newTracker(trackerId, endpoint, {
appId: appId,
cookieLifetime: cookieLifetime,
platform: 'web',
contexts: {
webPage: true,
},
plugins: [linkClickTrackingPlugin(), siteTrackingPlugin()],
});

return new SnowplowAnalytics({
enabled,
baseUrl,
trackerId,
endpoint,
appId,
cookieLifetime,
debounceTime
});
}

captureEvent(event: AnalyticsEvent): void {
if (this.enabled) {
switch (event.action) {
case "search":
this.captureSearch(event);
break;
case "navigate":
trackPageView();
break;
case "click":
case "discover":
this.trackClick(event);
break;
}
}
enableActivityTracking({
minimumVisitLength: 30,
heartbeatDelay: 30,
});
}
}

private trackClick(event: AnalyticsEvent): void {
let to: string = event.attributes?.to as string ?? '';
const hasDomain = new RegExp(/[A-Za-z0-9-]{1,63}\.[A-Za-z]{2,6}/).test(to);
const isMailto = to.startsWith('mailto:');
static fromConfig(config: Config): SnowplowAnalytics {
const enabled = config.getBoolean('app.analytics.snowplow.enabled');
const baseUrl = config.getString('app.baseUrl');
const endpoint = config.getString('app.analytics.snowplow.collectorUrl');
const appId =
config.getOptionalString('app.analytics.snowplow.appId') ||
'Snowplow_standalone_OCIO';
const trackerId =
config.getOptionalString('app.analytics.snowplow.trackerId') || 'rt';
const cookieLifetime =
config.getOptionalNumber('app.analytics.snowplow.cookieLifetime') ??
86400 * 548;
const debounceTime =
config.getOptionalNumber('app.analytics.snowplow.debounceTime') ?? 3000;

// add the baseUrl to relative path links (this is largely to remain consistent with previous analytics)
if (!hasDomain && !isMailto) {
to = (to.startsWith('/'))? this.baseUrl + to : this.baseUrl + '/' + to;
}
return new SnowplowAnalytics({
enabled,
baseUrl,
trackerId,
endpoint,
appId,
cookieLifetime,
debounceTime,
});
}

trackLinkClick({ targetUrl: to, elementContent: event.subject });
captureEvent(event: AnalyticsEvent): void {
if (this.enabled) {
switch (event.action) {
case 'search':
this.captureSearch(event);
break;
case 'navigate':
trackPageView();
break;
case 'click':
case 'discover':
this.trackClick(event);
break;
case 'create':
this.trackCreate(event);
break;
default:
break;
}
}
}

private trackSearch(event: AnalyticsEvent): void {
// trim whitespace, split into non-empty terms
trackSiteSearch({ terms: event.subject.trim().split(" ").filter( t => t ) });
private trackClick(event: AnalyticsEvent): void {
let to: string = (event.attributes?.to as string) ?? '';
const hasDomain = new RegExp(/[A-Za-z0-9-]{1,63}\.[A-Za-z]{2,6}/).test(to);
const isMailto = to.startsWith('mailto:');

// add the baseUrl to relative path links (this is largely to remain consistent with previous analytics)
if (!hasDomain && !isMailto) {
to = to.startsWith('/') ? this.baseUrl + to : `${this.baseUrl}/${to}`;
}

private captureSearch(event: AnalyticsEvent): void {
// cancel any pending trackSearch call
if (this.cancelProc) {
clearTimeout(this.cancelProc);
}
trackLinkClick({ targetUrl: to, elementContent: event.subject });
}

private trackSearch(event: AnalyticsEvent): void {
// trim whitespace, split into non-empty terms
trackSiteSearch({
terms: event.subject
.trim()
.split(' ')
.filter(t => t),
});
}

// track event once the debounceTime has elapsed
this.cancelProc = setTimeout(() => {
this.trackSearch(event);
this.cancelProc = null;
}, this.debounceTime);
private captureSearch(event: AnalyticsEvent): void {
// cancel any pending trackSearch call
if (this.cancelProc) {
clearTimeout(this.cancelProc);
}

}
// track event once the debounceTime has elapsed
this.cancelProc = setTimeout(() => {
this.trackSearch(event);
this.cancelProc = null;
}, this.debounceTime);
}

private trackCreate(event: AnalyticsEvent): void {
trackSelfDescribingEvent({
event: {
schema: 'iglu:ca.bc.gov.devx/action/jsonschema/1-0-0',
data: {
action: 'wizard-complete',
text: event.subject,
ministry: '',
time_saved: event.value ?? 0.0,
},
},
});
}
}

0 comments on commit eba8493

Please sign in to comment.