feat(react): migrate analytics interface to react. (#6296) [EE-2100]
parent
d33ac8c588
commit
65821aaccc
|
@ -79,6 +79,7 @@ overrides:
|
|||
react/forbid-prop-types: off
|
||||
react/require-default-props: off
|
||||
react/no-array-index-key: off
|
||||
no-underscore-dangle: off
|
||||
react/jsx-filename-extension: [0]
|
||||
import/no-extraneous-dependencies: ['error', { devDependencies: true }]
|
||||
'@typescript-eslint/explicit-module-boundary-types': off
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
import _ from 'lodash-es';
|
||||
|
||||
const categories = [
|
||||
'docker',
|
||||
'kubernetes',
|
||||
'aci',
|
||||
'portainer',
|
||||
'edge',
|
||||
] as const;
|
||||
type Category = typeof categories[number];
|
||||
|
||||
enum DimensionConfig {
|
||||
PortainerVersion = 1,
|
||||
PortainerInstanceID,
|
||||
PortainerUserRole,
|
||||
PortainerEndpointUserRole,
|
||||
}
|
||||
|
||||
interface TrackEventProps {
|
||||
category: Category;
|
||||
metadata?: Record<string, unknown>;
|
||||
value?: string | number;
|
||||
dimensions?: DimensionConfig;
|
||||
}
|
||||
|
||||
export function setPortainerStatus(instanceID: string, version: string) {
|
||||
setCustomDimension(DimensionConfig.PortainerInstanceID, instanceID);
|
||||
setCustomDimension(DimensionConfig.PortainerVersion, version);
|
||||
}
|
||||
|
||||
export function setUserRole(role: string) {
|
||||
setCustomDimension(DimensionConfig.PortainerUserRole, role);
|
||||
}
|
||||
|
||||
export function clearUserRole() {
|
||||
deleteCustomDimension(DimensionConfig.PortainerUserRole);
|
||||
}
|
||||
|
||||
export function setUserEndpointRole(role: string) {
|
||||
setCustomDimension(DimensionConfig.PortainerEndpointUserRole, role);
|
||||
}
|
||||
|
||||
export function clearUserEndpointRole() {
|
||||
deleteCustomDimension(DimensionConfig.PortainerEndpointUserRole);
|
||||
}
|
||||
|
||||
function setCustomDimension(dimensionId: number, value: string) {
|
||||
push('setCustomDimension', dimensionId, value);
|
||||
}
|
||||
|
||||
function deleteCustomDimension(dimensionId: number) {
|
||||
push('deleteCustomDimension', dimensionId.toString());
|
||||
}
|
||||
|
||||
export function push(
|
||||
name: string,
|
||||
...args: (string | number | DimensionConfig)[]
|
||||
) {
|
||||
if (typeof window !== 'undefined') {
|
||||
window._paq.push([name, ...args]);
|
||||
}
|
||||
}
|
||||
|
||||
export function trackEvent(action: string, properties: TrackEventProps) {
|
||||
/**
|
||||
* @description Logs an event with an event category (Videos, Music, Games...), an event
|
||||
* action (Play, Pause, Duration, Add Playlist, Downloaded, Clicked...), and an optional
|
||||
* event name and optional numeric value.
|
||||
*
|
||||
* @link https://piwik.org/docs/event-tracking/
|
||||
* @link https://developer.piwik.org/api-reference/tracking-javascript#using-the-tracker-object
|
||||
*
|
||||
*/
|
||||
|
||||
let { value } = properties;
|
||||
const { metadata, dimensions, category } = properties;
|
||||
// PAQ requires that eventValue be an integer, see: http://piwik.org/docs/event-tracking
|
||||
if (value) {
|
||||
const parsed = parseInt(value.toString(), 10);
|
||||
value = Number.isNaN(parsed) ? 0 : parsed;
|
||||
}
|
||||
|
||||
if (!category) {
|
||||
throw new Error('missing category');
|
||||
}
|
||||
|
||||
if (!categories.includes(category)) {
|
||||
throw new Error('unsupported category');
|
||||
}
|
||||
|
||||
let metadataString = '';
|
||||
if (metadata) {
|
||||
const kebabCasedMetadata = Object.fromEntries(
|
||||
Object.entries(metadata).map(([key, value]) => [_.kebabCase(key), value])
|
||||
);
|
||||
metadataString = JSON.stringify(kebabCasedMetadata).toLowerCase();
|
||||
}
|
||||
|
||||
push(
|
||||
'trackEvent',
|
||||
category,
|
||||
action.toLowerCase(),
|
||||
metadataString, // Changed in favour of Piwik documentation. Added fallback so it's backwards compatible.
|
||||
value || '',
|
||||
dimensions || <DimensionConfig>{}
|
||||
);
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
_paq: [string, ...(string | number)[]][];
|
||||
}
|
||||
}
|
|
@ -1,17 +1,7 @@
|
|||
import angular from 'angular';
|
||||
import _ from 'lodash-es';
|
||||
|
||||
import { setPortainerStatus, setUserRole, clearUserRole, setUserEndpointRole, clearUserEndpointRole, push, trackEvent } from './analytics-services';
|
||||
const basePath = 'http://portainer-ce.app';
|
||||
|
||||
const dimensions = {
|
||||
PortainerVersion: 1,
|
||||
PortainerInstanceID: 2,
|
||||
PortainerUserRole: 3,
|
||||
PortainerEndpointUserRole: 4,
|
||||
};
|
||||
|
||||
const categories = ['docker', 'kubernetes', 'aci', 'portainer', 'edge'];
|
||||
|
||||
// forked from https://github.com/angulartics/angulartics-piwik/blob/master/src/angulartics-piwik.js
|
||||
|
||||
/**
|
||||
|
@ -37,12 +27,12 @@ function config($analyticsProvider, $windowProvider) {
|
|||
|
||||
// scope: visit or page. Defaults to 'page'
|
||||
$analyticsProvider.api.setCustomVariable = function (varIndex, varName, value, scope = 'page') {
|
||||
push(['setCustomVariable', varIndex, varName, value, scope]);
|
||||
push('setCustomVariable', varIndex, varName, value, scope);
|
||||
};
|
||||
|
||||
// scope: visit or page. Defaults to 'page'
|
||||
$analyticsProvider.api.deleteCustomVariable = function (varIndex, scope = 'page') {
|
||||
$window._paq.push(['deleteCustomVariable', varIndex, scope]);
|
||||
push('deleteCustomVariable', varIndex, scope);
|
||||
};
|
||||
|
||||
// trackSiteSearch(keyword, category, [searchCount])
|
||||
|
@ -63,7 +53,7 @@ function config($analyticsProvider, $windowProvider) {
|
|||
// logs a conversion for goal 1. revenue is optional
|
||||
// trackGoal(goalID, [revenue]);
|
||||
$analyticsProvider.api.trackGoal = function (goalID, revenue) {
|
||||
push(['trackGoal', goalID, revenue || 0]);
|
||||
push('trackGoal', goalID, revenue || 0);
|
||||
};
|
||||
|
||||
// track outlink or download
|
||||
|
@ -71,21 +61,21 @@ function config($analyticsProvider, $windowProvider) {
|
|||
// trackLink(url, [linkType]);
|
||||
$analyticsProvider.api.trackLink = function (url, linkType) {
|
||||
const type = linkType || 'link';
|
||||
push(['trackLink', url, type]);
|
||||
push('trackLink', url, type);
|
||||
};
|
||||
|
||||
// Set default angulartics page and event tracking
|
||||
|
||||
$analyticsProvider.registerSetUsername(function (username) {
|
||||
push(['setUserId', username]);
|
||||
push('setUserId', username);
|
||||
});
|
||||
|
||||
// locationObj is the angular $location object
|
||||
$analyticsProvider.registerPageTrack(function (path) {
|
||||
push(['setDocumentTitle', $window.document.title]);
|
||||
push(['setReferrerUrl', '']);
|
||||
push(['setCustomUrl', basePath + path]);
|
||||
push(['trackPageView']);
|
||||
push('setDocumentTitle', $window.document.title);
|
||||
push('setReferrerUrl', '');
|
||||
push('setCustomUrl', basePath + path);
|
||||
push('trackPageView');
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -95,56 +85,7 @@ function config($analyticsProvider, $windowProvider) {
|
|||
* @param {string} action A string corresponding to the type of event that needs to be tracked.
|
||||
* @param {object} properties The properties that need to be logged with the event.
|
||||
*/
|
||||
$analyticsProvider.registerEventTrack(function trackEvent(action, properties = {}) {
|
||||
/**
|
||||
* @description Logs an event with an event category (Videos, Music, Games...), an event
|
||||
* action (Play, Pause, Duration, Add Playlist, Downloaded, Clicked...), and an optional
|
||||
* event name and optional numeric value.
|
||||
*
|
||||
* @link https://piwik.org/docs/event-tracking/
|
||||
* @link https://developer.piwik.org/api-reference/tracking-javascript#using-the-tracker-object
|
||||
*
|
||||
* @property {string} category
|
||||
* @property {string} action
|
||||
* @property {object} metadata
|
||||
* @property value (optional)
|
||||
* @property dimensions (optional)
|
||||
*/
|
||||
|
||||
let { category, metadata, value, dimensions } = properties;
|
||||
|
||||
// PAQ requires that eventValue be an integer, see: http://piwik.org/docs/event-tracking
|
||||
if (value) {
|
||||
const parsed = parseInt(properties.value, 10);
|
||||
properties.value = isNaN(parsed) ? 0 : parsed;
|
||||
}
|
||||
|
||||
if (!category) {
|
||||
throw new Error('missing category');
|
||||
}
|
||||
category = category.toLowerCase();
|
||||
|
||||
if (!categories.includes(category)) {
|
||||
throw new Error('unsupported category');
|
||||
}
|
||||
|
||||
action = action.toLowerCase();
|
||||
|
||||
let metadataString = '';
|
||||
if (metadata) {
|
||||
const kebabCasedMetadata = Object.fromEntries(Object.entries(metadata).map(([key, value]) => [_.kebabCase(key), value]));
|
||||
metadataString = JSON.stringify(kebabCasedMetadata).toLowerCase();
|
||||
}
|
||||
|
||||
push([
|
||||
'trackEvent',
|
||||
category,
|
||||
action,
|
||||
metadataString, // Changed in favour of Piwik documentation. Added fallback so it's backwards compatible.
|
||||
value,
|
||||
dimensions || {},
|
||||
]);
|
||||
});
|
||||
$analyticsProvider.registerEventTrack(trackEvent);
|
||||
|
||||
/**
|
||||
* @name exceptionTrack
|
||||
|
@ -154,41 +95,6 @@ function config($analyticsProvider, $windowProvider) {
|
|||
* @param {object} cause The cause of the error given from $exceptionHandler, not used.
|
||||
*/
|
||||
$analyticsProvider.registerExceptionTrack(function (error) {
|
||||
push(['trackEvent', 'Exceptions', error.toString(), error.stack, 0]);
|
||||
push('trackEvent', 'Exceptions', error.toString(), error.stack, 0);
|
||||
});
|
||||
|
||||
function push(args) {
|
||||
if ($window._paq) {
|
||||
$window._paq.push(args);
|
||||
}
|
||||
}
|
||||
|
||||
function setPortainerStatus(instanceID, version) {
|
||||
setCustomDimension(dimensions.PortainerInstanceID, instanceID);
|
||||
setCustomDimension(dimensions.PortainerVersion, version);
|
||||
}
|
||||
|
||||
function setUserRole(role) {
|
||||
setCustomDimension(dimensions.PortainerUserRole, role);
|
||||
}
|
||||
|
||||
function clearUserRole() {
|
||||
deleteCustomDimension(dimensions.PortainerUserRole);
|
||||
}
|
||||
|
||||
function setUserEndpointRole(role) {
|
||||
setCustomDimension(dimensions.PortainerEndpointUserRole, role);
|
||||
}
|
||||
|
||||
function clearUserEndpointRole() {
|
||||
deleteCustomDimension(dimensions.PortainerEndpointUserRole);
|
||||
}
|
||||
|
||||
function setCustomDimension(dimensionId, value) {
|
||||
push(['setCustomDimension', dimensionId, value]);
|
||||
}
|
||||
|
||||
function deleteCustomDimension(dimensionId) {
|
||||
push(['deleteCustomDimension', dimensionId]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue