From 97cc0a0d73dcacfefcdff785c802762e2a0a60d6 Mon Sep 17 00:00:00 2001 From: George Goldberg Date: Fri, 24 Feb 2017 17:34:21 +0000 Subject: PLT-5071: Client side component of Telemetry. (#5516) --- webapp/components/create_post.jsx | 1 + .../create_team/components/display_name.jsx | 8 +++--- .../components/create_team/components/team_url.jsx | 10 ++++--- webapp/components/logged_in.jsx | 16 +---------- webapp/components/root.jsx | 21 ++++++++++++--- webapp/components/sidebar.jsx | 9 +++++++ webapp/components/sidebar_right.jsx | 5 ++++ .../components/signup/components/signup_email.jsx | 11 +++++--- .../components/signup/components/signup_ldap.jsx | 8 +++--- .../team_sidebar/components/team_button.jsx | 2 ++ .../components/tutorial/tutorial_intro_screens.jsx | 26 ++++++++++++++++++ webapp/components/tutorial/tutorial_tip.jsx | 31 +++++++++++++++++++++- .../user_settings/user_settings_general.jsx | 12 +++++++++ webapp/components/webrtc/webrtc_controller.jsx | 5 ++++ 14 files changed, 132 insertions(+), 33 deletions(-) (limited to 'webapp/components') diff --git a/webapp/components/create_post.jsx b/webapp/components/create_post.jsx index 581ed16a0..7bdcf6888 100644 --- a/webapp/components/create_post.jsx +++ b/webapp/components/create_post.jsx @@ -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' /> ); } diff --git a/webapp/components/create_team/components/display_name.jsx b/webapp/components/create_team/components/display_name.jsx index 29077bd24..aeb8afbb9 100644 --- a/webapp/components/create_team/components/display_name.jsx +++ b/webapp/components/create_team/components/display_name.jsx @@ -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) { diff --git a/webapp/components/create_team/components/team_url.jsx b/webapp/components/create_team/components/team_url.jsx index 2ab143d7f..c8a60cdf9 100644 --- a/webapp/components/create_team/components/team_url.jsx +++ b/webapp/components/create_team/components/team_url.jsx @@ -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) { diff --git a/webapp/components/logged_in.jsx b/webapp/components/logged_in.jsx index 9282e74ca..8d7a00653 100644 --- a/webapp/components/logged_in.jsx +++ b/webapp/components/logged_in.jsx @@ -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 }); diff --git a/webapp/components/root.jsx b/webapp/components/root.jsx index 465df5d79..4e7c19452 100644 --- a/webapp/components/root.jsx +++ b/webapp/components/root.jsx @@ -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 ); } @@ -566,6 +570,7 @@ export default class Sidebar extends React.Component { {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) { diff --git a/webapp/components/sidebar_right.jsx b/webapp/components/sidebar_right.jsx index da7ff818d..fb120337a 100644 --- a/webapp/components/sidebar_right.jsx +++ b/webapp/components/sidebar_right.jsx @@ -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(); } diff --git a/webapp/components/signup/components/signup_email.jsx b/webapp/components/signup/components/signup_email.jsx index 8325c9f56..cf4ff0a95 100644 --- a/webapp/components/signup/components/signup_email.jsx +++ b/webapp/components/signup/components/signup_email.jsx @@ -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 = ( diff --git a/webapp/components/signup/components/signup_ldap.jsx b/webapp/components/signup/components/signup_ldap.jsx index bf98d0461..0e02d5db7 100644 --- a/webapp/components/signup/components/signup_ldap.jsx +++ b/webapp/components/signup/components/signup_ldap.jsx @@ -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; diff --git a/webapp/components/team_sidebar/components/team_button.jsx b/webapp/components/team_sidebar/components/team_button.jsx index 6fbf8aef9..894567538 100644 --- a/webapp/components/team_sidebar/components/team_button.jsx +++ b/webapp/components/team_sidebar/components/team_button.jsx @@ -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); } diff --git a/webapp/components/tutorial/tutorial_intro_screens.jsx b/webapp/components/tutorial/tutorial_intro_screens.jsx index a0b6118d3..c266191b8 100644 --- a/webapp/components/tutorial/tutorial_intro_screens.jsx +++ b/webapp/components/tutorial/tutorial_intro_screens.jsx @@ -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(), diff --git a/webapp/components/tutorial/tutorial_tip.jsx b/webapp/components/tutorial/tutorial_tip.jsx index 7b613fe51..e78668b10 100644 --- a/webapp/components/tutorial/tutorial_tip.jsx +++ b/webapp/components/tutorial/tutorial_tip.jsx @@ -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' /> ); diff --git a/webapp/components/user_settings/user_settings_general.jsx b/webapp/components/user_settings/user_settings_general.jsx index d79507511..f9c624aa0 100644 --- a/webapp/components/user_settings/user_settings_general.jsx +++ b/webapp/components/user_settings/user_settings_general.jsx @@ -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); } diff --git a/webapp/components/webrtc/webrtc_controller.jsx b/webapp/components/webrtc/webrtc_controller.jsx index b8d3d4db6..0fab0d2e7 100644 --- a/webapp/components/webrtc/webrtc_controller.jsx +++ b/webapp/components/webrtc/webrtc_controller.jsx @@ -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(); -- cgit v1.2.3-1-g7c22