Skip to content
Snippets Groups Projects
Commit 92e6852f authored by Allen Gilliland's avatar Allen Gilliland
Browse files

Merge pull request #792 from metabase/ga_event_tracking

Google Analytics Event Tracking
parents 01619357 46f7c49c
No related branches found
No related tags found
No related merge requests found
......@@ -8,7 +8,6 @@ var Corvus = angular.module('corvus', [
'ngCookies',
'ngSanitize',
'xeditable', // inplace editing capabilities
'angularytics', // google analytics
'ui.bootstrap', // bootstrap LIKE widgets via angular directives
'gridster', // used for dashboard grids
'ui.sortable',
......@@ -69,13 +68,3 @@ Corvus.run(["AppState", "editableOptions", "editableThemes", function(AppState,
editableThemes['default'].submitTpl = '<button class="Button Button--primary" type="submit">Save</button>';
editableThemes['default'].cancelTpl = '<button class="Button" ng-click="$form.$cancel()">cancel</button>';
}]);
if (document.location.hostname != "localhost") {
// Only set up logging in production
Corvus.config(["AngularyticsProvider", function(AngularyticsProvider) {
AngularyticsProvider.setEventHandlers(['Console', 'GoogleUniversal']);
}]).run(["Angularytics", function(Angularytics) {
Angularytics.init();
}]);
}
'use strict';
/*global _, document, confirm*/
import MetabaseAnalytics from '../lib/metabase_analytics';
import DataReference from '../query_builder/data_reference.react';
import GuiQueryEditor from '../query_builder/gui_query_editor.react';
import NativeQueryEditor from '../query_builder/native_query_editor.react';
......@@ -10,6 +12,7 @@ import QueryVisualization from '../query_builder/visualization.react';
import Query from '../query_builder/query';
import { serializeCardForUrl, deserializeCardFromUrl, cleanCopyCard, urlForCardState } from './card.util';
// Card Controllers
var CardControllers = angular.module('corvus.card.controllers', []);
......@@ -147,9 +150,13 @@ CardControllers.controller('CardDetail', [
},
notifyCardCreatedFn: function(newCard) {
setCard(newCard, { resetDirty: true, replaceState: true });
MetabaseAnalytics.trackEvent('QueryBuilder', 'Create Card', newCard.dataset_query.type);
},
notifyCardUpdatedFn: function(updatedCard) {
setCard(updatedCard, { resetDirty: true, replaceState: true });
MetabaseAnalytics.trackEvent('QueryBuilder', 'Update Card', updatedCard.dataset_query.type);
},
setQueryModeFn: function(mode) {
if (!card.dataset_query.type || mode !== card.dataset_query.type) {
......@@ -498,6 +505,8 @@ CardControllers.controller('CardDetail', [
renderAll();
});
MetabaseAnalytics.trackEvent('QueryBuilder', 'Run Query', dataset_query.type);
}
function getDefaultQuery() {
......@@ -708,6 +717,8 @@ CardControllers.controller('CardDetail', [
// clear out any visualization and reset to defaults
queryResult = null;
card.display = "table";
MetabaseAnalytics.trackEvent('QueryBuilder', 'Query Started', mode);
}
}
......
'use strict';
/*global _*/
import MetabaseAnalytics from '../lib/metabase_analytics';
// Dashboard Controllers
var DashboardControllers = angular.module('corvus.dashboard.controllers', []);
......@@ -102,6 +105,13 @@ DashboardControllers.controller('DashDetail', ['$scope', '$routeParams', '$locat
}
$scope.gridsterOptions.draggable.enabled = !$scope.gridsterOptions.draggable.enabled;
$scope.gridsterOptions.resizable.enabled = !$scope.gridsterOptions.resizable.enabled;
// Tracking
if ($scope.gridsterOptions.resizable.enabled) {
MetabaseAnalytics.trackEvent('Dashboard', 'Rearrange Finished');
} else {
MetabaseAnalytics.trackEvent('Dashboard', 'Rearrange Started');
}
};
$scope.notifyDashboardSaved = function(dashboard) {
......
'use strict';
/*global ga*/
// Simple module for in-app analytics. Currently sends data to GA but could be extended to anything else.
var MetabaseAnalytics = {
// track a pageview (a.k.a. route change)
trackPageView: function(url) {
if (url) {
// scrub query builder urls to remove serialized json queries from path
url = (url.lastIndexOf('/q/', 0) === 0) ? '/q/' : url;
ga('set', 'page', url);
ga('send', 'pageview', url);
}
},
// track an event
trackEvent: function(category, action, label, value) {
// category & action are required, rest are optional
if (category && action) {
ga('send', 'event', category, action, label, value);
}
}
}
export default MetabaseAnalytics;
'use strict';
/*global _*/
import MetabaseAnalytics from '../lib/metabase_analytics';
import AggregationWidget from './aggregation_widget.react';
import DataSelector from './data_selector.react';
import FieldWidget from './field_widget.react';
......@@ -36,48 +38,66 @@ export default React.createClass({
addDimension: function() {
Query.addDimension(this.props.query.query);
this.setQuery(this.props.query);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Add GroupBy');
},
updateDimension: function(index, dimension) {
Query.updateDimension(this.props.query.query, dimension, index);
this.setQuery(this.props.query);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Modify GroupBy');
},
removeDimension: function(index) {
Query.removeDimension(this.props.query.query, index);
this.setQuery(this.props.query);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Remove GroupBy');
},
updateAggregation: function(aggregationClause) {
Query.updateAggregation(this.props.query.query, aggregationClause);
this.setQuery(this.props.query);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Set Aggregation', aggregationClause[0]);
},
addFilter: function() {
Query.addFilter(this.props.query.query);
this.setQuery(this.props.query);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Add Filter');
},
updateFilter: function(index, filter) {
Query.updateFilter(this.props.query.query, index, filter);
this.setQuery(this.props.query);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Modify Filter');
},
removeFilter: function(index) {
Query.removeFilter(this.props.query.query, index);
this.setQuery(this.props.query);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Remove Filter');
},
addLimit: function() {
Query.addLimit(this.props.query.query);
this.setQuery(this.props.query);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Set Limit');
},
updateLimit: function(limit) {
if (limit) {
Query.updateLimit(this.props.query.query, limit);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Set Limit');
} else {
Query.removeLimit(this.props.query.query);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Remove Limit');
}
this.setQuery(this.props.query);
},
......@@ -85,16 +105,22 @@ export default React.createClass({
addSort: function() {
Query.addSort(this.props.query.query);
this.setQuery(this.props.query);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Set Sort', 'manual');
},
updateSort: function(index, sort) {
Query.updateSort(this.props.query.query, index, sort);
this.setQuery(this.props.query);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Set Sort', 'manual');
},
removeSort: function(index) {
Query.removeSort(this.props.query.query, index);
this.setQuery(this.props.query);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Remove Sort');
},
renderAdd: function(text, onClick) {
......
'use strict';
/*global _*/
import MetabaseAnalytics from '../lib/metabase_analytics';
import FixedDataTable from 'fixed-data-table';
import Icon from './icon.react';
......@@ -119,6 +121,8 @@ export default React.createClass({
setSort: function(fieldId) {
this.props.setSortFn(fieldId);
MetabaseAnalytics.trackEvent('QueryBuilder', 'Set Sort', 'table column');
},
cellClicked: function(rowIndex, columnIndex) {
......
......@@ -3,6 +3,8 @@
/*global _*/
/* Services */
import MetabaseAnalytics from './lib/metabase_analytics';
var CorvusServices = angular.module('corvus.services', ['http-auth-interceptor', 'ipCookie', 'corvus.core.services']);
CorvusServices.factory('AppState', ['$rootScope', '$q', '$location', '$timeout', 'ipCookie', 'Session', 'User', 'Settings',
......@@ -159,6 +161,12 @@ CorvusServices.factory('AppState', ['$rootScope', '$q', '$location', '$timeout',
}
};
// listen for location changes and use that as a trigger for page view tracking
$rootScope.$on('$locationChangeSuccess', function() {
// NOTE: we are only taking the path right now to avoid accidentally grabbing sensitive data like table/field ids
MetabaseAnalytics.trackPageView($location.path());
});
// listen for all route changes so that we can update organization as appropriate
$rootScope.$on('$routeChangeSuccess', service.routeChanged);
......
......@@ -130,6 +130,5 @@
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-60817802-1', 'auto');
ga('send', 'pageview');
</script>
</html>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment