Skip to content

Commit 9a802bb

Browse files
pilhuhnedonehoo
andauthored
feat(Analytics): Major overhaul of provider init and Umami Provider
Allow to tune down the logging on console. Change initialisation of providers and do a major overhaul of the Umami Provider. Co-authored-by: Erin Donehoo <105813956+edonehoo@users.noreply.github.com>
1 parent ecee998 commit 9a802bb

11 files changed

Lines changed: 227 additions & 104 deletions

File tree

.eslintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
"dot-notation": "error",
6363
"eqeqeq": ["error", "smart"],
6464
"guard-for-in": "error",
65-
"indent": ["error", 2],
65+
"indent": ["error", 2, {"SwitchCase": 1}],
6666
"max-classes-per-file": ["error", 1],
6767
"no-nested-ternary": "error",
6868
"no-bitwise": "error",

packages/module/patternfly-docs/content/extensions/chatbot/examples/Analytics/Analytics.md

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ Note that user code only interacts with:
3636

3737
### Setup
3838

39-
1. Before you can use the `trackingAPI`, you must first supply the API keys of the respective providers.
39+
1. Before you can use the `trackingAPI`, you must first supply the API keys of the respective providers. To enable a provider, it must be added to the `activeProviders` property:
4040

4141
```nolive
4242
const initProps: InitProps = {
43+
verbose: false,
44+
activeProviders: ['Segment', 'Umami', 'Posthog', 'Console' ],
4345
segmentKey: 'TODO-key', // TODO add your key here
4446
// segmentCdn: 'https://my.org/cdn', // Set up segment cdn (optional)
4547
// segmentIntegrations: { // Provide Segment integrations (optional)
@@ -50,13 +52,15 @@ const initProps: InitProps = {
5052
},
5153
5254
posthogKey: 'TODO-key',
53-
umamiKey: 'TODO-key',
55+
umamiKey: 'TODO-umami-key',
5456
umamiHostUrl: 'http://localhost:3000', // TODO where is your JS provider?
57+
'umami-data-domains': 'TODO umami data domain',
5558
something: 'test',
56-
console: 'true' // Console provider
5759
};
5860
```
5961

62+
- **Note:** To enable output debugging via the web-browser console, set the `verbose` key to `true`. By default, this is set to `false`.
63+
6064
1. Once this is done, you can create an instance of the `trackingAPI` and start sending events.
6165

6266
```nolive
@@ -76,35 +80,35 @@ trackingAPI.trackSingleItem("MyEvent", { response: 'Good response' })
7680

7781
#### Tracking providers
7882

79-
Only providers with a matching key in the `InitProps` will be started and used.
83+
Only providers with a matching entry in the `InitProps.activeProviders` array will be started and used.
84+
85+
Possible values are:
86+
* Umami
87+
* Posthog
88+
* Segment
89+
* Console
8090

81-
```nolive
82-
const initProps: InitProps = {
83-
segmentKey: 'TODO-key', // TODO add your key here
84-
posthogKey: 'TODO-key',
85-
umamiKey: 'TODO-key',
86-
umamiHostUrl: 'http://localhost:3000', // TODO where is your JS provider?
87-
console: true
88-
```
8991

9092
##### Modifying providers
9193

9294
If you know upfront that you only want to use 1 of the supported providers, you can modify `getTrackingProviders()` and remove all other providers in the providers array.
9395

94-
When using the providers you need to add additional dependencies to your package.json file:
96+
When using the providers, you might need to add additional dependencies to your package.json file:
9597

9698
```nolive
9799
"dependencies": {
98100
"@segment/analytics-next": "^1.76.0",
99101
"posthog-js": "^1.194.4"
100102
```
101103

104+
Depending on your local setup, this might not be necessary. For example, if you pull the ChatBot codebase as a dependency into your project, you don't need to add it as an additional dependency in your package.json.
105+
102106
##### Adding providers
103107

104108
To add another analytics provider, you need to implement 2 interfaces, `TrackingSpi` and `trackingApi`.
105109

106110
1. It is easiest to start by copying the `ConsoleTrackingProvider`
107-
1. The first thing you should do is to provide a correct value in `getKey()`
111+
1. Add an entry for your new provider to the `Providers` enum in `tracking_spi.ts`
108112
1. Once you are happy enough with the implementation, add it to the array of providers in `getTrackingProviders()`
109113

110114
### Page flow tracking

packages/module/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,18 @@ export default MessageLoading;
9898
const date = new Date();
9999

100100
const initProps: InitProps = {
101+
verbose: false,
101102
segmentKey: 'TODO-key', // TODO add your key here
102103
posthogKey: 'TODO-key',
103104
umamiKey: 'TODO-key',
104-
umamiHostUrl: 'http://localhost:3000', // TODO where is your JS provider?
105+
umamiHostUrl: 'http://localhost:3000', // TODO where is your Umami installation?
105106
console: true,
106107
something: 'test'
107108
};
108109

109110
const tracking = getTrackingProviders(initProps);
110-
tracking.identify('user-123'); // TODO get real user id
111-
tracking.trackPageView(window.document.documentURI);
111+
tracking.identify('user-123', { superUser: true }); // TODO get real user id + properties
112+
tracking.trackPageView(window.location.href);
112113

113114
const actionEventName = 'MessageAction';
114115
const initialMessages: MessageProps[] = [
Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
1-
import { TrackingSpi } from './tracking_spi';
1+
import { InitProps, TrackingSpi } from './tracking_spi';
22
import { TrackingApi, TrackingEventProperties } from './tracking_api';
33

44
export class ConsoleTrackingProvider implements TrackingSpi, TrackingApi {
5+
private verbose = false;
56
trackPageView(url: string | undefined) {
6-
// eslint-disable-next-line no-console
7-
console.log('ConsoleProvider pageView', url);
7+
if (this.verbose) {
8+
// eslint-disable-next-line no-console
9+
console.log('ConsoleProvider pageView ', url);
10+
}
811
}
9-
// eslint-disable-next-line @typescript-eslint/no-empty-function
10-
registerProvider(): void {}
1112

12-
initialize(): void {
13-
// eslint-disable-next-line no-console
14-
console.log('ConsoleProvider initialize');
13+
initialize(props: InitProps): void {
14+
this.verbose = props.verbose;
15+
if (this.verbose) {
16+
// eslint-disable-next-line no-console
17+
console.log('ConsoleProvider initialize');
18+
}
1519
}
1620

17-
identify(userID: string): void {
18-
// eslint-disable-next-line no-console
19-
console.log('ConsoleProvider identify', userID);
21+
identify(userID: string, userProperties: TrackingEventProperties = {}): void {
22+
if (this.verbose) {
23+
// eslint-disable-next-line no-console
24+
console.log('ConsoleProvider identify ', userID, userProperties);
25+
}
2026
}
2127

2228
trackSingleItem(item: string, properties?: TrackingEventProperties): void {
23-
// eslint-disable-next-line no-console
24-
console.log('ConsoleProvider: ' + item, properties);
25-
}
26-
27-
getKey(): string {
28-
return 'console';
29+
if (this.verbose) {
30+
// eslint-disable-next-line no-console
31+
console.log('ConsoleProvider: ' + item, properties);
32+
}
2933
}
3034
}

packages/module/src/tracking/posthog_tracking_provider.ts

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import { TrackingApi, TrackingEventProperties } from './tracking_api';
44
import { InitProps, TrackingSpi } from './tracking_spi';
55

66
export class PosthogTrackingProvider implements TrackingSpi, TrackingApi {
7-
getKey(): string {
8-
return 'posthogKey';
9-
}
7+
private verbose = false;
108

119
initialize(props: InitProps): void {
12-
// eslint-disable-next-line no-console
13-
console.log('PosthogProvider initialize');
10+
this.verbose = props.verbose;
11+
if (this.verbose) {
12+
// eslint-disable-next-line no-console
13+
console.log('PosthogProvider initialize');
14+
}
1415
const posthogKey = props.posthogKey as string;
1516

1617
posthog.init(posthogKey, {
@@ -21,22 +22,28 @@ export class PosthogTrackingProvider implements TrackingSpi, TrackingApi {
2122
});
2223
}
2324

24-
identify(userID: string): void {
25-
// eslint-disable-next-line no-console
26-
console.log('PosthogProvider userID: ' + userID);
27-
posthog.identify(userID);
25+
identify(userID: string, userProperties: TrackingEventProperties = {}): void {
26+
if (this.verbose) {
27+
// eslint-disable-next-line no-console
28+
console.log('PosthogProvider userID: ' + userID);
29+
}
30+
posthog.identify(userID, userProperties);
2831
}
2932

3033
trackPageView(url: string | undefined): void {
31-
// eslint-disable-next-line no-console
32-
console.log('PostHogProvider url', url);
34+
if (this.verbose) {
35+
// eslint-disable-next-line no-console
36+
console.log('PostHogProvider url ', url);
37+
}
3338
// TODO posthog seems to record that automatically.
3439
// How to not clash with this here? Just leave as no-op?
3540
}
3641

3742
trackSingleItem(item: string, properties?: TrackingEventProperties): void {
38-
// eslint-disable-next-line no-console
39-
console.log('PosthogProvider: trackSingleItem' + item, properties);
43+
if (this.verbose) {
44+
// eslint-disable-next-line no-console
45+
console.log('PosthogProvider: trackSingleItem ' + item, properties);
46+
}
4047
posthog.capture(item, { properties });
4148
}
4249
}

packages/module/src/tracking/segment_tracking_provider.ts

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import { InitProps, TrackingSpi } from './tracking_spi';
55

66
export class SegmentTrackingProvider implements TrackingSpi, TrackingApi {
77
private analytics: AnalyticsBrowser | undefined;
8-
getKey(): string {
9-
return 'segmentKey';
10-
}
8+
private verbose = false;
119

1210
initialize(props: InitProps): void {
13-
// eslint-disable-next-line no-console
14-
console.log('SegmentProvider initialize');
11+
this.verbose = props.verbose;
12+
if (this.verbose) {
13+
// eslint-disable-next-line no-console
14+
console.log('SegmentProvider initialize');
15+
}
1516
const segmentKey = props.segmentKey as string;
1617

1718
// We need to create an object here, as ts lint is unhappy otherwise
@@ -32,17 +33,21 @@ export class SegmentTrackingProvider implements TrackingSpi, TrackingApi {
3233
);
3334
}
3435

35-
identify(userID: string): void {
36-
// eslint-disable-next-line no-console
37-
console.log('SegmentProvider userID: ' + userID);
36+
identify(userID: string, userProperties: TrackingEventProperties = {}): void {
37+
if (this.verbose) {
38+
// eslint-disable-next-line no-console
39+
console.log('SegmentProvider userID: ' + userID);
40+
}
3841
if (this.analytics) {
39-
this.analytics.identify(userID);
42+
this.analytics.identify(userID, userProperties);
4043
}
4144
}
4245

4346
trackPageView(url: string | undefined): void {
44-
// eslint-disable-next-line no-console
45-
console.log('SegmentProvider url', url);
47+
if (this.verbose) {
48+
// eslint-disable-next-line no-console
49+
console.log('SegmentProvider url ', url);
50+
}
4651
if (this.analytics) {
4752
if (url) {
4853
this.analytics.page(url);
@@ -53,8 +58,10 @@ export class SegmentTrackingProvider implements TrackingSpi, TrackingApi {
5358
}
5459

5560
trackSingleItem(item: string, properties?: TrackingEventProperties): void {
56-
// eslint-disable-next-line no-console
57-
console.log('SegmentProvider: trackSingleItem' + item, properties);
61+
if (this.verbose) {
62+
// eslint-disable-next-line no-console
63+
console.log('SegmentProvider: trackSingleItem ' + item, properties);
64+
}
5865
if (this.analytics) {
5966
this.analytics.track(item, { properties });
6067
}

packages/module/src/tracking/trackingProviderProxy.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ class TrackingProviderProxy implements TrackingApi {
66
this.providers = providers;
77
}
88

9-
identify(userID: string): void {
9+
identify(userID: string, userProperties: TrackingEventProperties = {}): void {
1010
for (const provider of this.providers) {
11-
provider.identify(userID);
11+
provider.identify(userID, userProperties);
1212
}
1313
}
1414

packages/module/src/tracking/tracking_api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ export interface TrackingEventProperties {
33
}
44

55
export interface TrackingApi {
6-
identify: (userID: string) => void;
6+
identify: (userID: string, userProperties: TrackingEventProperties) => void;
77

88
trackPageView: (url: string | undefined) => void;
99

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { InitProps, TrackingSpi } from './tracking_spi';
1+
import { InitProps, Providers, TrackingSpi } from './tracking_spi';
22
import { TrackingApi } from './tracking_api';
33
import TrackingProviderProxy from './trackingProviderProxy';
44
import { ConsoleTrackingProvider } from './console_tracking_provider';
@@ -8,26 +8,59 @@ import { UmamiTrackingProvider } from './umami_tracking_provider';
88

99
export const getTrackingProviders = (initProps: InitProps): TrackingApi => {
1010
const providers: TrackingSpi[] = [];
11-
providers.push(new SegmentTrackingProvider());
12-
providers.push(new PosthogTrackingProvider());
13-
providers.push(new UmamiTrackingProvider());
1411

15-
// TODO dynamically find and register providers
12+
if (initProps.activeProviders) {
13+
let tmpProps: string[] = initProps.activeProviders;
14+
15+
// Theoretically we get an array of provider names, but it could also be a CSV string...
16+
if (!Array.isArray(initProps.activeProviders)) {
17+
const tmpString = initProps.activeProviders as string;
18+
if (tmpString && tmpString.indexOf(',') !== -1) {
19+
tmpProps = tmpString.split(',');
20+
} else {
21+
tmpProps = [tmpString];
22+
}
23+
}
24+
25+
tmpProps.forEach((provider) => {
26+
switch (Providers[provider]) {
27+
case Providers.Segment:
28+
providers.push(new SegmentTrackingProvider());
29+
break;
30+
case Providers.Umami:
31+
providers.push(new UmamiTrackingProvider());
32+
break;
33+
case Providers.Posthog:
34+
providers.push(new PosthogTrackingProvider());
35+
break;
36+
case Providers.Console:
37+
providers.push(new ConsoleTrackingProvider());
38+
break;
39+
case Providers.None: // Do nothing, just a placeholder
40+
break;
41+
default:
42+
if (providers.length > 1) {
43+
if (initProps.verbose) {
44+
// eslint-disable-next-line no-console
45+
console.error("Unknown provider '" + provider);
46+
}
47+
}
48+
break;
49+
}
50+
});
51+
}
1652

1753
// Initialize them
18-
const enabledProviders: TrackingSpi[] = [];
1954
for (const provider of providers) {
20-
const key = provider.getKey();
21-
if (Object.keys(initProps).indexOf(key) > -1) {
55+
try {
2256
provider.initialize(initProps);
23-
enabledProviders.push(provider);
57+
} catch (e) {
58+
// eslint-disable-next-line no-console
59+
console.error(e);
2460
}
2561
}
26-
// Add the console provider
27-
const consoleTrackingProvider = new ConsoleTrackingProvider();
28-
enabledProviders.push(consoleTrackingProvider); // TODO noop- provider?
2962

30-
return new TrackingProviderProxy(enabledProviders);
63+
return new TrackingProviderProxy(providers);
3164
};
3265

3366
export default getTrackingProviders;

0 commit comments

Comments
 (0)