Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error collection optin #570

Merged
merged 22 commits into from
Apr 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ A list of all environment variables and their purpose:
|--|--|--|--|
|NODE_ENV|'production', 'development'|||
|LOGGING|'true', 'false'|'true'|Disable logging|
|COSMOS_ANALYTICS|'true', 'false'|'false'|Disable code that should not run in e2e tests, like crash reporting|
|COSMOS_NETWORK|{path to network configuration folder}|'../networks/gaia-1'|Network to connect to|
|COSMOS_HOME|{path to config persistence folder}|'$HOME/voyager[-dev]'||
|COSMOS_NODE|{ip of a certain node}||Node to connect to|
Expand Down
28 changes: 7 additions & 21 deletions app/src/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@ const winURL = DEV
: `file://${__dirname}/index.html`
const LCD_PORT = DEV ? config.lcd_port : config.lcd_port_prod
const NODE = process.env.COSMOS_NODE
const ANALYTICS = process.env.COSMOS_ANALYTICS ? JSON.parse(process.env.COSMOS_ANALYTICS) : (process.env.NODE_ENV === 'production' && config.analytics_networks.indexOf(config.default_network) !== -1)
// set analytics for renderer
process.env.COSMOS_ANALYTICS = ANALYTICS

let SERVER_BINARY = 'gaia' + (WIN ? '.exe' : '')

Expand Down Expand Up @@ -329,6 +326,9 @@ function handleIPC () {
event.sender.send('connected', nodeIP)
}
})
ipcMain.on('error-collection', (event, optin) => {
Raven.uninstall().config(optin ? config.sentry_dsn : '', { captureUnhandledRejections: false }).install()
})
}

// check if LCD is initialized as the configs could be corrupted
Expand Down Expand Up @@ -400,17 +400,9 @@ async function reconnect (seeds) {
return nodeIP
}

function setupAnalytics () {
if (ANALYTICS) {
log('Adding analytics')
}

// only enable sending of error events in production setups and if the network is a testnet
Raven.config(ANALYTICS ? config.sentry_dsn : '', { captureUnhandledRejections: false }).install()
}

async function main () {
setupAnalytics()
// we only enable error collection after users opted in
Raven.config('', { captureUnhandledRejections: false }).install()

let appVersionPath = join(root, 'app_version')
let genesisPath = join(root, 'genesis.json')
Expand Down Expand Up @@ -499,12 +491,7 @@ async function main () {

// pick a random seed node from config.toml
// TODO: user-specified nodes, support switching?
let configText
try {
configText = fs.readFileSync(configPath, 'utf8')
} catch (e) {
throw new Error(`Can't open config.toml: ${e.message}`)
}
let configText = fs.readFileSync(configPath, 'utf8') // checked before if the file exists
let configTOML = toml.parse(configText)
seeds = configTOML.p2p.seeds.split(',').filter(x => x !== '')
if (seeds.length === 0) {
Expand All @@ -530,6 +517,5 @@ module.exports = main()
})
.then(() => ({
shutdown,
processes: { lcdProcess },
analytics: ANALYTICS
processes: { lcdProcess }
}))
24 changes: 21 additions & 3 deletions app/src/renderer/components/common/NiSessionImport.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@
placeholder="Must be exactly 12 words")
form-msg(name='Seed' type='required' v-if='!$v.fields.importSeed.required')

form-group(field-id="error-collection" field-label=' ')
.ni-field-checkbox
.ni-field-checkbox-input
input#sign-up-warning(type="checkbox" v-model="fields.errorCollection")
label.ni-field-checkbox-label(for="error-collection")
| I'd like to opt in for remote error tracking to help improve Voyager.

.ni-session-footer
btn(icon="arrow_forward" icon-pos="right" value="Next" size="lg")
</template>
Expand Down Expand Up @@ -87,15 +94,25 @@ export default {
name: this.fields.importName
})
if (key) {
this.$store.dispatch('setErrorCollection', {
account: this.fields.importName,
optin: this.fields.errorCollection
})
this.$store.commit('setModalSession', false)
this.$store.commit('notify', { title: 'Welcome back!', body: 'Your account has been successfully imported.' })
this.$store.commit('notify', {
title: 'Welcome back!',
body: 'Your account has been successfully imported.'
})
this.$store.dispatch('signIn', {
account: this.fields.importName,
password: this.fields.importPassword
})
}
} catch (err) {
this.$store.commit('notifyError', { title: `Couldn't create account`, body: err.message })
this.$store.commit('notifyError', {
title: `Couldn't create account`,
body: err.message
})
}
}
},
Expand All @@ -107,7 +124,8 @@ export default {
importName: { required, minLength: minLength(5) },
importPassword: { required, minLength: minLength(10) },
importPasswordConfirm: { sameAsPassword: sameAs('importPassword') },
importSeed: { required }
importSeed: { required },
errorCollection: false
}
})
}
Expand Down
43 changes: 33 additions & 10 deletions app/src/renderer/components/common/NiSessionSignUp.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@
label.ni-field-checkbox-label(for="sign-up-backup")
| I have securely written down my seed.
form-msg(name='Backup confirmation' type='required' v-if='!$v.fields.signUpBackup.required')

form-group(field-id="error-collection" field-label=' ')
.ni-field-checkbox
.ni-field-checkbox-input
input#sign-up-warning(type="checkbox" v-model="fields.errorCollection")
label.ni-field-checkbox-label(for="error-collection")
| I'd like to opt in for remote error tracking to help improve Voyager.

.ni-session-footer
btn(icon="arrow_forward" icon-pos="right" value="Next" size="lg" :disabled="creating")
</template>
Expand Down Expand Up @@ -99,33 +107,48 @@ export default {
if (this.$v.$error) return
try {
let key = await this.$store.dispatch('createKey', {
seedPhrase: this.fields.signUpSeed, password: this.fields.signUpPassword, name: this.fields.signUpName
seedPhrase: this.fields.signUpSeed,
password: this.fields.signUpPassword,
name: this.fields.signUpName
})
if (key) {
this.$store.dispatch('setErrorCollection', {
account: this.fields.signUpName,
optin: this.fields.errorCollection
})
this.$store.commit('setModalSession', false)
this.$store.commit('notify', { title: 'Signed Up', body: 'Your account has been created.' })
this.$store.dispatch('signIn', { password: this.fields.signUpPassword, account: this.fields.signUpName })
this.$store.commit('notify', {
title: 'Signed Up',
body: 'Your account has been created.'
})
this.$store.dispatch('signIn', {
password: this.fields.signUpPassword,
account: this.fields.signUpName
})
}
} catch (err) {
this.$store.commit('notifyError', { title: `Couldn't create account`, body: err.message })
this.$store.commit('notifyError', {
title: `Couldn't create account`,
body: err.message
})
}
}
},
mounted () {
this.$el.querySelector('#sign-up-name').focus()
this.$store.dispatch('createSeed')
.then(seedPhrase => {
this.creating = false
this.fields.signUpSeed = seedPhrase
})
this.$store.dispatch('createSeed').then(seedPhrase => {
this.creating = false
this.fields.signUpSeed = seedPhrase
})
},
validations: () => ({
fields: {
signUpName: { required, minLength: minLength(5) },
signUpPassword: { required, minLength: minLength(10) },
signUpPasswordConfirm: { sameAsPassword: sameAs('signUpPassword') },
signUpWarning: { required },
signUpBackup: { required }
signUpBackup: { required },
errorCollection: false
}
})
}
Expand Down
15 changes: 15 additions & 0 deletions app/src/renderer/components/common/PageProfile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ page(title="My Profile")
part(title='My Profile')
list-item(dt="Account Name" :dd="user.account")
list-item(dt="Address" :dd="user.address")
.ni-li
.ni-li-container
.ni-li-dl
.ni-li-dt Automatic error reports
.ni-li-dd
.ni-field-checkbox
.ni-field-checkbox-input
input(type="checkbox" :checked="user.errorCollection || undefined" @change="setErrorCollection")

.ni-session-footer
btn(icon='exit_to_app' type='button' @click.native="signOut" value='Sign Out')
</template>
Expand All @@ -30,6 +39,12 @@ export default {
signOut () {
this.$store.dispatch('signOut')
this.$store.commit('notifySignOut')
},
setErrorCollection () {
this.$store.dispatch('setErrorCollection', {
account: this.user.account,
optin: !this.user.errorCollection
})
}
}
}
Expand Down
14 changes: 3 additions & 11 deletions app/src/renderer/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ import Router from 'vue-router'
import Vuelidate from 'vuelidate'
import shrinkStacktrace from '../helpers/shrink-stacktrace.js'
import Raven from 'raven-js'
import { remote, ipcRenderer } from 'electron'
import enableGoogleAnalytics from './google-analytics.js'

const config = require('../../../config')
import { ipcRenderer } from 'electron'

import App from './App'
import routes from './routes'
Expand All @@ -18,13 +15,8 @@ import Store from './vuex/store'
// exporting this for testing
let store

// setup sentry remote error reporting and google analytics
const analyticsEnabled = JSON.parse(remote.getGlobal('process').env.COSMOS_ANALYTICS)
if (analyticsEnabled) {
console.log('Analytics enabled in browser')
enableGoogleAnalytics(config.google_analytics_uid)
}
Raven.config(analyticsEnabled ? config.sentry_dsn_public : '').install()
// Raven serves automatic error reporting. It is turned off by default
Raven.config('').install()

// handle uncaught errors
window.addEventListener('unhandledrejection', function (event) {
Expand Down
32 changes: 30 additions & 2 deletions app/src/renderer/vuex/modules/user.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import enableGoogleAnalytics from '../../google-analytics.js'
import Raven from 'raven-js'
const { ipcRenderer } = require('electron')
const config = require('../../../../../config')

export default ({ commit, node }) => {
const state = {
const ERROR_COLLECTION_KEY = 'voyager_error_collection'

let state = {
atoms: 0,
signedIn: false,
accounts: [],
password: null,
account: null,
address: null
address: null,
errorCollection: false
}

const mutations = {
Expand Down Expand Up @@ -81,6 +89,7 @@ export default ({ commit, node }) => {

commit('setModalSession', false)
dispatch('initializeWallet', key)
dispatch('loadErrorCollection', account)
},
signOut ({ state, commit, dispatch }) {
state.password = null
Expand All @@ -89,6 +98,25 @@ export default ({ commit, node }) => {

commit('setModalSession', true)
dispatch('showInitialScreen')
},
loadErrorCollection ({ state, dispatch }, account) {
let errorCollection = localStorage.getItem(`${ERROR_COLLECTION_KEY}_${account}`) === 'true'
dispatch('setErrorCollection', { account, optin: errorCollection })
},
setErrorCollection ({ state }, { account, optin }) {
localStorage.setItem(`${ERROR_COLLECTION_KEY}_${account}`, optin)
state.errorCollection = optin

Raven.uninstall().config(optin ? config.sentry_dsn_public : '').install()
if (optin) {
console.log('Analytics enabled in browser')
enableGoogleAnalytics(config.google_analytics_uid)
} else {
console.log('Analytics disabled in browser')
window.analytics = null
}

ipcRenderer.send('error-collection', optin)
}
}

Expand Down
4 changes: 2 additions & 2 deletions archive/components/ToggleBtn.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('TogggleBtn', () => {
store.commit = jest.fn()

beforeEach(() => {
store.commit.mockReset()
store.commit.mockClear()
wrapper = mount(TogggleBtn, {
localVue,
store,
Expand All @@ -31,7 +31,7 @@ describe('TogggleBtn', () => {
})

it('should show an active state if active set', () => {
wrapper.setProps({active: true})
wrapper.setProps({ active: true })
expect(wrapper.classes()).toContain('active')
})
})
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@
"./test/unit/helpers/setup.js",
"./test/unit/helpers/console_error_throw.js",
"./test/unit/helpers/genesis_mock.js",
"./test/unit/helpers/ipc_mock.js",
"jest-localstorage-mock"
]
}
}
}
5 changes: 5 additions & 0 deletions test/unit/helpers/ipc_mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// this mocks the IPC layer
jest.mock('electron', () => ({
ipcRenderer: { send: jest.fn() },
ipcMain: { on: jest.fn() }
}))
Loading