From 7e4db83ead4a00002d0df73fb3470a7fa4cabd31 Mon Sep 17 00:00:00 2001 From: Sarah Edwards Date: Wed, 26 May 2021 14:11:55 -0700 Subject: [PATCH] Add event tracking for application selector (#19533) Co-authored-by: Kevin Heis --- javascripts/display-tool-specific-content.js | 16 +++++++ javascripts/events.js | 18 ++++++-- lib/hydro.js | 3 +- lib/schema-event.js | 46 +++++++++++++++++++- tests/rendering/events.js | 21 +++++++++ 5 files changed, 98 insertions(+), 6 deletions(-) diff --git a/javascripts/display-tool-specific-content.js b/javascripts/display-tool-specific-content.js index 60945c105c..bee88ec41d 100644 --- a/javascripts/display-tool-specific-content.js +++ b/javascripts/display-tool-specific-content.js @@ -1,3 +1,7 @@ +import Cookies from 'js-cookie' + +import { sendEvent } from './events' + const supportedTools = ['cli', 'desktop', 'webui'] const detectedTools = new Set() @@ -18,6 +22,16 @@ export default function displayToolSpecificContent () { event.preventDefault() showContentForTool(event.target.dataset.tool) findToolSpecificContent(event.target.dataset.tool) + + // Save this preference as a cookie. + Cookies.set('toolPreferred', event.target.dataset.tool, { sameSite: 'strict', secure: true }) + + // Send event data + sendEvent({ + type: 'preference', + preference_name: 'application', + preference_value: event.target.dataset.tool + }) }) }) } @@ -73,6 +87,8 @@ function detectTools (el) { } function getDefaultTool () { + const cookieValue = Cookies.get('toolPreferred') + if (cookieValue) return cookieValue const el = document.querySelector('[data-default-tool]') if (el) return el.dataset.defaultTool } diff --git a/javascripts/events.js b/javascripts/events.js index 55bec3f143..3311fd74fe 100644 --- a/javascripts/events.js +++ b/javascripts/events.js @@ -46,12 +46,14 @@ export function sendEvent ({ experiment_name, experiment_variation, experiment_success, - clipboard_operation + clipboard_operation, + preference_name, + preference_value }) { const body = { _csrf: getCsrf(), - type, // One of page, exit, link, search, navigate, survey, experiment + type, // One of page, exit, link, search, navigate, survey, experiment, preference context: { // Primitives @@ -77,7 +79,10 @@ export function sendEvent ({ // Location information timezone: new Date().getTimezoneOffset() / -60, - user_language: navigator.language + user_language: navigator.language, + + // Preference information + application_preference: Cookies.get('toolPreferred') }, // Page event @@ -112,7 +117,11 @@ export function sendEvent ({ experiment_success, // Clipboard event - clipboard_operation + clipboard_operation, + + // Preference event + preference_name, + preference_value } const blob = new Blob([JSON.stringify(body)], { type: 'application/json' }) navigator.sendBeacon('/events', blob) @@ -230,4 +239,5 @@ export default function initializeEvents () { // experiment event in ./experiment.js // search event in ./search.js // redirect event in middleware/record-redirect.js + // preference event in ./display-tool-specific-content.js } diff --git a/lib/hydro.js b/lib/hydro.js index 0c74378f6f..38af0b1a1d 100644 --- a/lib/hydro.js +++ b/lib/hydro.js @@ -13,7 +13,8 @@ const SCHEMAS = { experiment: 'docs.v0.ExperimentEvent', redirect: 'docs.v0.RedirectEvent', clipboard: 'docs.v0.ClipboardEvent', - print: 'docs.v0.PrintEvent' + print: 'docs.v0.PrintEvent', + preference: 'docs.v0.PreferenceEvent' } module.exports = class Hydro { diff --git a/lib/schema-event.js b/lib/schema-event.js index e832eecc97..f32ad34ec7 100644 --- a/lib/schema-event.js +++ b/lib/schema-event.js @@ -109,7 +109,22 @@ const context = { user_language: { type: 'string', description: 'The browser value of `navigator.language`.' + }, + + // Preference information + /* os_preference: { + type: 'string', + description: 'The os for examples selected by the user.' + }, */ + application_preference: { + type: 'string', + enum: ['webui', 'cli', 'desktop'], + description: 'The application selected by the user.' } + /* color_mode_preference: { + type: 'string', + description: 'The color mode selected by the user.' + } */ } } @@ -376,6 +391,34 @@ const printSchema = { } } +const preferenceSchema = { + type: 'object', + additionalProperties: false, + required: [ + 'type', + 'context', + 'preference_name', + 'preference_value' + ], + properties: { + context, + type: { + type: 'string', + pattern: '^preference$' + }, + preference_name: { + type: 'string', + enum: ['application'], // os, color_mode + description: 'The preference name, such as os, application, or color_mode' + }, + preference_value: { + type: 'string', + enum: ['webui', 'cli', 'desktop'], + description: 'The application selected by the user.' + } + } +} + module.exports = { oneOf: [ pageSchema, @@ -387,6 +430,7 @@ module.exports = { experimentSchema, redirectSchema, clipboardSchema, - printSchema + printSchema, + preferenceSchema ] } diff --git a/tests/rendering/events.js b/tests/rendering/events.js index df40ddfba3..2ec5d7eca3 100644 --- a/tests/rendering/events.js +++ b/tests/rendering/events.js @@ -474,4 +474,25 @@ describe('POST /events', () => { checkEvent(printExample, 200) ) }) + + describe('preference', () => { + const preferenceExample = { + ...baseExample, + type: 'preference', + preference_name: 'application', + preference_value: 'cli' + } + + it('should record an application event', () => + checkEvent(preferenceExample, 200) + ) + + it('preference_name is string', () => { + checkEvent({ ...preferenceExample, preference_name: null }, 400) + }) + + it('preference_value is string', () => { + checkEvent({ ...preferenceExample, preference_value: null }, 400) + }) + }) })