This commit is contained in:
Sébastien BARBIER 2018-05-07 17:53:40 +07:00 коммит произвёл Vlad Filippov
Родитель dcd0182352
Коммит 25b93f741a
10 изменённых файлов: 86 добавлений и 12 удалений

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

@ -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 () {