Skip to content

Commit acea593

Browse files
committed
Track install and error events
1 parent 8f414d1 commit acea593

File tree

3 files changed

+129
-54
lines changed

3 files changed

+129
-54
lines changed

packages/playground/website/src/components/layout/index.tsx

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
setSiteManagerOpen,
3434
} from '../../lib/state/redux/slice-ui';
3535
import { ImportFormModal } from '../import-form/modal';
36+
import { logErrorEvent } from '../../lib/tracking';
3637

3738
acquireOAuthTokenIfNeeded();
3839

@@ -42,8 +43,8 @@ export const modalSlugs = {
4243
START_ERROR: 'start-error',
4344
IMPORT_FORM: 'import-form',
4445
GITHUB_IMPORT: 'github-import',
45-
GITHUB_EXPORT: 'github-export'
46-
}
46+
GITHUB_EXPORT: 'github-export',
47+
};
4748

4849
const displayMode = getDisplayModeFromQuery();
4950
function getDisplayModeFromQuery(): DisplayMode {
@@ -159,6 +160,8 @@ function Modals(blueprint: Blueprint) {
159160
useEffect(() => {
160161
addCrashListener(logger, (e) => {
161162
const error = e as CustomEvent;
163+
logErrorEvent(error.detail?.source);
164+
162165
if (error.detail?.source === 'php-wasm') {
163166
dispatch(setActiveModal(modalSlugs.ERROR_REPORT));
164167
}
@@ -179,39 +182,43 @@ function Modals(blueprint: Blueprint) {
179182
} else if (currentModal === modalSlugs.IMPORT_FORM) {
180183
return <ImportFormModal />;
181184
} else if (currentModal === modalSlugs.GITHUB_IMPORT) {
182-
return <GithubImportModal
183-
onImported={({
184-
url,
185-
path,
186-
files,
187-
pluginOrThemeName,
188-
contentType,
189-
urlInformation: { owner, repo, type, pr },
190-
}) => {
191-
setGithubExportValues({
192-
repoUrl: url,
193-
prNumber: pr?.toString(),
194-
toPathInRepo: path,
195-
prAction: pr ? 'update' : 'create',
185+
return (
186+
<GithubImportModal
187+
onImported={({
188+
url,
189+
path,
190+
files,
191+
pluginOrThemeName,
196192
contentType,
197-
plugin: pluginOrThemeName,
198-
theme: pluginOrThemeName,
199-
});
200-
setGithubExportFiles(files);
201-
}}
202-
/>;
193+
urlInformation: { owner, repo, type, pr },
194+
}) => {
195+
setGithubExportValues({
196+
repoUrl: url,
197+
prNumber: pr?.toString(),
198+
toPathInRepo: path,
199+
prAction: pr ? 'update' : 'create',
200+
contentType,
201+
plugin: pluginOrThemeName,
202+
theme: pluginOrThemeName,
203+
});
204+
setGithubExportFiles(files);
205+
}}
206+
/>
207+
);
203208
} else if (currentModal === modalSlugs.GITHUB_EXPORT) {
204-
return <GithubExportModal
205-
allowZipExport={
206-
(query.get('ghexport-allow-include-zip') ?? 'yes') === 'yes'
207-
}
208-
initialValues={githubExportValues}
209-
initialFilesBeforeChanges={githubExportFiles}
210-
onExported={(prUrl, formValues) => {
211-
setGithubExportValues(formValues);
212-
setGithubExportFiles(undefined);
213-
}}
214-
/>;
209+
return (
210+
<GithubExportModal
211+
allowZipExport={
212+
(query.get('ghexport-allow-include-zip') ?? 'yes') === 'yes'
213+
}
214+
initialValues={githubExportValues}
215+
initialFilesBeforeChanges={githubExportFiles}
216+
onExported={(prUrl, formValues) => {
217+
setGithubExportValues(formValues);
218+
setGithubExportFiles(undefined);
219+
}}
220+
/>
221+
);
215222
}
216223

217224
if (query.get('gh-ensure-auth') === 'yes') {

packages/playground/website/src/lib/state/redux/boot-site-client.ts

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ import {
1010
removeClientInfo,
1111
updateClientInfo,
1212
} from './slice-clients';
13-
import { logTrackingEvent } from '../../tracking';
14-
import { Blueprint, StepDefinition } from '@wp-playground/blueprints';
13+
import {
14+
logBlueprintStepEvent,
15+
logErrorEvent,
16+
logTrackingEvent,
17+
} from '../../tracking';
18+
import { Blueprint } from '@wp-playground/blueprints';
1519
import { logger } from '@php-wasm/logger';
1620
import { setupPostMessageRelay } from '@php-wasm/web';
1721
import { startPlaygroundWeb } from '@wp-playground/client';
@@ -100,17 +104,6 @@ export function bootSiteClient(
100104
blueprint = site.metadata.runtimeConfiguration;
101105
} else {
102106
blueprint = site.metadata.originalBlueprint;
103-
// Log the names of provided Blueprint's steps.
104-
// Only the names (e.g. "runPhp" or "login") are logged. Step options like
105-
// code, password, URLs are never sent anywhere.
106-
const steps = (blueprint?.steps || [])
107-
?.filter(
108-
(step: any) => !!(typeof step === 'object' && step?.step)
109-
)
110-
.map((step) => (step as StepDefinition).step);
111-
for (const step of steps) {
112-
logTrackingEvent('step', { step });
113-
}
114107
}
115108

116109
let playground: PlaygroundClient;
@@ -125,6 +118,9 @@ export function bootSiteClient(
125118
onClientConnected: (playground) => {
126119
(window as any)['playground'] = playground;
127120
},
121+
onBlueprintStepCompleted: (result, step) => {
122+
logBlueprintStepEvent(step);
123+
},
128124
mounts: mountDescriptor
129125
? [
130126
{
@@ -177,6 +173,7 @@ export function bootSiteClient(
177173
}
178174
} catch (e) {
179175
logger.error(e);
176+
logErrorEvent('boot');
180177
dispatch(setActiveSiteError('site-boot-failed'));
181178
dispatch(setActiveModal(modalSlugs.ERROR_REPORT));
182179
return;
Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,94 @@
1+
import { StepDefinition } from '@wp-playground/blueprints';
2+
13
/**
24
* Declare the global window.gtag function
35
*/
46
declare global {
5-
interface Window { gtag: any; }
7+
interface Window {
8+
gtag: any;
9+
}
610
}
711

812
/**
913
* Google Analytics event names
1014
*/
11-
type GAEvent = 'load' | 'step';
15+
type GAEvent = 'load' | 'step' | 'install' | 'error';
1216

1317
/**
1418
* Log a tracking event to Google Analytics
1519
* @param GAEvent The event name
1620
* @param Object Event data
1721
*/
18-
export const logTrackingEvent = (event: GAEvent, data?: {[key: string]: string}) => {
19-
if (typeof window === 'undefined' || !window.gtag) {
20-
return;
21-
}
22-
window.gtag('event', event, data);
23-
}
22+
export const logTrackingEvent = (
23+
event: GAEvent,
24+
data?: { [key: string]: string }
25+
) => {
26+
if (typeof window === 'undefined' || !window.gtag) {
27+
return;
28+
}
29+
window.gtag('event', event, data);
30+
};
31+
32+
/**
33+
* Log Plugin install events
34+
* @param step The Blueprint step
35+
*/
36+
export const logPluginInstallEvent = (step: StepDefinition) => {
37+
const pluginData = (step as any).pluginData;
38+
if (pluginData.slug) {
39+
logTrackingEvent('install', {
40+
plugin: pluginData.slug,
41+
});
42+
} else if (pluginData.url) {
43+
logTrackingEvent('install', {
44+
plugin: pluginData.url,
45+
});
46+
}
47+
};
48+
49+
/**
50+
* Log Theme install events
51+
* @param step The Blueprint step
52+
*/
53+
export const logThemeInstallEvent = (step: StepDefinition) => {
54+
const themeData = (step as any).themeData;
55+
if (themeData.slug) {
56+
logTrackingEvent('install', {
57+
theme: themeData.slug,
58+
});
59+
} else if (themeData.url) {
60+
logTrackingEvent('install', {
61+
theme: themeData.url,
62+
});
63+
}
64+
};
65+
66+
/**
67+
* Log Blueprint step events
68+
* @param step The Blueprint step
69+
*/
70+
export const logBlueprintStepEvent = (step: StepDefinition) => {
71+
/**
72+
* Log the names of provided Blueprint's steps.
73+
* Only the names (e.g. "runPhp" or "login") are logged. Step options like
74+
* code, password, URLs are never sent anywhere.
75+
*/
76+
logTrackingEvent('step', { step: step.step });
77+
78+
if (step.step === 'installPlugin') {
79+
logPluginInstallEvent(step);
80+
} else if (step.step === 'installTheme') {
81+
logThemeInstallEvent(step);
82+
}
83+
};
84+
85+
/**
86+
* Log error events
87+
*
88+
* @param error The error
89+
*/
90+
export const logErrorEvent = (source: string) => {
91+
logTrackingEvent('error', {
92+
source,
93+
});
94+
};

0 commit comments

Comments
 (0)