Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added mixpanel tracking for some basic events #2462

Merged
merged 6 commits into from
Apr 27, 2017
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Added mixpanel tracking for bunch of events.
fbarl committed Apr 26, 2017
commit 14912834829c2e99f8bff06210bebfc5ee06064a
30 changes: 29 additions & 1 deletion client/app/scripts/actions/app-actions.js
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@ import {
import { getCurrentTopologyUrl } from '../utils/topology-utils';
import { storageSet } from '../utils/storage-utils';
import { loadTheme } from '../utils/contrast-utils';
import { trackMixpanelEvent } from '../utils/tracking-utils';
import {
availableMetricTypesSelector,
selectedMetricTypeSelector,
@@ -200,6 +201,13 @@ export function changeTopologyOption(option, value, topologyId, addOrRemove) {
// update all request workers with new options
resetUpdateBuffer();
const state = getState();
trackMixpanelEvent('scope.topology.option.click', {
option,
value,
layout: state.get('topologyViewMode'),
topologyId: state.getIn(['currentTopology', 'id']),
parentTopologyId: state.getIn(['currentTopology', 'parentId']),
});
getTopologies(activeTopologyOptionsSelector(state), dispatch);
getNodesDelta(
getCurrentTopologyUrl(state),
@@ -257,7 +265,11 @@ export function clickDownloadGraph() {
}

export function clickForceRelayout() {
return (dispatch) => {
return (dispatch, getState) => {
const state = getState();
trackMixpanelEvent('scope.layout.refresh.click', {
layout: state.get('topologyViewMode'),
});
dispatch({
type: ActionTypes.CLICK_FORCE_RELAYOUT,
forceRelayout: true
@@ -335,6 +347,11 @@ export function clickNode(nodeId, label, origin) {
});
updateRoute(getState);
const state = getState();
trackMixpanelEvent('scope.node.click', {
layout: state.get('topologyViewMode'),
topologyId: state.getIn(['currentTopology', 'id']),
parentTopologyId: state.getIn(['currentTopology', 'parentId']),
});
getNodeDetails(
state.get('topologyUrlsById'),
state.get('currentTopologyId'),
@@ -362,6 +379,11 @@ export function clickRelative(nodeId, topologyId, label, origin) {
});
updateRoute(getState);
const state = getState();
trackMixpanelEvent('scope.node.relative.click', {
layout: state.get('topologyViewMode'),
topologyId: state.getIn(['currentTopology', 'id']),
parentTopologyId: state.getIn(['currentTopology', 'parentId']),
});
getNodeDetails(
state.get('topologyUrlsById'),
state.get('currentTopologyId'),
@@ -511,6 +533,12 @@ export function hitEnter() {
if (state.get('searchFocused')) {
const query = state.get('searchQuery');
if (query && parseQuery(query)) {
trackMixpanelEvent('scope.search.query.pin', {
query,
layout: state.get('topologyViewMode'),
topologyId: state.getIn(['currentTopology', 'id']),
parentTopologyId: state.getIn(['currentTopology', 'parentId']),
});
dispatch({
type: ActionTypes.PIN_SEARCH,
query
17 changes: 16 additions & 1 deletion client/app/scripts/components/metric-selector-item.js
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import { connect } from 'react-redux';

import { hoverMetric, pinMetric, unpinMetric } from '../actions/app-actions';
import { selectedMetricTypeSelector } from '../selectors/node-metric';
import { trackMixpanelEvent } from '../utils/tracking-utils';


class MetricSelectorItem extends React.Component {
@@ -24,8 +25,20 @@ class MetricSelectorItem extends React.Component {
const pinnedMetricType = this.props.pinnedMetricType;

if (metricType !== pinnedMetricType) {
trackMixpanelEvent('scope.metric.resource.pin', {
metricType,
layout: this.props.topologyViewMode,
topologyId: this.props.currentTopology.get('id'),
parentTopologyId: this.props.currentTopology.get('parentId'),
});
this.props.pinMetric(metricType);
} else {
trackMixpanelEvent('scope.metric.resource.unpin', {
metricType,
layout: this.props.topologyViewMode,
topologyId: this.props.currentTopology.get('id'),
parentTopologyId: this.props.currentTopology.get('parentId'),
});
this.props.unpinMetric();
}
}
@@ -54,8 +67,10 @@ class MetricSelectorItem extends React.Component {

function mapStateToProps(state) {
return {
selectedMetricType: selectedMetricTypeSelector(state),
topologyViewMode: state.get('topologyViewMode'),
currentTopology: state.get('currentTopology'),
pinnedMetricType: state.get('pinnedMetricType'),
selectedMetricType: selectedMetricTypeSelector(state),
};
}

13 changes: 12 additions & 1 deletion client/app/scripts/components/search.js
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import { searchMatchCountByTopologySelector } from '../selectors/search';
import { isResourceViewModeSelector } from '../selectors/topology';
import { slugify } from '../utils/string-utils';
import { isTopologyEmpty } from '../utils/topology-utils';
import { trackMixpanelEvent } from '../utils/tracking-utils';
import SearchItem from './search-item';


@@ -71,7 +72,7 @@ class Search extends React.Component {
if (this.state.value && value === '') {
value = null;
}
this.setState({value});
this.setState({ value });
this.doSearch(inputValue);
}

@@ -80,6 +81,14 @@ class Search extends React.Component {
}

doSearch(value) {
if (value !== '') {
trackMixpanelEvent('scope.search.query.change', {
query: value,

This comment was marked as abuse.

This comment was marked as abuse.

layout: this.props.topologyViewMode,
topologyId: this.props.currentTopology.get('id'),
parentTopologyId: this.props.currentTopology.get('parentId'),
});
}
this.props.doSearch(value);
}

@@ -155,8 +164,10 @@ class Search extends React.Component {
export default connect(
state => ({
nodes: state.get('nodes'),
topologyViewMode: state.get('topologyViewMode'),
isResourceViewMode: isResourceViewModeSelector(state),
isTopologyEmpty: isTopologyEmpty(state),
currentTopology: state.get('currentTopology'),
topologiesLoaded: state.get('topologiesLoaded'),
pinnedSearches: state.get('pinnedSearches'),
searchFocused: state.get('searchFocused'),
13 changes: 10 additions & 3 deletions client/app/scripts/components/topologies.js
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ import React from 'react';
import { connect } from 'react-redux';
import classnames from 'classnames';

import { trackMixpanelEvent } from '../utils/tracking-utils';
import { searchMatchCountByTopologySelector } from '../selectors/search';
import { isResourceViewModeSelector } from '../selectors/topology';
import { clickTopology } from '../actions/app-actions';
@@ -25,8 +26,12 @@ class Topologies extends React.Component {
this.onTopologyClick = this.onTopologyClick.bind(this);
}

onTopologyClick(ev) {
onTopologyClick(ev, topology) {
ev.preventDefault();
trackMixpanelEvent('scope.topology.selector.click', {
topologyId: topology.get('id'),
parentTopologyId: topology.get('parentId'),
});
this.props.clickTopology(ev.currentTarget.getAttribute('rel'));
}

@@ -44,7 +49,7 @@ class Topologies extends React.Component {
return (
<div
className={className} title={title} key={topologyId} rel={topologyId}
onClick={this.onTopologyClick}>
onClick={ev => this.onTopologyClick(ev, subTopology)}>
<div className="topologies-sub-item-label">
{subTopology.get('name')}
</div>
@@ -65,7 +70,9 @@ class Topologies extends React.Component {

return (
<div className="topologies-item" key={topologyId}>
<div className={className} title={title} rel={topologyId} onClick={this.onTopologyClick}>
<div
className={className} title={title} rel={topologyId}
onClick={ev => this.onTopologyClick(ev, topology)}>
<div className="topologies-item-label">
{topology.get('name')}
</div>
66 changes: 39 additions & 27 deletions client/app/scripts/components/view-mode-selector.js
Original file line number Diff line number Diff line change
@@ -3,49 +3,61 @@ import { connect } from 'react-redux';
import classNames from 'classnames';

import MetricSelector from './metric-selector';
import { trackMixpanelEvent } from '../utils/tracking-utils';
import { setGraphView, setTableView, setResourceView } from '../actions/app-actions';
import { layersTopologyIdsSelector } from '../selectors/resource-view/layout';
import { availableMetricsSelector } from '../selectors/node-metric';
import { isResourceViewModeSelector } from '../selectors/topology';
import {
isGraphViewModeSelector,
isTableViewModeSelector,
isResourceViewModeSelector,
} from '../selectors/topology';
GRAPH_VIEW_MODE,
TABLE_VIEW_MODE,
RESOURCE_VIEW_MODE,
} from '../constants/naming';


const Item = (icons, label, isSelected, onClick, isEnabled = true) => {
const className = classNames('view-mode-selector-action', {
'view-mode-selector-action-selected': isSelected,
});
return (
<div
className={className}
disabled={!isEnabled}
onClick={isEnabled && onClick}
title={`View ${label.toLowerCase()}`}>
<span className={icons} style={{fontSize: 12}} />
<span className="label">{label}</span>
</div>
);
};

class ViewModeSelector extends React.Component {
componentWillReceiveProps(nextProps) {
if (nextProps.isResourceViewMode && !nextProps.hasResourceView) {
nextProps.setGraphView();
}
}

renderItem(icons, label, viewMode, setViewModeAction, isEnabled = true) {
const isSelected = (this.props.topologyViewMode === viewMode);
const className = classNames('view-mode-selector-action', {
'view-mode-selector-action-selected': isSelected,
});
const onClick = () => {
trackMixpanelEvent('scope.layout.selector.click', {
layout: viewMode,
topologyId: this.props.currentTopology.get('id'),
parentTopologyId: this.props.currentTopology.get('parentId'),
});
setViewModeAction();
};

return (
<div
className={className}
disabled={!isEnabled}
onClick={isEnabled && onClick}
title={`View ${label.toLowerCase()}`}>
<span className={icons} style={{ fontSize: 12 }} />
<span className="label">{label}</span>
</div>
);
}

render() {
const { isGraphViewMode, isTableViewMode, isResourceViewMode, hasResourceView } = this.props;
const { hasResourceView } = this.props;

return (
<div className="view-mode-selector">
<div className="view-mode-selector-wrapper">
{Item('fa fa-share-alt', 'Graph', isGraphViewMode, this.props.setGraphView)}
{Item('fa fa-table', 'Table', isTableViewMode, this.props.setTableView)}
{Item('fa fa-bar-chart', 'Resources', isResourceViewMode, this.props.setResourceView,
hasResourceView)}
{this.renderItem('fa fa-share-alt', 'Graph', GRAPH_VIEW_MODE, this.props.setGraphView)}
{this.renderItem('fa fa-table', 'Table', TABLE_VIEW_MODE, this.props.setTableView)}
{this.renderItem('fa fa-bar-chart', 'Resources', RESOURCE_VIEW_MODE,
this.props.setResourceView, hasResourceView)}
</div>
<MetricSelector />
</div>
@@ -55,11 +67,11 @@ class ViewModeSelector extends React.Component {

function mapStateToProps(state) {
return {
isGraphViewMode: isGraphViewModeSelector(state),
isTableViewMode: isTableViewModeSelector(state),
isResourceViewMode: isResourceViewModeSelector(state),
hasResourceView: !layersTopologyIdsSelector(state).isEmpty(),
showingMetricsSelector: availableMetricsSelector(state).count() > 0,
topologyViewMode: state.get('topologyViewMode'),
currentTopology: state.get('currentTopology'),
};
}

13 changes: 13 additions & 0 deletions client/app/scripts/utils/tracking-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import debug from 'debug';

const log = debug('service:tracking');

// Track mixpanel events only if Scope is running inside of Weave Cloud.
export function trackMixpanelEvent(name, props) {
if (window.mixpanel && process.env.WEAVE_CLOUD) {
window.mixpanel.track(name, props);
log('trackMixpanelEvent', name, props);
} else {
log('trackMixpanelEvent', name, props);
}
}