зеркало из https://github.com/mozilla/notes.git
Implement all GA events (#1033)
This commit is contained in:
Родитель
dcd0182352
Коммит
25b93f741a
|
@ -34,7 +34,7 @@ Data will be collected with Google Analytics and follow [Test Pilot standards](h
|
|||
- `cd4` - whether the user has, anywhere in their active notepad, italicized text. One of `true` or `false`.
|
||||
- `cd5` - whether the user has, anywhere in their active notepad, strikethrough text. One of `true` or `false`.
|
||||
- `cd6` - whether the user has, anywhere in their active notepad, a list. One of `true` or `false`.
|
||||
- `cd7` - the UI element used to open or close the notepad. Possible values TBD, but may include `closeButton`, `sidebarButton`, and `sidebarSwitcher`.
|
||||
- `cd7` - the UI element used to open or close the notepad. Possible values TBD, but may include `closeButton`, `sidebarButton`, `sidebarSwitcher`, `appBackground`, `appInactive`.
|
||||
- `cd8` - the reason an editing session ended. One of `timeout` or `closed`.
|
||||
- `cd9` - whether the user was able to load the note panel or not. One of `true` or `false`.
|
||||
- `cd10` - provide current user state. Possible values are: 'error', 'isSyncing', 'synced', 'openLogin', 'verifyAccount', 'reconnectSync', and 'signIn'.
|
||||
|
@ -220,5 +220,3 @@ deleted on server side. Those were deleted before v4.0.0-beta.4 (during multi-no
|
|||
|
||||
- `ec` - `notes`
|
||||
- `ea` - `delete-deleted-notes`
|
||||
|
||||
|
||||
|
|
|
@ -20,17 +20,20 @@ import { SYNC_AUTHENTICATED,
|
|||
|
||||
import browser from './browser';
|
||||
import { v4 as uuid4 } from 'uuid';
|
||||
import { trackEvent } from './utils/metrics';
|
||||
import sync from './utils/sync';
|
||||
|
||||
export function pleaseLogin() {
|
||||
return { type: PLEASE_LOGIN };
|
||||
}
|
||||
|
||||
export function kintoLoad(from) {
|
||||
export function kintoLoad(origin) {
|
||||
// Return id to callback using promises
|
||||
return (dispatch, getState) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
dispatch({ type: TEXT_SYNCING, from: from });
|
||||
|
||||
dispatch({ type: TEXT_SYNCING, from: origin });
|
||||
|
||||
sync.loadFromKinto(kintoClient, getState().sync.loginDetails).then(result => {
|
||||
if (result && result.data) {
|
||||
dispatch({ type: KINTO_LOADED, notes: result.data });
|
||||
|
@ -55,6 +58,10 @@ export function createNote(note = {}) {
|
|||
return (dispatch, getState) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
trackEvent('new-note', {
|
||||
el: 'list-view'
|
||||
});
|
||||
|
||||
note.id = uuid4();
|
||||
if (!note.lastModified) note.lastModified = new Date();
|
||||
|
||||
|
@ -83,6 +90,7 @@ export function createNote(note = {}) {
|
|||
}
|
||||
|
||||
export function updateNote(id, content, lastModified) {
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: UPDATE_NOTE,
|
||||
id,
|
||||
|
@ -92,7 +100,11 @@ export function updateNote(id, content, lastModified) {
|
|||
return { type: UPDATE_NOTE, id, content, lastModified };
|
||||
}
|
||||
|
||||
export function deleteNote(id) {
|
||||
export function deleteNote(id, origin) {
|
||||
trackEvent('new-note', {
|
||||
el: origin
|
||||
});
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: DELETE_NOTE,
|
||||
id
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import kintoClient from './vendor/kinto-client';
|
||||
import fxaUtils from './vendor/fxa-utils';
|
||||
import { trackEvent } from './utils/metrics';
|
||||
|
||||
import { SYNC_AUTHENTICATED,
|
||||
KINTO_LOADED,
|
||||
|
@ -52,7 +53,7 @@ browser.runtime.onMessage.addListener(eventData => {
|
|||
store.dispatch({ type: ERROR, message: eventData.message });
|
||||
break;
|
||||
case RECONNECT_SYNC:
|
||||
console.log('Implement me (background.js RECONNECT_SYNC message)');
|
||||
trackEvent('reconnect-sync');
|
||||
store.dispatch({ type: ERROR, message: 'Reconnect to Sync' });
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -58,6 +58,7 @@ class DrawerItems extends React.Component {
|
|||
{
|
||||
label : 'Feedback',
|
||||
action : () => {
|
||||
trackEvent('give-feedback');
|
||||
return Linking.openURL(SURVEY_PATH);
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +85,8 @@ class DrawerItems extends React.Component {
|
|||
};
|
||||
|
||||
this._requestSync = () => {
|
||||
|
||||
trackEvent('webext-button-authenticate');
|
||||
props.dispatch(kintoLoad('drawer')).then(_ => {
|
||||
// If load succeed, we close drawer
|
||||
this.props.navigation.dispatch(DrawerActions.closeDrawer());
|
||||
|
|
|
@ -44,7 +44,7 @@ class RichTextExample extends Component {
|
|||
this.props.dispatch(setFocusedNote(note.id));
|
||||
});
|
||||
} else if (this.note && e === '') { // if we delete all caracters from a note
|
||||
this.props.dispatch(deleteNote(this.note.id));
|
||||
this.props.dispatch(deleteNote(this.note.id, 'blank-note'));
|
||||
this.note = null;
|
||||
this.props.dispatch(setFocusedNote());
|
||||
} else if (this.note && e !== '') { // default case, on modification we save
|
||||
|
|
|
@ -11,6 +11,8 @@ import { View, FlatList, StyleSheet, RefreshControl, AppState, Animated } from '
|
|||
import { COLOR_DARK_SYNC, COLOR_NOTES_BLUE, COLOR_NOTES_WHITE, KINTO_LOADED } from '../utils/constants';
|
||||
import { kintoLoad, createNote } from "../actions";
|
||||
import browser from '../browser';
|
||||
import { trackEvent } from '../utils/metrics';
|
||||
|
||||
|
||||
import ListPanelEmpty from './ListPanelEmpty';
|
||||
import ListPanelLoading from './ListPanelLoading';
|
||||
|
@ -40,6 +42,7 @@ class ListPanel extends React.Component {
|
|||
}
|
||||
|
||||
this._onRefresh = () => {
|
||||
trackEvent('webext-button-authenticate');
|
||||
this.setState({ refreshing: true });
|
||||
props.dispatch(kintoLoad()).then(() => {
|
||||
this.setState({ refreshing: false });
|
||||
|
@ -48,9 +51,12 @@ class ListPanel extends React.Component {
|
|||
|
||||
this._handleAppStateChange = (nextAppState) => {
|
||||
if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
|
||||
trackEvent('open');
|
||||
props.dispatch(kintoLoad()).then(() => {
|
||||
this.setState({ refreshing: false });
|
||||
});
|
||||
} else {
|
||||
trackEvent('close', { state: nextAppState });
|
||||
}
|
||||
this.setState({ appState: nextAppState });
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ class MoreMenu extends Component {
|
|||
return note.id === this.props.state.sync.focusedNoteId
|
||||
});
|
||||
if (deletedNote) {
|
||||
this.props.dispatch(deleteNote(deletedNote.id));
|
||||
this.props.dispatch(deleteNote(deletedNote.id, 'in-note'));
|
||||
}
|
||||
navigation.navigate('ListPanel', { deletedNote });
|
||||
break;
|
||||
|
|
|
@ -1,9 +1,52 @@
|
|||
import { GoogleAnalyticsTracker } from "react-native-google-analytics-bridge";
|
||||
import { store } from '../store';
|
||||
|
||||
// See https://github.com/mozilla/notes/blob/master/docs/metrics.md for details
|
||||
const tracker = new GoogleAnalyticsTracker('UA-35433268-79');
|
||||
const EVENT_CATEGORY = 'notes';
|
||||
|
||||
export const trackEvent = (action) => {
|
||||
tracker.trackEvent(EVENT_CATEGORY, action);
|
||||
export const trackEvent = (action, optionalValues = {}) => {
|
||||
|
||||
const state = store.getState();
|
||||
|
||||
if (action === 'changed') {
|
||||
optionalValues.cd1 = state.profile.email !== null;
|
||||
}
|
||||
|
||||
if (action === 'close') {
|
||||
// See about appState : https://facebook.github.io/react-native/docs/appstate.html
|
||||
if (optionalValues.state === 'inactive') {
|
||||
optionalValues.cd7 = 'appInactive';
|
||||
} else if (optionalValues.state === 'background') {
|
||||
optionalValues.cd7 = 'appBackground';
|
||||
}
|
||||
}
|
||||
|
||||
optionalValues.cd9 = optionalValues.cd9 || 'true'; // if panel is loaded
|
||||
// Generate cd10 based on footer.js rules. Same in webext.
|
||||
if (state.sync && ['open', 'close', 'changed', 'drag-n-drop', 'new-note', 'export',
|
||||
'delete-note', 'give-feedback', 'limit-reached'].includes(action)) {
|
||||
if (state.sync.email) { // If user is authenticated
|
||||
if (state.sync.error) {
|
||||
optionalValues.cd10 = 'error';
|
||||
} else if (state.sync.isSyncing) {
|
||||
optionalValues.cd10 = 'isSyncing';
|
||||
} else {
|
||||
optionalValues.cd10 = 'synced';
|
||||
}
|
||||
} else {
|
||||
if (state.sync.isOpeningLogin) { // eslint-disable-line no-lonely-if
|
||||
optionalValues.cd10 = 'openLogin';
|
||||
} else if (state.sync.isPleaseLogin) {
|
||||
optionalValues.cd10 = 'verifyAccount';
|
||||
} else if (state.sync.isReconnectSync) {
|
||||
optionalValues.cd10 = 'reconnectSync';
|
||||
} else {
|
||||
optionalValues.cd10 = 'signIn';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
optionalValues.cd11 = state.notes.length;
|
||||
tracker.trackEvent(EVENT_CATEGORY, action, optionalValues);
|
||||
};
|
||||
|
|
|
@ -3,6 +3,8 @@ import {
|
|||
} from '../actions';
|
||||
import { store } from '../store';
|
||||
import browser from '../browser';
|
||||
import { trackEvent } from './metrics';
|
||||
import striptags from 'striptags';
|
||||
|
||||
const fxaUtils = require('../vendor/fxa-utils');
|
||||
const fxaCryptoRelier = require('../vendor/fxa-crypto-relier');
|
||||
|
@ -272,7 +274,7 @@ function syncKinto(client, loginDetails) {
|
|||
resolution.deleted = true;
|
||||
}
|
||||
client.conflict = true;
|
||||
// sendMetrics('handle-conflict'); // eslint-disable-line no-undef
|
||||
trackEvent('handle-conflict'); // eslint-disable-line no-undef
|
||||
}
|
||||
return collection.resolve(conflict, resolution);
|
||||
}))
|
||||
|
@ -390,6 +392,12 @@ function saveToKinto(client, loginDetails, note) { // eslint-disable-line no-unu
|
|||
action: TEXT_SYNCING
|
||||
});
|
||||
|
||||
trackEvent('changed', {
|
||||
cm1: striptags(note.content).length,
|
||||
cm2: (striptags(note.content.replace(/<\/p>|<\/li>/gi, '\n')).match(/\n/g) || []).length,
|
||||
cm3: null, // Size of change
|
||||
});
|
||||
|
||||
client.conflict = false;
|
||||
syncDebounce = null;
|
||||
return syncKinto(client, loginDetails)
|
||||
|
|
|
@ -27,6 +27,8 @@ import { Toolbar, ToolbarContent, ToolbarAction, Provider as PaperProvider } fro
|
|||
import { COLOR_APP_BAR, COLOR_STATUS_BAR } from './app/utils/constants';
|
||||
import { store, persistor } from './app/store';
|
||||
|
||||
import { trackEvent } from './app/utils/metrics';
|
||||
|
||||
import DrawerItems from './app/components/DrawerItems';
|
||||
import EditorPanel from './app/components/EditorPanel';
|
||||
import EditorPanelHeader from './app/components/EditorPanelHeader';
|
||||
|
@ -137,6 +139,7 @@ class Notes extends React.Component {
|
|||
StatusBar.setBackgroundColor('rgba(249, 249, 250, 0.3)');
|
||||
StatusBar.setTranslucent(true);
|
||||
StatusBar.setBarStyle('dark-content');
|
||||
trackEvent('open');
|
||||
}
|
||||
|
||||
render () {
|
||||
|
|
Загрузка…
Ссылка в новой задаче