-
Notifications
You must be signed in to change notification settings - Fork 1
[RUM-24816][FEATURE] added experimental triggering mechanism. added a… #85
base: development
Are you sure you want to change the base?
Changes from 1 commit
c2eb660
30c3b56
6ac95e5
baa0085
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,8 +5,22 @@ function rciMainAction(tenancyId, rciSdk) { | |
|
||
// Step 2: Capture your default collectors | ||
let defaults = rciSdk.collector.defaultCollectors; | ||
|
||
/** | ||
* @type {Config} | ||
*/ | ||
const config = { | ||
actions: true | ||
actions: true, | ||
actionsBatching: false, | ||
events: [ | ||
{ | ||
selector: 'window', eventName: 'load', eventCategory: 'Document', scope: 'state' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @robertdumitrescu CONSISTENCY - The naming conventions here are becoming a little unclear - particularly as the names crossover from Web APIs to RCI's Data API. I would suggest referencing terms from the Moz documentation and the Data API directly, for example:
I would also suggest that we plumb the |
||
}, | ||
{ | ||
selector: '*', eventName: 'mousedown', eventCategory: 'Mouse', scope: 'action' | ||
} | ||
] | ||
|
||
}; | ||
|
||
// Step 2.1 Prepare the collectors collection | ||
|
@@ -15,8 +29,8 @@ function rciMainAction(tenancyId, rciSdk) { | |
// Step 3: Build a new Producer with transport and collector | ||
const producer = new rciSdk.Producer(transport, defaults); | ||
|
||
// Step 3.2: Register the action triggers | ||
rciSdk.TriggerHelper.registerActionTriggers(producer, config); | ||
// Step 3.2: Register the triggers | ||
rciSdk.TriggerHelper.registerTriggers(producer, config); | ||
|
||
// Step 4: Trigger Event | ||
window.addEventListener('load', async () => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
|
||
const localStorageActionsKey = 'eggplantRciActions'; | ||
export default class ActionBatchingCollector { | ||
|
||
constructor(localStorage) { | ||
this.localStorage = localStorage; | ||
} | ||
|
||
/** | ||
* @param {Event} event | ||
* @param {Context} context | ||
*/ | ||
async prepare (event, context) { | ||
/** Pull out the actions from local storage */ | ||
const actions = this.localStorage.getItem(localStorageActionsKey); | ||
|
||
/** Append the new action */ | ||
actions.push(event.eventInfo5[0]); | ||
if (context.scope === 'state') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @robertdumitrescu MAINTAINABILITY - I'd rather we use ENUMs than lose strings. We have some set up here: https://github.com/TestPlant/real-user-data-sdk-js/blob/development/src/core/constants.js#L1 |
||
|
||
/** Stringify actions and attached it to the state beacon */ | ||
event.eventInfo5 = JSON.stringify(actions); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @robertdumitrescu INFO - We need to be careful about string length as anything above 1024 chars will be rejected. This is much lower than I had originally thought... https://docs.real-user-data.eggplant.cloud/open-api/index.html |
||
|
||
} else if (context.scope === 'action') { | ||
this.localStorage.setItem(localStorageActionsKey, actions); | ||
} | ||
return event; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
export default class ActionStringifyCollector { | ||
|
||
/** | ||
* @param {Event} event | ||
*/ | ||
async prepare (event) { | ||
|
||
event.eventInfo5 = JSON.stringify(event.eventInfo5); | ||
return event; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
export default class InitializeActionCollector { | ||
|
||
|
||
/** | ||
* @param {Event} event | ||
* @param {Context} context | ||
*/ | ||
async prepare (event) { | ||
event.eventInfo5 = [{}]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @robertdumitrescu KISS - Is the empty object required here..? |
||
return event; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/** | ||
* @typedef {Object} Action | ||
* @link https://developer.mozilla.org/en-US/docs/Web/Events | ||
* @description Considerdations: In case of clipboard events, for instance when somebody pastes, all the actionStart properties may be empty/null | ||
* @property {String|null} actionStartEventCategory - Enum: "Clipboard", "Focus", "Drag and Drop", "Touch", "Keyboard", "Mouse". More to come, this is only an initial list that I feel we should support | ||
* @property {String} actionEndEventCategory - Enum: "clipboard", "Focus", "Drag and Drop", "Touch", "Keyboard", "Mouse". More to come, this is only an initial list that I feel we should support | ||
* @property {String|null} actionStartEventName - The type of the event that started the action. Ex: mousedown | ||
* @property {String} actionEndEventName - The type of the event that ended the action. Ex: mouseup | ||
* @property {Number|null} actionStartEventTimestamp - When the action started in miliseconds | ||
* @property {Number} actionEndEventTimestamp - When the action ended in miliseconds | ||
* @property {String|null} actionStartElementCategory - Enum: "document", "window", "StaticElement", "FormElement" | ||
* @property {String} actionEndElementCategory - Enum: "document", "window", "StaticElement", "FormElement" | ||
* @property {Element|null} actionStartElement - In case of clicks/swipes the element that was under the pointer/finger when the action started. In case of scroll the "document". In case of pan in/pan out, the element that was zoomed in/out. In case of device tilt, the "document" | ||
* @property {Element} actionEndElement - In case of clicks/swipes the element that was under the pointer/finger when the action ended. In case of scroll the "document". In case of pan in/pan out, the element that was zoomed in/out. In case of device tilt, the "document" | ||
* @property {String|null} actionStartElementXPath - The XPath of the element | ||
* @property {String} actionEndElementXPath - The XPath of the element | ||
* @property {String|null} actionStartElementCSSPath - The CSS path of the element | ||
* @property {String} actionEndElementCSSPath - The CSS path of the element | ||
* @property {String|null} actionStartElementViewPortCoords - The coordinates of the element in px relative to the top left corner of the screen separated by comma on horizontal and vertical axis | ||
* @property {Number|null} actionStartElementWidth - The width in px of the element | ||
* @property {Number|null} actionStartElementHeight - The height in px of the element | ||
* @property {Boolean|null} actionStartElementHidden - Enum: null if not applicable, true if is hidden, false if is visible | ||
* @property {Boolean|null} actionStartElementDisabled - Enum: null if not applicable, true if is disabled, false if is enabled | ||
* @property {String} actionEndElementViewPortCoords - The coordinates of the element in px relative to the top left corner of the screen separated by comma on horizontal and vertical axis | ||
* @property {Number} actionEndElementWidth - The width in px of the element | ||
* @property {Number} actionEndElementHeight - The height in px of the element | ||
* @property {Boolean} actionEndElementHidden - Enum: null if not applicable, true if is hidden, false if is visible | ||
* @property {Boolean} actionEndElementDisabled - Enum: null if not applicable, true if is disabled, false if is enabled | ||
* @property {String|null} actionStartElementImage - Cropped image of the element for OCR purposes | ||
* @property {String} actionEndElementImage - Cropped image of the element for OCR purposes | ||
* @property {ActionEventLocation[]} actionEventLocations - An array of objects with all the locations of the pointer, finger. This can be used to calculate heatmaps, rage clicks, rage abandonment, user anxiety and other various metrics for abandonment. Probably this can be a phase 2. | ||
* */ | ||
|
||
|
||
/** | ||
* PHASE 2 | ||
* @typedef {Object} ActionEventLocation | ||
* @property {Number} hCoords - Horizontal coordinates in px relative to top left corner of the viewport | ||
* @property {Number} vCoords - Vertical coordinates in px relative to top left corner of the viewport | ||
* @property {Number} timestamp - Timestamp when the location was registered | ||
* */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/** | ||
* @typedef {Object} Config | ||
* @description Configuration object that composes the capability of the SDK | ||
* @property {Boolean} actions - If this is on true, action beacons will be sent to the cloud (address defined in transport). If on false, only on load events (representing states) will be sent. | ||
* @property {Boolean} actionsBatching - If this is on true, the actions beacons will be batched and sent alongside states. Otherwise will be sent as separate events. | ||
* @property {ListenerDefinition[]} events - The events that will trigger beacons | ||
* */ | ||
|
||
/** | ||
* @typedef {Object} ListenerDefinition | ||
* @property {String} selector - The selector on which the event will be listened for | ||
* @property {String} eventName - The name of the event | ||
* @property {String} eventCategory - The name of the event | ||
* @property {String} scope - Either "state", either "action". Useful to identify if the actions array should be pulled from local storage when batching is adctivated and needs to be sent with qa state. | ||
* */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
/** | ||
* @typedef {Object} Context | ||
* @property {String} eventName | ||
* @property {String} scope - Either "state", either "action". Useful to identify if the actions array should be pulled from local storage when batching is adctivated and needs to be sent with qa state. | ||
* @property {HTMLElement} elm - The DOM element or HTML element (no matter from the context is coming from) | ||
* */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@robertdumitrescu CONSISTENCY - I'm all for composition, leading to maximum flexibility. However, if we're going through the trouble of configuring the collectors, I'd like to see all the concatenation and registering to be handled. For example, if something like the following is provided:
That should register all triggers and collectors with the relevant producer. Job done!