PLT-5071: Client side component of Telemetry. (#5516)

Этот коммит содержится в:
George Goldberg
2017-02-24 17:34:21 +00:00
коммит произвёл GitHub
родитель f182d196ff
Коммит 97cc0a0d73
23 изменённых файлов: 280 добавлений и 129 удалений

Просмотреть файл

@@ -497,6 +497,7 @@ export default class CreatePost extends React.Component {
placement='top'
screens={screens}
overlayClass='tip-overlay--chat'
diagnosticsTag='tutorial_tip_1_sending_messages'
/>
);
}

Просмотреть файл

@@ -1,7 +1,7 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import {track} from 'actions/analytics_actions.jsx';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
import Constants from 'utils/constants.jsx';
import {cleanUpUrlable} from 'utils/url.jsx';
@@ -22,6 +22,10 @@ export default class TeamSignupDisplayNamePage extends React.Component {
this.state = {};
}
componentDidMount() {
trackEvent('signup', 'signup_team_01_name');
}
submitNext(e) {
e.preventDefault();
@@ -60,8 +64,6 @@ export default class TeamSignupDisplayNamePage extends React.Component {
}
render() {
track('signup', 'signup_team_02_name');
var nameError = null;
var nameDivClass = 'form-group';
if (this.state.nameError) {

Просмотреть файл

@@ -2,7 +2,7 @@
// See License.txt for license information.
import {checkIfTeamExists, createTeam} from 'actions/team_actions.jsx';
import {track} from 'actions/analytics_actions.jsx';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
import Constants from 'utils/constants.jsx';
import * as URL from 'utils/url.jsx';
@@ -27,6 +27,10 @@ export default class TeamUrl extends React.Component {
};
}
componentDidMount() {
trackEvent('signup', 'signup_team_02_url');
}
submitBack(e) {
e.preventDefault();
this.props.state.wizard = 'display_name';
@@ -106,7 +110,7 @@ export default class TeamUrl extends React.Component {
createTeam(teamSignup.team,
() => {
track('signup', 'signup_team_08_complete');
trackEvent('signup', 'signup_team_03_complete');
},
(err) => {
this.setState({nameError: err.message});
@@ -126,8 +130,6 @@ export default class TeamUrl extends React.Component {
}
render() {
track('signup', 'signup_team_03_url');
let nameError = null;
let nameDivClass = 'form-group';
if (this.state.nameError) {

Просмотреть файл

@@ -26,7 +26,6 @@ export default class LoggedIn extends React.Component {
super(params);
this.onUserChanged = this.onUserChanged.bind(this);
this.setupUser = this.setupUser.bind(this);
// Because current CSS requires the root tag to have specific stuff
$('#root').attr('class', 'channel-view');
@@ -45,9 +44,7 @@ export default class LoggedIn extends React.Component {
user: UserStore.getCurrentUser()
};
if (this.state.user) {
this.setupUser(this.state.user);
} else {
if (!this.state.user) {
GlobalActions.emitUserLoggedOutEvent('/login');
}
}
@@ -56,21 +53,10 @@ export default class LoggedIn extends React.Component {
return this.state.user != null;
}
setupUser(user) {
// Update segment indentify
if (global.window.mm_config.SegmentDeveloperKey != null && global.window.mm_config.SegmentDeveloperKey !== '') {
global.window.analytics.identify(user.id, {
createdAt: user.create_at,
id: user.id
});
}
}
onUserChanged() {
// Grab the current user
const user = UserStore.getCurrentUser();
if (!Utils.areObjectsEqual(this.state.user, user)) {
this.setupUser(user);
this.setState({
user
});

Просмотреть файл

@@ -14,6 +14,7 @@ import $ from 'jquery';
import {browserHistory} from 'react-router/es6';
import UserStore from 'stores/user_store.jsx';
import BrowserStore from 'stores/browser_store.jsx';
import Constants from 'utils/constants.jsx';
export default class Root extends React.Component {
constructor(props) {
@@ -26,12 +27,26 @@ export default class Root extends React.Component {
this.localizationChanged = this.localizationChanged.bind(this);
this.redirectIfNecessary = this.redirectIfNecessary.bind(this);
const segmentKey = Constants.DIAGNOSTICS_SEGMENT_KEY;
// Ya....
/*eslint-disable */
if (window.mm_config.SegmentDeveloperKey != null && window.mm_config.SegmentDeveloperKey !== "") {
if (segmentKey != null && segmentKey !== '' && window.mm_config.DiagnosticsEnabled) {
!function(){var analytics=global.window.analytics=global.window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","group","track","ready","alias","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t<analytics.methods.length;t++){var e=analytics.methods[t];analytics[e]=analytics.factory(e)}analytics.load=function(t){var e=document.createElement("script");e.type="text/javascript";e.async=!0;e.src=("https:"===document.location.protocol?"https://":"http://")+"cdn.segment.com/analytics.js/v1/"+t+"/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(e,n)};analytics.SNIPPET_VERSION="3.0.1";
analytics.load(window.mm_config.SegmentDeveloperKey);
analytics.page();
analytics.load(segmentKey);
analytics.page('ApplicationLoaded', {
path: '',
referrer: '',
search: '',
title: '',
url: '',
},
{
context: {
ip: '0.0.0.0'
},
});
}}();
}
/*eslint-enable */

Просмотреть файл

@@ -21,6 +21,7 @@ import * as Utils from 'utils/utils.jsx';
import * as ChannelUtils from 'utils/channel_utils.jsx';
import * as ChannelActions from 'actions/channel_actions.jsx';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
import Constants from 'utils/constants.jsx';
import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
@@ -363,6 +364,7 @@ export default class Sidebar extends React.Component {
showMoreChannelsModal() {
this.setState({showMoreChannelsModal: true});
trackEvent('ui', 'ui_channels_more_public');
}
hideMoreChannelsModal() {
@@ -378,6 +380,7 @@ export default class Sidebar extends React.Component {
}
showMoreDirectChannelsModal() {
trackEvent('ui', 'ui_channels_more_direct');
this.setState({showDirectChannelsModal: true});
}
@@ -448,6 +451,7 @@ export default class Sidebar extends React.Component {
placement='right'
screens={screens}
overlayClass='tip-overlay--sidebar'
diagnosticsTag='tutorial_tip_2_channels'
/>
);
}
@@ -566,6 +570,7 @@ export default class Sidebar extends React.Component {
<Link
to={link}
className={rowClass}
onClick={this.trackChannelSelectedEvent}
>
{icon}
{channel.display_name}
@@ -577,6 +582,10 @@ export default class Sidebar extends React.Component {
);
}
trackChannelSelectedEvent() {
trackEvent('ui', 'ui_channel_selected');
}
render() {
// Check if we have all info needed to render
if (this.state.currentTeam == null || this.state.currentUser == null) {

Просмотреть файл

@@ -12,6 +12,7 @@ import PreferenceStore from 'stores/preference_store.jsx';
import WebrtcStore from 'stores/webrtc_store.jsx';
import {getFlaggedPosts} from 'actions/post_actions.jsx';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
import * as Utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx';
@@ -71,6 +72,10 @@ export default class SidebarRight extends React.Component {
const isOpen = this.state.searchVisible || this.state.postRightVisible;
const willOpen = nextState.searchVisible || nextState.postRightVisible;
if (!isOpen && willOpen) {
trackEvent('ui', 'ui_rhs_opened');
}
if (isOpen !== willOpen) {
PostStore.jumpPostsViewSidebarOpen();
}

Просмотреть файл

@@ -4,8 +4,9 @@
import LoadingScreen from 'components/loading_screen.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
import BrowserStore from 'stores/browser_store.jsx';
import {track} from 'actions/analytics_actions.jsx';
import {getInviteInfo} from 'actions/team_actions.jsx';
import {loginById, createUserWithInvite} from 'actions/user_actions.jsx';
@@ -37,6 +38,10 @@ export default class SignupEmail extends React.Component {
this.state = this.getInviteInfo();
}
componentDidMount() {
trackEvent('signup', 'signup_user_01_welcome');
}
getInviteInfo() {
let data = this.props.location.query.d;
let hash = this.props.location.query.h;
@@ -117,7 +122,7 @@ export default class SignupEmail extends React.Component {
}
handleSignupSuccess(user, data) {
track('signup', 'signup_user_02_complete');
trackEvent('signup', 'signup_user_02_complete');
loginById(
data.id,
user.password,
@@ -401,8 +406,6 @@ export default class SignupEmail extends React.Component {
}
render() {
track('signup', 'signup_user_01_welcome');
let serverError = null;
if (this.state.serverError) {
serverError = (

Просмотреть файл

@@ -4,9 +4,9 @@
import FormError from 'components/form_error.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
import {track} from 'actions/analytics_actions.jsx';
import {addUserToTeamFromInvite} from 'actions/team_actions.jsx';
import {webLoginByLdap} from 'actions/user_actions.jsx';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
import * as Utils from 'utils/utils.jsx';
@@ -39,6 +39,10 @@ export default class SignupLdap extends React.Component {
});
}
componentDidMount() {
trackEvent('signup', 'signup_user_01_welcome');
}
handleLdapIdChange(e) {
this.setState({
ldapId: e.target.value
@@ -107,8 +111,6 @@ export default class SignupLdap extends React.Component {
}
render() {
track('signup', 'signup_user_01_welcome');
let ldapIdPlaceholder;
if (global.window.mm_config.LdapLoginFieldName) {
ldapIdPlaceholder = global.window.mm_config.LdapLoginFieldName;

Просмотреть файл

@@ -3,6 +3,7 @@
import Constants from 'utils/constants.jsx';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
import {switchTeams} from 'actions/team_actions.jsx';
import React from 'react';
@@ -19,6 +20,7 @@ export default class TeamButton extends React.Component {
handleSwitch(e) {
e.preventDefault();
trackEvent('ui', 'ui_team_sidebar_switch_team');
switchTeams(this.props.url);
}

Просмотреть файл

@@ -6,6 +6,7 @@ import TeamStore from 'stores/team_store.jsx';
import PreferenceStore from 'stores/preference_store.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
import {Constants, Preferences} from 'utils/constants.jsx';
@@ -31,10 +32,23 @@ export default class TutorialIntroScreens extends React.Component {
this.handleNext = this.handleNext.bind(this);
this.createScreen = this.createScreen.bind(this);
this.createCircles = this.createCircles.bind(this);
this.skipTutorial = this.skipTutorial.bind(this);
this.state = {currentScreen: 0};
}
handleNext() {
switch (this.state.currentScreen) {
case 0:
trackEvent('tutorial', 'tutorial_screen_1_welcome_to_mattermost_next');
break;
case 1:
trackEvent('tutorial', 'tutorial_screen_2_how_mattermost_works_next');
break;
case 2:
trackEvent('tutorial', 'tutorial_screen_3_youre_all_set_next');
break;
}
if (this.state.currentScreen < 2) {
this.setState({currentScreen: this.state.currentScreen + 1});
return;
@@ -53,6 +67,18 @@ export default class TutorialIntroScreens extends React.Component {
skipTutorial(e) {
e.preventDefault();
switch (this.state.currentScreen) {
case 0:
trackEvent('tutorial', 'tutorial_screen_1_welcome_to_mattermost_skip');
break;
case 1:
trackEvent('tutorial', 'tutorial_screen_2_how_mattermost_works_skip');
break;
case 2:
trackEvent('tutorial', 'tutorial_screen_3_youre_all_set_skip');
break;
}
AsyncClient.savePreference(
Preferences.TUTORIAL_STEP,
UserStore.getCurrentId(),

Просмотреть файл

@@ -4,6 +4,7 @@
import UserStore from 'stores/user_store.jsx';
import PreferenceStore from 'stores/preference_store.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
import Constants from 'utils/constants.jsx';
@@ -25,6 +26,7 @@ export default class TutorialTip extends React.Component {
this.handleNext = this.handleNext.bind(this);
this.toggle = this.toggle.bind(this);
this.skipTutorial = this.skipTutorial.bind(this);
this.state = {currentScreen: 0, show: false};
}
@@ -48,6 +50,22 @@ export default class TutorialTip extends React.Component {
return;
}
if (this.props.diagnosticsTag) {
let tag = this.props.diagnosticsTag;
if (this.props.screens.length > 1) {
tag += '_' + (this.state.currentScreen + 1).toString();
}
if (this.state.currentScreen === this.props.screens.length - 1) {
tag += '_okay';
} else {
tag += '_next';
}
trackEvent('tutorial', tag);
}
this.closeRightSidebar();
this.toggle();
}
@@ -62,6 +80,15 @@ export default class TutorialTip extends React.Component {
skipTutorial(e) {
e.preventDefault();
if (this.props.diagnosticsTag) {
let tag = this.props.diagnosticsTag;
if (this.props.screens.length > 1) {
tag += '_' + this.state.currentScreen;
}
tag += '_skip';
trackEvent('tutorial', tag);
}
AsyncClient.savePreference(
Preferences.TUTORIAL_STEP,
UserStore.getCurrentId(),
@@ -174,7 +201,8 @@ TutorialTip.defaultProps = {
TutorialTip.propTypes = {
screens: React.PropTypes.array.isRequired,
placement: React.PropTypes.string.isRequired,
overlayClass: React.PropTypes.string
overlayClass: React.PropTypes.string,
diagnosticsTag: React.PropTypes.string
};
export function createMenuTip(toggleFunc, onBottom) {
@@ -207,6 +235,7 @@ export function createMenuTip(toggleFunc, onBottom) {
placement={placement}
screens={screens}
overlayClass={'tip-overlay--header--' + arrow}
diagnosticsTag='tutorial_tip_3_main_menu'
/>
</div>
);

Просмотреть файл

@@ -16,6 +16,7 @@ import * as Utils from 'utils/utils.jsx';
import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage, FormattedDate} from 'react-intl';
import {updateUser, uploadProfileImage} from 'actions/user_actions.jsx';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
const holders = defineMessages({
usernameReserved: {
@@ -127,6 +128,8 @@ class UserSettingsGeneralTab extends React.Component {
user.username = username;
trackEvent('settings', 'user_settings_update', {field: 'username'});
this.submitUser(user, Constants.UserUpdateEvents.USERNAME, false);
}
@@ -143,6 +146,8 @@ class UserSettingsGeneralTab extends React.Component {
user.nickname = nickname;
trackEvent('settings', 'user_settings_update', {field: 'username'});
this.submitUser(user, Constants.UserUpdateEvents.NICKNAME, false);
}
@@ -161,6 +166,8 @@ class UserSettingsGeneralTab extends React.Component {
user.first_name = firstName;
user.last_name = lastName;
trackEvent('settings', 'user_settings_update', {field: 'fullname'});
this.submitUser(user, Constants.UserUpdateEvents.FULLNAME, false);
}
@@ -189,6 +196,7 @@ class UserSettingsGeneralTab extends React.Component {
}
user.email = email;
trackEvent('settings', 'user_settings_update', {field: 'email'});
this.submitUser(user, Constants.UserUpdateEvents.EMAIL, true);
}
@@ -228,6 +236,8 @@ class UserSettingsGeneralTab extends React.Component {
return;
}
trackEvent('settings', 'user_settings_update', {field: 'picture'});
const {formatMessage} = this.props.intl;
const picture = this.state.picture;
@@ -268,6 +278,8 @@ class UserSettingsGeneralTab extends React.Component {
user.position = position;
trackEvent('settings', 'user_settings_update', {field: 'position'});
this.submitUser(user, Constants.UserUpdateEvents.Position, false);
}

Просмотреть файл

@@ -13,6 +13,7 @@ import SearchBox from '../search_bar.jsx';
import WebrtcHeader from './components/webrtc_header.jsx';
import ConnectingScreen from 'components/loading_screen.jsx';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
import * as WebrtcActions from 'actions/webrtc_actions.jsx';
import * as Utils from 'utils/utils.jsx';
@@ -600,6 +601,8 @@ export default class WebrtcController extends React.Component {
}
onFailed() {
trackEvent('api', 'api_users_webrtc_failed');
this.setState({
isCalling: false,
isAnswering: false,
@@ -733,6 +736,7 @@ export default class WebrtcController extends React.Component {
}
doAnswer(jsep) {
trackEvent('api', 'api_users_webrtc_start');
this.videocall.createAnswer({
jsep,
stream: this.localMedia,
@@ -747,6 +751,7 @@ export default class WebrtcController extends React.Component {
}
doHangup(error, manual) {
trackEvent('api', 'api_users_webrtc_end');
if (this.videocall && this.state.callInProgress) {
this.videocall.send({message: {request: 'hangup'}});
this.videocall.hangup();