Merge branch 'i328-MultiVault-v1' into i715-AddImportMenu

This commit is contained in:
Dan Finlay 2017-01-17 13:58:54 -08:00
commit 958cbfbde4
19 changed files with 560 additions and 74 deletions

View File

@ -1,5 +1,6 @@
{
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 6,
"ecmaFeatures": {
"experimentalObjectRestSpread": true,

View File

@ -0,0 +1,124 @@
{
"metamask": {
"isInitialized": true,
"isUnlocked": true,
"rpcTarget": "https://rawtestrpc.metamask.io/",
"identities": {
"0xac39b311dceb2a4b2f5d8461c1cdaf756f4f7ae9": {
"address": "0xac39b311dceb2a4b2f5d8461c1cdaf756f4f7ae9",
"name": "Account 1"
},
"0xd7c0cd9e7d2701c710d64fc492c7086679bdf7b4": {
"address": "0xd7c0cd9e7d2701c710d64fc492c7086679bdf7b4",
"name": "Account 2"
},
"0x1acfb961c5a8268eac8e09d6241a26cbeff42241": {
"address": "0x1acfb961c5a8268eac8e09d6241a26cbeff42241",
"name": "Account 3"
},
"0xabc2bca51709b8615147352c62420f547a63a00c": {
"address": "0xabc2bca51709b8615147352c62420f547a63a00c",
"name": "Account 4"
}
},
"unconfTxs": {
"7992944905869041": {
"id": 7992944905869041,
"txParams": {
"from": "0xac39b311dceb2a4b2f5d8461c1cdaf756f4f7ae9",
"value": "0x0",
"data": "0x606060405234610000575b60da806100186000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630dbe671f14603c575b6000565b3460005760466088565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a72305820a99dfa6091771f518dd1ae8d1ee347bae3304dffd98fd24b1b99a8380bc60a750029",
"gas": "0x1af75",
"metamaskId": 7992944905869041,
"metamaskNetworkId": "3"
},
"time": 1482279685589,
"status": "unconfirmed",
"gasMultiplier": 1,
"metamaskNetworkId": "3",
"gasLimitSpecified": true,
"estimatedGas": "0x1af75",
"simulationFails": true
}
},
"currentFiat": "USD",
"conversionRate": 7.69158136,
"conversionDate": 1482279663,
"noActiveNotices": true,
"network": "3",
"accounts": {
"0xac39b311dceb2a4b2f5d8461c1cdaf756f4f7ae9": {
"code": "0x",
"nonce": "0x3",
"balance": "0x11f646fe14c9c000",
"address": "0xac39b311dceb2a4b2f5d8461c1cdaf756f4f7ae9"
},
"0xd7c0cd9e7d2701c710d64fc492c7086679bdf7b4": {
"code": "0x",
"nonce": "0x0",
"balance": "0x0",
"address": "0xd7c0cd9e7d2701c710d64fc492c7086679bdf7b4"
},
"0x1acfb961c5a8268eac8e09d6241a26cbeff42241": {
"code": "0x",
"balance": "0x0",
"nonce": "0x0",
"address": "0x1acfb961c5a8268eac8e09d6241a26cbeff42241"
},
"0xabc2bca51709b8615147352c62420f547a63a00c": {
"code": "0x",
"balance": "0x0",
"nonce": "0x0",
"address": "0xabc2bca51709b8615147352c62420f547a63a00c"
}
},
"transactions": [
{
"id": 7992944905869041,
"txParams": {
"from": "0xac39b311dceb2a4b2f5d8461c1cdaf756f4f7ae9",
"value": "0x0",
"data": "0x606060405234610000575b60da806100186000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630dbe671f14603c575b6000565b3460005760466088565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a72305820a99dfa6091771f518dd1ae8d1ee347bae3304dffd98fd24b1b99a8380bc60a750029",
"gas": "0x1af75",
"metamaskId": 7992944905869041,
"metamaskNetworkId": "3"
},
"time": 1482279685589,
"status": "unconfirmed",
"gasMultiplier": 1,
"metamaskNetworkId": "3",
"gasLimitSpecified": true,
"estimatedGas": "0x1af75",
"simulationFails": true
}
],
"provider": {
"type": "testnet"
},
"selectedAccount": "0xac39b311dceb2a4b2f5d8461c1cdaf756f4f7ae9",
"seedWords": false,
"isDisclaimerConfirmed": true,
"unconfMsgs": {},
"messages": [],
"shapeShiftTxList": [],
"keyringTypes": [
"Simple Key Pair",
"HD Key Tree"
],
"lostAccounts": []
},
"appState": {
"menuOpen": false,
"currentView": {
"name": "confTx",
"context": 0
},
"accountDetail": {
"subview": "transactions"
},
"transForward": true,
"isLoading": false,
"warning": null
},
"identities": {}
}

View File

@ -0,0 +1,66 @@
{
"metamask": {
"isInitialized": true,
"isUnlocked": true,
"rpcTarget": "https://rawtestrpc.metamask.io/",
"identities": {
"0xa6ef573d60594731178b7f85d80da13cc2af52dd": {
"address": "0xa6ef573d60594731178b7f85d80da13cc2af52dd",
"name": "Dan! 1"
},
"0xf9f52e84ad2c9122caa87478d27041ddaa215666": {
"address": "0xf9f52e84ad2c9122caa87478d27041ddaa215666",
"name": "Account 2"
}
},
"unconfTxs": {},
"currentFiat": "USD",
"conversionRate": 10.92067835,
"conversionDate": 1478282884,
"network": null,
"accounts": {
"0xa6ef573d60594731178b7f85d80da13cc2af52dd": {
"balance": "0x00",
"nonce": "0x100000",
"code": "0x",
"address": "0xa6ef573d60594731178b7f85d80da13cc2af52dd"
},
"0xf9f52e84ad2c9122caa87478d27041ddaa215666": {
"balance": "0x00",
"nonce": "0x100000",
"code": "0x",
"address": "0xf9f52e84ad2c9122caa87478d27041ddaa215666"
}
},
"transactions": [],
"provider": {
"type": "testnet"
},
"selectedAccount": "0xa6ef573d60594731178b7f85d80da13cc2af52dd",
"isConfirmed": true,
"unconfMsgs": {},
"messages": [],
"selectedAddress": "0xa6ef573d60594731178b7f85d80da13cc2af52dd",
"shapeShiftTxList": [],
"keyringTypes": [
"Simple Key Pair",
"HD Key Tree"
]
},
"appState": {
"menuOpen": false,
"currentView": {
"name": "new-account"
},
"accountDetail": {
"subview": "transactions"
},
"transForward": true,
"isLoading": false,
"warning": null,
"forgottenPassword": null,
"detailView": {},
"scrollToBottom": false
},
"identities": {}
}

View File

@ -83,6 +83,7 @@
"react-hyperscript": "^2.2.2",
"react-markdown": "^2.3.0",
"react-redux": "^4.4.5",
"react-select": "^1.0.0-rc.2",
"react-tooltip-component": "^0.3.0",
"readable-stream": "^2.1.2",
"redux": "^3.0.5",

79
ui/app/accounts/add.js Normal file
View File

@ -0,0 +1,79 @@
const inherits = require('util').inherits
const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
const actions = require('../actions')
// Components
const TabBar = require('../components/tab-bar')
// Subviews
const NewAccountView = require('./new')
const ImportAccountView = require('./import')
module.exports = connect(mapStateToProps)(AddAccountScreen)
function mapStateToProps (state) {
return {}
}
inherits(AddAccountScreen, Component)
function AddAccountScreen () {
Component.call(this)
}
AddAccountScreen.prototype.render = function () {
return (
h('.flex-column', {
style: {
},
}, [
// title and nav
h('.flex-row.space-between', {
style: {
alignItems: 'center',
padding: '0px 20px',
},
}, [
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
onClick: this.goHome.bind(this),
}),
h('h2.page-subtitle', 'Add Account'),
h('i', { style: { width: '18px' } }),
]),
h(TabBar, {
tabs: [
{ content: 'Create New', key: 'new' },
{ content: 'Import', key: 'import' },
],
defaultTab: 'new',
tabSelected: (key) => {
this.setState({ subview: key })
},
}),
this.renderNewOrImport(),
])
)
}
AddAccountScreen.prototype.goHome = function() {
this.props.dispatch(actions.showAccountsPage())
}
AddAccountScreen.prototype.renderNewOrImport = function() {
const state = this.state || {}
const subview = state.subview || 'new'
switch (subview) {
case 'new':
return h(NewAccountView)
case 'import':
return h(ImportAccountView)
}
}

View File

@ -0,0 +1,82 @@
const inherits = require('util').inherits
const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
import Select from 'react-select'
// Subviews
const JsonImportView = require('./json.js')
const SeedImportView = require('./seed.js')
module.exports = connect(mapStateToProps)(AccountImportSubview)
function mapStateToProps (state) {
return {
types: state.metamask.keyringTypes,
}
}
inherits(AccountImportSubview, Component)
function AccountImportSubview () {
Component.call(this)
}
AccountImportSubview.prototype.render = function () {
const props = this.props
const state = this.state || {}
const { types } = props
const { type } = state
return (
h('div', {
style: {
},
}, [
h('div', {
style: {
padding: '10px',
color: 'rgb(174, 174, 174)',
},
}, [
h('h3', { style: { padding: '3px' } }, 'SELECT TYPE'),
h('style', `
.has-value.Select--single > .Select-control .Select-value .Select-value-label, .Select-value-label {
color: rgb(174,174,174);
}
`),
h(Select, {
name: 'import-type-select',
clearable: false,
value: type || types[0],
options: types.map((type) => {
return {
value: type,
label: type,
}
}),
onChange: (opt) => {
this.setState({ type: opt.value })
},
}),
]),
this.renderImportView(),
])
)
}
AccountImportSubview.prototype.renderImportView = function() {
const props = this.props
const state = this.state || {}
const { type } = state || props.types[0]
switch (type) {
case 'HD Key Tree':
return h(SeedImportView)
default:
return h(JsonImportView)
}
}

View File

@ -0,0 +1,27 @@
const inherits = require('util').inherits
const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
module.exports = connect(mapStateToProps)(JsonImportSubview)
function mapStateToProps (state) {
return {}
}
inherits(JsonImportSubview, Component)
function JsonImportSubview () {
Component.call(this)
}
JsonImportSubview.prototype.render = function () {
return (
h('div', {
style: {
},
}, [
`Upload your json file here!`,
])
)
}

View File

@ -0,0 +1,30 @@
const inherits = require('util').inherits
const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
module.exports = connect(mapStateToProps)(SeedImportSubview)
function mapStateToProps (state) {
return {}
}
inherits(SeedImportSubview, Component)
function SeedImportSubview () {
Component.call(this)
}
SeedImportSubview.prototype.render = function () {
return (
h('div', {
style: {
},
}, [
`Paste your seed phrase here!`,
h('textarea'),
h('br'),
h('button', 'Submit'),
])
)
}

View File

@ -154,6 +154,13 @@ AccountsScreen.prototype.addNewAccount = function () {
this.props.dispatch(actions.addNewAccount(0))
}
/* An optional view proposed in this design:
* https://consensys.quip.com/zZVrAysM5znY
AccountsScreen.prototype.addNewAccount = function () {
this.props.dispatch(actions.navigateToNewAccountScreen())
}
*/
AccountsScreen.prototype.goHome = function () {
this.props.dispatch(actions.goHome())
}

30
ui/app/accounts/new.js Normal file
View File

@ -0,0 +1,30 @@
const inherits = require('util').inherits
const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
module.exports = connect(mapStateToProps)(COMPONENTNAME)
function mapStateToProps (state) {
return {}
}
inherits(COMPONENTNAME, Component)
function COMPONENTNAME () {
Component.call(this)
}
COMPONENTNAME.prototype.render = function () {
const props = this.props
return (
h('div', {
style: {
background: 'red',
},
}, [
`Hello, ${props.sender}`,
])
)
}

View File

@ -44,6 +44,8 @@ var actions = {
createNewVaultInProgress: createNewVaultInProgress,
addNewKeyring,
addNewAccount,
NEW_ACCOUNT_SCREEN: 'NEW_ACCOUNT_SCREEN',
navigateToNewAccountScreen,
showNewVaultSeed: showNewVaultSeed,
showInfoPage: showInfoPage,
// seed recovery actions
@ -254,6 +256,12 @@ function addNewKeyring (type, opts) {
return callBackgroundThenUpdate(background.addNewKeyring, type, opts)
}
function navigateToNewAccountScreen() {
return {
type: this.NEW_ACCOUNT_SCREEN,
}
}
function addNewAccount (ringNumber = 0) {
return callBackgroundThenUpdate(background.addNewAccount, ringNumber)
}

View File

@ -20,7 +20,7 @@ const NoticeScreen = require('./components/notice')
const generateLostAccountsNotice = require('../lib/lost-accounts-notice')
// other views
const ConfigScreen = require('./config')
const Import = require('./import')
const Import = require('./accounts/import')
const InfoScreen = require('./info')
const LoadingIndicator = require('./components/loading')
const SandwichExpando = require('sandwich-expando')
@ -33,6 +33,7 @@ const QrView = require('./components/qr-code')
const HDCreateVaultComplete = require('./keychains/hd/create-vault-complete')
const HDRestoreVaultScreen = require('./keychains/hd/restore-vault')
const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation')
const AddAccountScreen = require('./accounts/add')
module.exports = connect(mapStateToProps)(App)
@ -407,6 +408,9 @@ App.prototype.renderPrimary = function () {
case 'accountDetail':
return h(AccountDetailScreen, {key: 'account-detail'})
case 'new-account':
return h(AddAccountScreen, {key: 'new-account'})
case 'sendTransaction':
return h(SendTransactionScreen, {key: 'send-transaction'})

View File

@ -7,6 +7,7 @@ const CoinbaseForm = require('./coinbase-form')
const ShapeshiftForm = require('./shapeshift-form')
const extension = require('../../../app/scripts/lib/extension')
const Loading = require('./loading')
const TabBar = require('./tab-bar')
module.exports = connect(mapStateToProps)(BuyButtonSubview)
@ -29,7 +30,6 @@ function BuyButtonSubview () {
BuyButtonSubview.prototype.render = function () {
const props = this.props
const currentForm = props.buyView.formView
const isLoading = props.isSubLoading
return (
@ -53,43 +53,53 @@ BuyButtonSubview.prototype.render = function () {
h(Loading, { isLoading }),
h('h3.flex-row.text-transform-uppercase', {
style: {
background: '#EBEBEB',
color: '#AEAEAE',
paddingTop: '4px',
justifyContent: 'space-around',
h(TabBar, {
tabs: [
{
content: [
'Coinbase',
h('a', {
onClick: (event) => this.navigateTo('https://github.com/MetaMask/faq/blob/master/COINBASE.md'),
}, [
h('i.fa.fa-question-circle', {
style: {
margin: '0px 5px',
},
}),
]),
],
key: 'coinbase',
},
{
content: [
'Shapeshift',
h('a', {
href: 'https://github.com/MetaMask/faq/blob/master/COINBASE.md',
onClick: (event) => this.navigateTo('https://info.shapeshift.io/about'),
}, [
h('i.fa.fa-question-circle', {
style: {
margin: '0px 5px',
},
}),
]),
],
key: 'shapeshift',
},
],
defaultTab: 'coinbase',
tabSelected: (key) => {
switch (key) {
case 'coinbase':
props.dispatch(actions.coinBaseSubview())
break
case 'shapeshift':
props.dispatch(actions.shapeShiftSubview(props.provider.type))
break
}
},
}, [
h(currentForm.coinbase ? '.activeForm' : '.inactiveForm.pointer', {
onClick: () => props.dispatch(actions.coinBaseSubview()),
}, 'Coinbase'),
h('a', {
onClick: (event) => this.navigateTo('https://github.com/MetaMask/faq/blob/master/COINBASE.md'),
}, [
h('i.fa.fa-question-circle', {
style: {
position: 'relative',
right: '33px',
},
}),
]),
h(currentForm.shapeshift ? '.activeForm' : '.inactiveForm.pointer', {
onClick: () => props.dispatch(actions.shapeShiftSubview(props.provider.type)),
}, 'Shapeshift'),
}),
h('a', {
href: 'https://github.com/MetaMask/faq/blob/master/COINBASE.md',
onClick: (event) => this.navigateTo('https://info.shapeshift.io/about'),
}, [
h('i.fa.fa-question-circle', {
style: {
position: 'relative',
right: '28px',
},
}),
]),
]),
this.formVersionSubview(),
])
)

View File

@ -0,0 +1,35 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
module.exports = TabBar
inherits(TabBar, Component)
function TabBar () {
Component.call(this)
}
TabBar.prototype.render = function () {
const props = this.props
const state = this.state || {}
const { tabs = [], defaultTab, tabSelected } = props
const { subview = defaultTab } = state
return (
h('.flex-row.space-around.text-transform-uppercase', {
style: {
background: '#EBEBEB',
color: '#AEAEAE',
paddingTop: '4px',
},
}, tabs.map((tab) => {
const { key, content } = tab
return h(subview === key ? '.activeForm' : '.inactiveForm.pointer', {
onClick: () => {
this.setState({ subview: key })
tabSelected(key)
},
}, content)
}))
)
}

View File

@ -23,6 +23,14 @@
flex-direction: column;
}
.space-between {
justify-content: space-between;
}
.space-around {
justify-content: space-around;
}
.flex-column-bottom {
display: flex;
flex-direction: column-reverse;

View File

@ -1,36 +0,0 @@
const inherits = require('util').inherits
const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
module.exports = connect(mapStateToProps)(ImportIndex)
function mapStateToProps (state) {
return {}
}
inherits(ImportIndex, Component)
function ImportIndex () {
Component.call(this)
}
ImportIndex.prototype.render = function () {
const props = this.props
return (
h('.accounts-section.flex-grow', [
// subtitle and nav
h('.section-title.flex-center', [
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
onClick: this.goHome.bind(this),
}),
h('h2.page-subtitle', 'Select Account'),
]),
])
)
}

View File

@ -136,6 +136,15 @@ function reduceApp (state, action) {
isLoading: false,
})
case actions.NEW_ACCOUNT_SCREEN:
return extend(appState, {
currentView: {
name: 'new-account',
context: appState.currentView.context,
},
transForward: true,
})
case actions.SHOW_SEND_PAGE:
return extend(appState, {
currentView: {

View File

@ -26,7 +26,7 @@ UnlockScreen.prototype.render = function () {
const state = this.props
const warning = state.warning
return (
h('.flex-column.hey-im-here', [
h('.flex-column', [
h('.unlock-screen.flex-column.flex-center.flex-grow', [
h(Mascot, {

View File

@ -10,6 +10,7 @@ var cssFiles = {
'index.css': fs.readFileSync(path.join(__dirname, '/app/css/index.css'), 'utf8'),
'transitions.css': fs.readFileSync(path.join(__dirname, '/app/css/transitions.css'), 'utf8'),
'react-tooltip-component.css': fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'react-tooltip-component', 'dist', 'react-tooltip-component.css'), 'utf8'),
'react-css': fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'react-select', 'dist', 'react-select.css'), 'utf8'),
}
function bundleCss () {