1
0
mirror of synced 2025-12-21 19:06:49 -05:00

Add page_event_id to all successive events (#17738)

* Add `page_event_id` to all successive events

* Update events.js

* Break out event inits into functions so they don't break each other

* Update events.js

* Update events.js

* Update events.js
This commit is contained in:
Kevin Heis
2021-02-09 07:40:27 -08:00
committed by GitHub
parent b3764cc4da
commit 207c536609
3 changed files with 44 additions and 32 deletions

View File

@@ -31,7 +31,6 @@ export function sendEvent ({
type, type,
version = '1.0.0', version = '1.0.0',
page_render_duration, page_render_duration,
exit_page_id,
exit_first_paint, exit_first_paint,
exit_dom_interactive, exit_dom_interactive,
exit_dom_complete, exit_dom_complete,
@@ -60,6 +59,7 @@ export function sendEvent ({
user: getUserEventsId(), user: getUserEventsId(),
version, version,
created: new Date().toISOString(), created: new Date().toISOString(),
page_event_id: pageEventId,
// Content information // Content information
path: location.pathname, path: location.pathname,
@@ -84,7 +84,6 @@ export function sendEvent ({
page_render_duration, page_render_duration,
// Exit event // Exit event
exit_page_id,
exit_first_paint, exit_first_paint,
exit_dom_interactive, exit_dom_interactive,
exit_dom_complete, exit_dom_complete,
@@ -149,7 +148,6 @@ function trackScroll () {
function sendExit () { function sendExit () {
if (sentExit) return if (sentExit) return
if (document.visibilityState !== 'hidden') return if (document.visibilityState !== 'hidden') return
if (!pageEventId) return
sentExit = true sentExit = true
const { const {
firstContentfulPaint, firstContentfulPaint,
@@ -158,7 +156,6 @@ function sendExit () {
} = getPerformance() } = getPerformance()
return sendEvent({ return sendEvent({
type: 'exit', type: 'exit',
exit_page_id: pageEventId,
exit_first_paint: firstContentfulPaint, exit_first_paint: firstContentfulPaint,
exit_dom_interactive: domInteractive, exit_dom_interactive: domInteractive,
exit_dom_complete: domComplete, exit_dom_complete: domComplete,
@@ -167,22 +164,24 @@ function sendExit () {
}) })
} }
export default function initializeEvents () { function initPageEvent () {
// Page event
const { render } = getPerformance() const { render } = getPerformance()
const pageEvent = sendEvent({ const pageEvent = sendEvent({
type: 'page', type: 'page',
page_render_duration: render page_render_duration: render
}) })
pageEventId = pageEvent?.context?.event_id
}
// Clipboard event function initClipboardEvent () {
;['copy', 'cut', 'paste'].forEach(verb => { ['copy', 'cut', 'paste'].forEach(verb => {
document.documentElement.addEventListener(verb, () => { document.documentElement.addEventListener(verb, () => {
sendEvent({ type: 'clipboard', clipboard_operation: verb }) sendEvent({ type: 'clipboard', clipboard_operation: verb })
}) })
}) })
}
// Link event function initLinkEvent () {
document.documentElement.addEventListener('click', evt => { document.documentElement.addEventListener('click', evt => {
const link = evt.target.closest('a[href^="http"]') const link = evt.target.closest('a[href^="http"]')
if (!link) return if (!link) return
@@ -191,10 +190,16 @@ export default function initializeEvents () {
link_url: link.href link_url: link.href
}) })
}) })
}
function initExitEvent () {
window.addEventListener('scroll', trackScroll)
document.addEventListener('visibilitychange', sendExit)
}
function initNavigateEvent () {
if (!document.querySelector('.sidebar-products')) return if (!document.querySelector('.sidebar-products')) return
// Navigate event
Array.from( Array.from(
document.querySelectorAll('.sidebar-products details') document.querySelectorAll('.sidebar-products details')
).forEach(details => details.addEventListener( ).forEach(details => details.addEventListener(
@@ -213,9 +218,17 @@ export default function initializeEvents () {
navigate_label: `link: ${link.href}` navigate_label: `link: ${link.href}`
}) })
}) })
}
// Exit event
pageEventId = pageEvent?.context?.event_id export default function initializeEvents () {
window.addEventListener('scroll', trackScroll) initPageEvent() // must come first
document.addEventListener('visibilitychange', sendExit) initExitEvent()
initLinkEvent()
initClipboardEvent()
initNavigateEvent()
// print event in ./print.js
// survey event in ./helpfulness.js
// experiment event in ./experiment.js
// search event in ./search.js
// redirect event in middleware/record-redirect.js
} }

View File

@@ -32,6 +32,11 @@ const context = {
format: 'date-time', format: 'date-time',
description: 'The time we created the event; please reference UTC.' description: 'The time we created the event; please reference UTC.'
}, },
page_event_id: {
type: 'string',
description: 'The id of the corresponding `page` event.',
format: 'uuid'
},
// Content information // Content information
path: { path: {
@@ -132,8 +137,7 @@ const exitSchema = {
additionalProperties: false, additionalProperties: false,
required: [ required: [
'type', 'type',
'context', 'context'
'exit_page_id'
], ],
properties: { properties: {
context, context,
@@ -141,12 +145,6 @@ const exitSchema = {
type: 'string', type: 'string',
pattern: '^exit$' pattern: '^exit$'
}, },
exit_page_id: {
type: 'string',
format: 'uuid',
description: 'The value of the corresponding `page` event.'
// id of the "page" event
},
exit_first_paint: { exit_first_paint: {
type: 'number', type: 'number',
minimum: 0.001, minimum: 0.001,

View File

@@ -119,6 +119,16 @@ describe('POST /events', () => {
}, 400) }, 400)
) )
it('should allow page_event_id', () =>
checkEvent({
...pageExample,
context: {
...pageExample.context,
page_event_id: baseExample.context.event_id
}
}, 201)
)
it('should not allow a honeypot token', () => it('should not allow a honeypot token', () =>
checkEvent({ checkEvent({
...pageExample, ...pageExample,
@@ -281,7 +291,6 @@ describe('POST /events', () => {
const exitExample = { const exitExample = {
...baseExample, ...baseExample,
type: 'exit', type: 'exit',
exit_page_id: 'c93c2d16-8e07-43d5-bc3c-eacc999c184d',
exit_first_paint: 0.1, exit_first_paint: 0.1,
exit_dom_interactive: 0.2, exit_dom_interactive: 0.2,
exit_dom_complete: 0.3, exit_dom_complete: 0.3,
@@ -293,14 +302,6 @@ describe('POST /events', () => {
checkEvent(exitExample, 201) checkEvent(exitExample, 201)
) )
it('should require exit_page_id', () =>
checkEvent({ ...exitExample, exit_page_id: undefined }, 400)
)
it('should require exit_page_id is a uuid', () =>
checkEvent({ ...exitExample, exit_page_id: 'afjdskalj' }, 400)
)
it('exit_first_paint is a number', () => it('exit_first_paint is a number', () =>
checkEvent({ ...exitExample, exit_first_paint: 'afjdkl' }, 400) checkEvent({ ...exitExample, exit_first_paint: 'afjdkl' }, 400)
) )