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

Move account export into own view #171

Merged
merged 6 commits into from
May 5, 2016
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
## Current Master

- Add support for calls to `eth.sign`.
- Moved account exporting within transitioning subview on the account detail view.
- Added buttons to the account export process.
- Improved visual appearance of account detail transition where button heights would change.

## 1.7.0 2016-04-29

Expand Down
112 changes: 45 additions & 67 deletions ui/app/account-detail.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
const inherits = require('util').inherits
const extend = require('xtend')
const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
const copyToClipboard = require('copy-to-clipboard')
const actions = require('./actions')
const ReactCSSTransitionGroup = require('react-addons-css-transition-group')

const AccountPanel = require('./components/account-panel')
const transactionList = require('./components/transaction-list')
const ExportAccountView = require('./components/account-export')

module.exports = connect(mapStateToProps)(AccountDetailScreen)

Expand Down Expand Up @@ -35,7 +39,11 @@ AccountDetailScreen.prototype.render = function() {

return (

h('.account-detail-section.flex-column.flex-grow', [
h('.account-detail-section.flex-column.flex-grow', {
style: {
width: '330px',
},
}, [

// subtitle and nav
h('.section-title.flex-row.flex-center', [
Expand Down Expand Up @@ -78,12 +86,13 @@ AccountDetailScreen.prototype.render = function() {
}, 'EXPORT'),
]),

transactionList(transactions
.filter(tx => tx.txParams.from === state.address)
.filter(tx => tx.txParams.metamaskNetworkId === state.networkVersion)
.sort((a, b) => b.time - a.time), state.networkVersion),
this.exportedAccount(accountDetail),

h(ReactCSSTransitionGroup, {
transitionName: "main",
transitionEnterTimeout: 300,
transitionLeaveTimeout: 300,
}, [
this.subview(),
]),
// transaction table
/*
h('section.flex-column', [
Expand All @@ -94,72 +103,41 @@ AccountDetailScreen.prototype.render = function() {
)
}

AccountDetailScreen.prototype.subview = function() {
var subview
try {
subview = this.props.accountDetail.subview
} catch (e) {
subview = null
}

switch (subview) {
case 'transactions':
return this.transactionList()
case 'export':
var state = extend({key: 'export'}, this.props)
return h(ExportAccountView, state)
default:
return this.transactionList()
}
}

AccountDetailScreen.prototype.transactionList = function() {
var state = this.props
var transactions = state.transactions

return transactionList(transactions
.filter(tx => tx.txParams.from === state.address)
.filter(tx => tx.txParams.metamaskNetworkId === state.networkVersion)
.sort((a, b) => b.time - a.time), state.networkVersion)
}

AccountDetailScreen.prototype.navigateToAccounts = function(event){
event.stopPropagation()
this.props.dispatch(actions.showAccountsPage())
}

AccountDetailScreen.prototype.exportAccount = function(address) {
this.props.dispatch(actions.exportAccount(address))
}

AccountDetailScreen.prototype.requestAccountExport = function() {
this.props.dispatch(actions.requestExportAccount())
}

AccountDetailScreen.prototype.exportedAccount = function(accountDetail) {
if (!accountDetail) return
var accountExport = accountDetail.accountExport

var notExporting = accountExport === 'none'
var exportRequested = accountExport === 'requested'
var accountExported = accountExport === 'completed'

if (notExporting) return

if (exportRequested) {
var warning = `Exporting your private key is very dangerous,
and you should only do it if you know what you're doing.`
var confirmation = `If you're absolutely sure, type "I understand" below and
hit Enter.`
return h('div', {}, [
h('p.error', warning),
h('p', confirmation),
h('input#exportAccount', {
onKeyPress: this.onExportKeyPress.bind(this),
})
])
}

if (accountExported) {
return h('div.privateKey', {

}, [
h('label', 'Your private key (click to copy):'),
h('p.error.cursor-pointer', {
style: {
textOverflow: 'ellipsis',
overflow: 'hidden',
webkitUserSelect: 'text',
width: '100%',
},
onClick: function(event) {
copyToClipboard(accountDetail.privateKey)
}
}, accountDetail.privateKey),
])
}
}

AccountDetailScreen.prototype.onExportKeyPress = function(event) {
if (event.key !== 'Enter') return
event.preventDefault()

var input = document.getElementById('exportAccount')
if (input.value === 'I understand') {
this.props.dispatch(actions.exportAccount(this.props.address))
} else {
input.value = ''
input.placeholder = 'Please retype "I understand" exactly.'
}
}
1 change: 0 additions & 1 deletion ui/app/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ function tryUnlockMetamask(password) {
return (dispatch) => {
dispatch(this.unlockInProgress())
_accountManager.submitPassword(password, (err, selectedAccount) => {
dispatch(this.hideLoadingIndication())
if (err) {
dispatch(this.unlockFailed())
} else {
Expand Down
3 changes: 2 additions & 1 deletion ui/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ App.prototype.render = function() {
h('.flex-column.flex-grow.full-height', {
style: {
// Windows was showing a vertical scroll bar:
overflowY: 'hidden',
overflow: 'hidden',
}
},
[
Expand All @@ -82,6 +82,7 @@ App.prototype.render = function() {
h('.app-primary.flex-grow' + (transForward ? '.from-right' : '.from-left'), {
style: {
height: '380px',
width: '360px',
}
}, [
h(ReactCSSTransitionGroup, {
Expand Down
87 changes: 87 additions & 0 deletions ui/app/components/account-export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const actions = require('../actions')

module.exports = ExportAccountView


inherits(ExportAccountView, Component)
function ExportAccountView() {
Component.call(this)
}

ExportAccountView.prototype.render = function() {
console.log("EXPORT VIEW")
console.dir(this.props)
var state = this.props
var accountDetail = state.accountDetail

if (!accountDetail) return h('div')
var accountExport = accountDetail.accountExport

var notExporting = accountExport === 'none'
var exportRequested = accountExport === 'requested'
var accountExported = accountExport === 'completed'

if (notExporting) return h('div')

if (exportRequested) {
var warning = `Exporting your private key is very dangerous,
and you should only do it if you know what you're doing.`
var confirmation = `If you're absolutely sure, type "I understand" below and
submit.`
return h('div', { key: 'exporting' }, [
h('p.error', warning),
h('p', confirmation),
h('input#exportAccount', {
onKeyPress: this.onExportKeyPress.bind(this),
}),
h('button', {
onClick: () => this.onExportKeyPress({ key: 'Enter', preventDefault: () => {} }),
}, 'Submit'),
h('button', {
onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address))
}, 'Cancel'),
])
}

if (accountExported) {
return h('div.privateKey', {

}, [
h('label', 'Your private key (click to copy):'),
h('p.error.cursor-pointer', {
style: {
textOverflow: 'ellipsis',
overflow: 'hidden',
webkitUserSelect: 'text',
width: '100%',
},
onClick: function(event) {
copyToClipboard(accountDetail.privateKey)
}
}, accountDetail.privateKey),
h('button', {
onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address))
}, 'Done'),
])
}
}

ExportAccountView.prototype.onExportKeyPress = function(event) {
if (event.key !== 'Enter') return
event.preventDefault()

var input = document.getElementById('exportAccount')
if (input.value === 'I understand') {
this.props.dispatch(actions.exportAccount(this.props.address))
} else {
input.value = ''
input.placeholder = 'Please retype "I understand" exactly.'
}
}

ExportAccountView.prototype.exportAccount = function(address) {
this.props.dispatch(actions.exportAccount(address))
}
2 changes: 1 addition & 1 deletion ui/app/components/transaction-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const addressSummary = require('../util').addressSummary
const explorerLink = require('../../lib/explorer-link')

module.exports = function(transactions, network) {
return h('details', [
return h('details', { key: 'transaction-list' }, [

h('summary', [
h('div.font-small', {style: {display: 'inline'}}, 'Transactions'),
Expand Down
1 change: 1 addition & 0 deletions ui/app/css/transitions.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
position: absolute;
width: 100%;
transition: transform 300ms ease-in-out;
overflow-x: hidden;
}

/* final positions */
Expand Down
19 changes: 19 additions & 0 deletions ui/app/reducers/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ function reduceApp(state, action) {

var appState = extend({
currentView: seedWords ? seedConfView : defaultView,
accountDetail: {
subview: 'transactions',
},
currentDomain: 'example.com',
transForward: true, // Used to render transition direction
isLoading: false, // Used to display loading indicator
Expand Down Expand Up @@ -109,7 +112,9 @@ function reduceApp(state, action) {
case actions.UNLOCK_METAMASK:
return extend(appState, {
currentView: {},
detailView: {},
transForward: true,
isLoading: false,
warning: null,
})

Expand All @@ -131,6 +136,7 @@ function reduceApp(state, action) {
return extend(appState, {
currentView: {},
accountDetail: {
subview: 'transactions',
accountExport: 'none',
privateKey: '',
},
Expand All @@ -144,6 +150,7 @@ function reduceApp(state, action) {
context: action.value || account,
},
accountDetail: {
subview: 'transactions',
accountExport: 'none',
privateKey: '',
},
Expand All @@ -157,6 +164,7 @@ function reduceApp(state, action) {
context: action.value,
},
accountDetail: {
subview: 'transactions',
accountExport: 'none',
privateKey: '',
},
Expand Down Expand Up @@ -218,6 +226,9 @@ function reduceApp(state, action) {
name: 'accountDetail',
context: state.metamask.selectedAddress,
},
accountDetail: {
subview: 'transactions',
},
})
}

Expand Down Expand Up @@ -285,21 +296,29 @@ function reduceApp(state, action) {

case actions.REQUEST_ACCOUNT_EXPORT:
return extend(appState, {
transForward: true,
currentView: {
name: 'accountDetail',
context: appState.currentView.context,
},
accountDetail: {
subview: 'export',
accountExport: 'requested',
},
})

case actions.EXPORT_ACCOUNT:
return extend(appState, {
accountDetail: {
subview: 'export',
accountExport: 'completed',
},
})

case actions.SHOW_PRIVATE_KEY:
return extend(appState, {
accountDetail: {
subview: 'export',
accountExport: 'completed',
privateKey: action.value,
},
Expand Down