Commit aea7e507 authored by Axel García's avatar Axel García

Improve Snowplow frontend implementation

parent 0a5e6e68
...@@ -28,10 +28,10 @@ Tracking implementations must have an `action` and a `category`. You can provide ...@@ -28,10 +28,10 @@ Tracking implementations must have an `action` and a `category`. You can provide
properties from the [structured event taxonomy](index.md#structured-event-taxonomy), alongside properties from the [structured event taxonomy](index.md#structured-event-taxonomy), alongside
an `extra` object that accepts key-value pairs. an `extra` object that accepts key-value pairs.
| Field | Type | Default value | Description | | Property | Type | Default value | Description |
|:-----------|:-------|:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |:-----------|:-------|:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `category` | string | `document.body.dataset.page` | Page or subsection of a page in which events are captured. | | `category` | string | `document.body.dataset.page` | Page or subsection of a page in which events are captured. |
| `action` | string | generic | Action the user is taking. Clicks must be `click` and activations must be `activate`. For example, focusing a form field is `activate_form_input`, and clicking a button is `click_button`. | | `action` | string | `'generic'` | Action the user is taking. Clicks must be `click` and activations must be `activate`. For example, focusing a form field is `activate_form_input`, and clicking a button is `click_button`. |
| `data` | object | `{}` | Additional data such as `label`, `property`, `value` as described in [Structured event taxonomy](index.md#structured-event-taxonomy), `context` for custom contexts, and `extra` (key-value pairs object). | | `data` | object | `{}` | Additional data such as `label`, `property`, `value` as described in [Structured event taxonomy](index.md#structured-event-taxonomy), `context` for custom contexts, and `extra` (key-value pairs object). |
### Usage recommendations ### Usage recommendations
...@@ -117,63 +117,64 @@ track_action: "click_button" }) ...@@ -117,63 +117,64 @@ track_action: "click_button" })
### Implement Vue component tracking ### Implement Vue component tracking
For custom event tracking, use a Vue `mixin` in components. Vue `mixin` exposes the `Tracking.event` For custom event tracking, use the [Vue mixin](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/tracking/tracking.js#L207). It exposes `Tracking.event` as the `track` method.
static method and the `track` method. You can specify tracking options in `data` or `computed`. You can specify tracking options in by creating a `tracking` data object
These options override any defaults and allow the values to be dynamic from props or based on state. or computed property, and as a second parameter: `this.track('click_button', opts)`.
These options override any defaults and allow the values to be dynamic from props or based on state:
Several default options are passed when an event is tracked from the component: | Property | Type | Default | Example |
| -- | -- | -- | -- |
- `category`: If you don't specify, by default `document.body.dataset.page` is used. | `category` | string | `document.body.dataset.page` | `'code_quality_walkthrough'` |
- `label` | `label` | string | `''` | `'process_start_button'` |
- `property` | `property` | string | `''` | `'asc'` or `'desc'` |
- `value` | `value` | integer | `undefined` | `0`, `1`, `500` |
| `extra` | object | `{}` | `{ selectedVariant: this.variant }` |
To implement Vue component tracking: To implement Vue component tracking:
1. Import the `Tracking` library and request a `mixin`: 1. Import the `Tracking` library and call the `mixin` method:
```javascript ```javascript
import Tracking from '~/tracking'; import Tracking from '~/tracking';
const trackingMixin = Tracking.mixin;
```
1. Provide categories to track the event from the component. For example, to track all events in a const trackingMixin = Tracking.mixin();
component with a label, use the `label` category:
```javascript // Optionally provide default properties
import Tracking from '~/tracking'; // const trackingMixin = Tracking.mixin({ label: 'right_sidebar' });
const trackingMixin = Tracking.mixin({ label: 'right_sidebar' });
``` ```
1. In the component, declare the Vue `mixin`: 1. Use the mixin in the component:
```javascript ```javascript
export default { export default {
mixins: [trackingMixin], mixins: [trackingMixin],
// ...[component implementation]... // Or
// mixins: [Tracking.mixin()],
// mixins: [Tracking.mixin({ label: 'right_sidebar' })],
data() { data() {
return { return {
expanded: false, expanded: false,
tracking: {
label: 'left_sidebar',
},
}; };
}, },
}; };
``` ```
1. To receive event data as a tracking object or computed property: 1. You can specify tracking options in by creating a `tracking` data object
- Declare it in the `data` function. Use a `tracking` object when default event properties are dynamic or provided at runtime: or computed property:
```javascript ```javascript
export default { export default {
name: 'RightSidebar', name: 'RightSidebar',
mixins: [Tracking.mixin()], mixins: [Tracking.mixin()],
data() { data() {
return { return {
expanded: false,
variant: '',
tracking: { tracking: {
label: 'right_sidebar', label: 'right_sidebar',
// category: '',
// property: '', // property: '',
// value: '', // value: '',
// experiment: '', // experiment: '',
...@@ -181,18 +182,28 @@ component with a label, use the `label` category: ...@@ -181,18 +182,28 @@ component with a label, use the `label` category:
}, },
}; };
}, },
// Or
// computed: {
// tracking() {
// return {
// property: this.variant,
// extra: { expanded: this.expanded },
// };
// },
// },
}; };
``` ```
- Declare it in the event data in the `track` function. This object merges with any previously provided options: 1. Call the `track` method. Tracking options can be passed as the second parameter:
```javascript ```javascript
this.track('click_button', { this.track('click_button', {
label: 'right_sidebar', label: 'right_sidebar',
}); });
``` ```
1. Optional. Use the `track` method in a template: Or use the `track` method in the template:
```html ```html
<template> <template>
...@@ -201,55 +212,67 @@ component with a label, use the `label` category: ...@@ -201,55 +212,67 @@ component with a label, use the `label` category:
<div v-if="expanded"> <div v-if="expanded">
<p>Hello world!</p> <p>Hello world!</p>
<button @click="track('click_action')">Track another event</button> <button @click="track('click_button')">Track another event</button>
</div> </div>
</div> </div>
</template> </template>
``` ```
The following example shows an implementation of Vue component tracking: #### Testing example
```javascript ```javascript
export default { export default {
name: 'RightSidebar', name: 'CountDropdown',
mixins: [Tracking.mixin({ label: 'right_sidebar' })],
mixins: [Tracking.mixin({ label: 'count_dropdown' })],
data() { data() {
return { return {
expanded: false, variant: 'counter',
count: 0,
}; };
}, },
methods: { methods: {
toggle() { handleChange({ target }) {
this.expanded = !this.expanded; const { variant } = this;
// Additional data will be merged, like `value` below
this.track('click_toggle', { value: Number(this.expanded) }); this.count = Number(target.value);
}
} this.track('change_value', {
value: this.count,
extra: { variant }
});
},
},
}; };
``` ```
#### Testing example
```javascript ```javascript
import { mockTracking } from 'helpers/tracking_helper'; import { mockTracking } from 'helpers/tracking_helper';
// mockTracking(category, documentOverride, spyMethod) // mockTracking(category, documentOverride, spyMethod)
describe('RightSidebar.vue', () => { describe('CountDropdown.vue', () => {
let trackingSpy; let trackingSpy;
let wrapper; let wrapper;
...
beforeEach(() => { beforeEach(() => {
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn); trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
}); });
const findToggle = () => wrapper.find('[data-testid="toggle"]'); const findDropdown = () => wrapper.find('[data-testid="dropdown"]');
it('tracks turning off toggle', () => { it('tracks change event', () => {
findToggle().trigger('click'); const dropdown = findDropdown();
dropdown.element.value = 30;
dropdown.trigger('change');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_toggle', { expect(trackingSpy).toHaveBeenCalledWith(undefined, 'change_value', {
label: 'right_sidebar', value: 30,
value: 0, label: 'count_dropdown',
extra: { variant: 'counter' },
}); });
}); });
}); });
...@@ -257,7 +280,8 @@ describe('RightSidebar.vue', () => { ...@@ -257,7 +280,8 @@ describe('RightSidebar.vue', () => {
### Implement raw JavaScript tracking ### Implement raw JavaScript tracking
To call custom event tracking and instrumentation directly from the JavaScript file, call the `Tracking.event` static function. To track from a vanilla JavaScript file, use the `Tracking.event` static function
(calls [`dispatchSnowplowEvent`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/tracking/dispatch_snowplow_event.js)).
The following example demonstrates tracking a click on a button by manually calling `Tracking.event`. The following example demonstrates tracking a click on a button by manually calling `Tracking.event`.
...@@ -267,7 +291,7 @@ import Tracking from '~/tracking'; ...@@ -267,7 +291,7 @@ import Tracking from '~/tracking';
const button = document.getElementById('create_from_template_button'); const button = document.getElementById('create_from_template_button');
button.addEventListener('click', () => { button.addEventListener('click', () => {
Tracking.event('dashboard:projects:index', 'click_button', { Tracking.event(undefined, 'click_button', {
label: 'create_from_template', label: 'create_from_template',
property: 'template_preview', property: 'template_preview',
extra: { extra: {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment