From acea593bc551aac14aebd982333be592ee4b298c Mon Sep 17 00:00:00 2001 From: Bero Date: Mon, 4 Nov 2024 16:15:08 +0100 Subject: [PATCH 1/7] Track install and error events --- .../website/src/components/layout/index.tsx | 73 +++++++++------- .../src/lib/state/redux/boot-site-client.ts | 23 +++-- .../playground/website/src/lib/tracking.ts | 87 +++++++++++++++++-- 3 files changed, 129 insertions(+), 54 deletions(-) diff --git a/packages/playground/website/src/components/layout/index.tsx b/packages/playground/website/src/components/layout/index.tsx index ee6906d1a5..b4ebf3bec4 100644 --- a/packages/playground/website/src/components/layout/index.tsx +++ b/packages/playground/website/src/components/layout/index.tsx @@ -33,6 +33,7 @@ import { setSiteManagerOpen, } from '../../lib/state/redux/slice-ui'; import { ImportFormModal } from '../import-form/modal'; +import { logErrorEvent } from '../../lib/tracking'; acquireOAuthTokenIfNeeded(); @@ -42,8 +43,8 @@ export const modalSlugs = { START_ERROR: 'start-error', IMPORT_FORM: 'import-form', GITHUB_IMPORT: 'github-import', - GITHUB_EXPORT: 'github-export' -} + GITHUB_EXPORT: 'github-export', +}; const displayMode = getDisplayModeFromQuery(); function getDisplayModeFromQuery(): DisplayMode { @@ -159,6 +160,8 @@ function Modals(blueprint: Blueprint) { useEffect(() => { addCrashListener(logger, (e) => { const error = e as CustomEvent; + logErrorEvent(error.detail?.source); + if (error.detail?.source === 'php-wasm') { dispatch(setActiveModal(modalSlugs.ERROR_REPORT)); } @@ -179,39 +182,43 @@ function Modals(blueprint: Blueprint) { } else if (currentModal === modalSlugs.IMPORT_FORM) { return ; } else if (currentModal === modalSlugs.GITHUB_IMPORT) { - return { - setGithubExportValues({ - repoUrl: url, - prNumber: pr?.toString(), - toPathInRepo: path, - prAction: pr ? 'update' : 'create', + return ( + ; + urlInformation: { owner, repo, type, pr }, + }) => { + setGithubExportValues({ + repoUrl: url, + prNumber: pr?.toString(), + toPathInRepo: path, + prAction: pr ? 'update' : 'create', + contentType, + plugin: pluginOrThemeName, + theme: pluginOrThemeName, + }); + setGithubExportFiles(files); + }} + /> + ); } else if (currentModal === modalSlugs.GITHUB_EXPORT) { - return { - setGithubExportValues(formValues); - setGithubExportFiles(undefined); - }} - />; + return ( + { + setGithubExportValues(formValues); + setGithubExportFiles(undefined); + }} + /> + ); } if (query.get('gh-ensure-auth') === 'yes') { diff --git a/packages/playground/website/src/lib/state/redux/boot-site-client.ts b/packages/playground/website/src/lib/state/redux/boot-site-client.ts index 6ae9b4664e..cdafb5ea87 100644 --- a/packages/playground/website/src/lib/state/redux/boot-site-client.ts +++ b/packages/playground/website/src/lib/state/redux/boot-site-client.ts @@ -10,8 +10,12 @@ import { removeClientInfo, updateClientInfo, } from './slice-clients'; -import { logTrackingEvent } from '../../tracking'; -import { Blueprint, StepDefinition } from '@wp-playground/blueprints'; +import { + logBlueprintStepEvent, + logErrorEvent, + logTrackingEvent, +} from '../../tracking'; +import { Blueprint } from '@wp-playground/blueprints'; import { logger } from '@php-wasm/logger'; import { setupPostMessageRelay } from '@php-wasm/web'; import { startPlaygroundWeb } from '@wp-playground/client'; @@ -100,17 +104,6 @@ export function bootSiteClient( blueprint = site.metadata.runtimeConfiguration; } else { blueprint = site.metadata.originalBlueprint; - // Log the names of provided Blueprint's steps. - // Only the names (e.g. "runPhp" or "login") are logged. Step options like - // code, password, URLs are never sent anywhere. - const steps = (blueprint?.steps || []) - ?.filter( - (step: any) => !!(typeof step === 'object' && step?.step) - ) - .map((step) => (step as StepDefinition).step); - for (const step of steps) { - logTrackingEvent('step', { step }); - } } let playground: PlaygroundClient; @@ -125,6 +118,9 @@ export function bootSiteClient( onClientConnected: (playground) => { (window as any)['playground'] = playground; }, + onBlueprintStepCompleted: (result, step) => { + logBlueprintStepEvent(step); + }, mounts: mountDescriptor ? [ { @@ -177,6 +173,7 @@ export function bootSiteClient( } } catch (e) { logger.error(e); + logErrorEvent('boot'); dispatch(setActiveSiteError('site-boot-failed')); dispatch(setActiveModal(modalSlugs.ERROR_REPORT)); return; diff --git a/packages/playground/website/src/lib/tracking.ts b/packages/playground/website/src/lib/tracking.ts index 1dbc0b85a0..1cf36f84f8 100644 --- a/packages/playground/website/src/lib/tracking.ts +++ b/packages/playground/website/src/lib/tracking.ts @@ -1,23 +1,94 @@ +import { StepDefinition } from '@wp-playground/blueprints'; + /** * Declare the global window.gtag function */ declare global { - interface Window { gtag: any; } + interface Window { + gtag: any; + } } /** * Google Analytics event names */ -type GAEvent = 'load' | 'step'; +type GAEvent = 'load' | 'step' | 'install' | 'error'; /** * Log a tracking event to Google Analytics * @param GAEvent The event name * @param Object Event data */ -export const logTrackingEvent = (event: GAEvent, data?: {[key: string]: string}) => { - if (typeof window === 'undefined' || !window.gtag) { - return; - } - window.gtag('event', event, data); -} +export const logTrackingEvent = ( + event: GAEvent, + data?: { [key: string]: string } +) => { + if (typeof window === 'undefined' || !window.gtag) { + return; + } + window.gtag('event', event, data); +}; + +/** + * Log Plugin install events + * @param step The Blueprint step + */ +export const logPluginInstallEvent = (step: StepDefinition) => { + const pluginData = (step as any).pluginData; + if (pluginData.slug) { + logTrackingEvent('install', { + plugin: pluginData.slug, + }); + } else if (pluginData.url) { + logTrackingEvent('install', { + plugin: pluginData.url, + }); + } +}; + +/** + * Log Theme install events + * @param step The Blueprint step + */ +export const logThemeInstallEvent = (step: StepDefinition) => { + const themeData = (step as any).themeData; + if (themeData.slug) { + logTrackingEvent('install', { + theme: themeData.slug, + }); + } else if (themeData.url) { + logTrackingEvent('install', { + theme: themeData.url, + }); + } +}; + +/** + * Log Blueprint step events + * @param step The Blueprint step + */ +export const logBlueprintStepEvent = (step: StepDefinition) => { + /** + * Log the names of provided Blueprint's steps. + * Only the names (e.g. "runPhp" or "login") are logged. Step options like + * code, password, URLs are never sent anywhere. + */ + logTrackingEvent('step', { step: step.step }); + + if (step.step === 'installPlugin') { + logPluginInstallEvent(step); + } else if (step.step === 'installTheme') { + logThemeInstallEvent(step); + } +}; + +/** + * Log error events + * + * @param error The error + */ +export const logErrorEvent = (source: string) => { + logTrackingEvent('error', { + source, + }); +}; From 4592b34ceccab81463bbed8a258025280ebd478d Mon Sep 17 00:00:00 2001 From: Bero Date: Tue, 5 Nov 2024 06:47:36 +0100 Subject: [PATCH 2/7] Don't track URLs and try sending event --- .../playground/website/src/lib/tracking.ts | 57 ++++++------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/packages/playground/website/src/lib/tracking.ts b/packages/playground/website/src/lib/tracking.ts index 1cf36f84f8..208b56eee3 100644 --- a/packages/playground/website/src/lib/tracking.ts +++ b/packages/playground/website/src/lib/tracking.ts @@ -1,4 +1,5 @@ import { StepDefinition } from '@wp-playground/blueprints'; +import { logger } from '@php-wasm/logger'; /** * Declare the global window.gtag function @@ -23,43 +24,13 @@ export const logTrackingEvent = ( event: GAEvent, data?: { [key: string]: string } ) => { - if (typeof window === 'undefined' || !window.gtag) { - return; - } - window.gtag('event', event, data); -}; - -/** - * Log Plugin install events - * @param step The Blueprint step - */ -export const logPluginInstallEvent = (step: StepDefinition) => { - const pluginData = (step as any).pluginData; - if (pluginData.slug) { - logTrackingEvent('install', { - plugin: pluginData.slug, - }); - } else if (pluginData.url) { - logTrackingEvent('install', { - plugin: pluginData.url, - }); - } -}; - -/** - * Log Theme install events - * @param step The Blueprint step - */ -export const logThemeInstallEvent = (step: StepDefinition) => { - const themeData = (step as any).themeData; - if (themeData.slug) { - logTrackingEvent('install', { - theme: themeData.slug, - }); - } else if (themeData.url) { - logTrackingEvent('install', { - theme: themeData.url, - }); + try { + if (typeof window === 'undefined' || !window.gtag) { + return; + } + window.gtag('event', event, data); + } catch (error) { + logger.warn('Failed to log tracking event', event, data, error); } }; @@ -75,10 +46,14 @@ export const logBlueprintStepEvent = (step: StepDefinition) => { */ logTrackingEvent('step', { step: step.step }); - if (step.step === 'installPlugin') { - logPluginInstallEvent(step); - } else if (step.step === 'installTheme') { - logThemeInstallEvent(step); + if (step.step === 'installPlugin' && (step as any).pluginData.slug) { + logTrackingEvent('install', { + plugin: (step as any).pluginData.slug, + }); + } else if (step.step === 'installTheme' && (step as any).themeData.slug) { + logTrackingEvent('install', { + theme: (step as any).themeData.slug, + }); } }; From 1fa774dd434c82fa1ff1f9d33d9b4e9ddf6a1939 Mon Sep 17 00:00:00 2001 From: Bero Date: Wed, 6 Nov 2024 12:11:34 +0100 Subject: [PATCH 3/7] Rename boot to bootSiteClient --- .../playground/website/src/lib/state/redux/boot-site-client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/playground/website/src/lib/state/redux/boot-site-client.ts b/packages/playground/website/src/lib/state/redux/boot-site-client.ts index cdafb5ea87..f5bc9647f6 100644 --- a/packages/playground/website/src/lib/state/redux/boot-site-client.ts +++ b/packages/playground/website/src/lib/state/redux/boot-site-client.ts @@ -173,7 +173,7 @@ export function bootSiteClient( } } catch (e) { logger.error(e); - logErrorEvent('boot'); + logErrorEvent('bootSiteClient'); dispatch(setActiveSiteError('site-boot-failed')); dispatch(setActiveModal(modalSlugs.ERROR_REPORT)); return; From ad63c4940e80eab01ad2f3d26fb00dd3580fbb8b Mon Sep 17 00:00:00 2001 From: Bero Date: Tue, 12 Nov 2024 08:40:08 +0100 Subject: [PATCH 4/7] Don't send error if source is unknown --- packages/playground/website/src/components/layout/index.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/playground/website/src/components/layout/index.tsx b/packages/playground/website/src/components/layout/index.tsx index b4ebf3bec4..3bcc2de6a5 100644 --- a/packages/playground/website/src/components/layout/index.tsx +++ b/packages/playground/website/src/components/layout/index.tsx @@ -160,7 +160,9 @@ function Modals(blueprint: Blueprint) { useEffect(() => { addCrashListener(logger, (e) => { const error = e as CustomEvent; - logErrorEvent(error.detail?.source); + if (error.detail?.source) { + logErrorEvent(error.detail.source); + } if (error.detail?.source === 'php-wasm') { dispatch(setActiveModal(modalSlugs.ERROR_REPORT)); From a10dfc96d07961fafc1ebfc48b65c790a1d720b4 Mon Sep 17 00:00:00 2001 From: Bero Date: Thu, 14 Nov 2024 09:56:02 +0100 Subject: [PATCH 5/7] Track errors with unknown source --- packages/playground/website/src/components/layout/index.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/playground/website/src/components/layout/index.tsx b/packages/playground/website/src/components/layout/index.tsx index 3bcc2de6a5..eaebb9c033 100644 --- a/packages/playground/website/src/components/layout/index.tsx +++ b/packages/playground/website/src/components/layout/index.tsx @@ -160,9 +160,7 @@ function Modals(blueprint: Blueprint) { useEffect(() => { addCrashListener(logger, (e) => { const error = e as CustomEvent; - if (error.detail?.source) { - logErrorEvent(error.detail.source); - } + logErrorEvent(error.detail?.source ?? 'unknown'); if (error.detail?.source === 'php-wasm') { dispatch(setActiveModal(modalSlugs.ERROR_REPORT)); From beeb585ec54e5ebd9c99a4cb752fe264967fb939 Mon Sep 17 00:00:00 2001 From: Bero Date: Thu, 14 Nov 2024 09:58:47 +0100 Subject: [PATCH 6/7] Track theme and plugin installs as separate events --- packages/playground/website/src/lib/tracking.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/playground/website/src/lib/tracking.ts b/packages/playground/website/src/lib/tracking.ts index 208b56eee3..8bdf4cf864 100644 --- a/packages/playground/website/src/lib/tracking.ts +++ b/packages/playground/website/src/lib/tracking.ts @@ -13,7 +13,7 @@ declare global { /** * Google Analytics event names */ -type GAEvent = 'load' | 'step' | 'install' | 'error'; +type GAEvent = 'load' | 'step' | 'installPlugin' | 'installTheme' | 'error'; /** * Log a tracking event to Google Analytics @@ -47,12 +47,12 @@ export const logBlueprintStepEvent = (step: StepDefinition) => { logTrackingEvent('step', { step: step.step }); if (step.step === 'installPlugin' && (step as any).pluginData.slug) { - logTrackingEvent('install', { - plugin: (step as any).pluginData.slug, + logTrackingEvent('installPlugin', { + slug: (step as any).pluginData.slug, }); } else if (step.step === 'installTheme' && (step as any).themeData.slug) { - logTrackingEvent('install', { - theme: (step as any).themeData.slug, + logTrackingEvent('installTheme', { + slug: (step as any).themeData.slug, }); } }; From 4bc154e891021d817e4f8d11187768f2b8975a1e Mon Sep 17 00:00:00 2001 From: Bero Date: Thu, 14 Nov 2024 10:16:54 +0100 Subject: [PATCH 7/7] Remove unnecessary nullish operator --- packages/playground/website/src/components/layout/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/playground/website/src/components/layout/index.tsx b/packages/playground/website/src/components/layout/index.tsx index eaebb9c033..2483e4ceba 100644 --- a/packages/playground/website/src/components/layout/index.tsx +++ b/packages/playground/website/src/components/layout/index.tsx @@ -160,7 +160,7 @@ function Modals(blueprint: Blueprint) { useEffect(() => { addCrashListener(logger, (e) => { const error = e as CustomEvent; - logErrorEvent(error.detail?.source ?? 'unknown'); + logErrorEvent(error.detail.source ?? 'unknown'); if (error.detail?.source === 'php-wasm') { dispatch(setActiveModal(modalSlugs.ERROR_REPORT));