PLT-5071: Client side component of Telemetry. (#5516)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
f182d196ff
Коммит
97cc0a0d73
@@ -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();
|
||||
|
||||
Ссылка в новой задаче
Block a user