diff options
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | app/scripts/lib/controllers/preferences.js | 38 | ||||
-rw-r--r-- | app/scripts/metamask-controller.js | 1 | ||||
-rw-r--r-- | development/states/first-time.json | 1 | ||||
-rw-r--r-- | test/unit/actions/config_test.js | 28 | ||||
-rw-r--r-- | test/unit/notice-controller-test.js | 2 | ||||
-rw-r--r-- | ui/app/actions.js | 18 | ||||
-rw-r--r-- | ui/app/app.js | 27 | ||||
-rw-r--r-- | ui/app/config.js | 1 | ||||
-rw-r--r-- | ui/app/reducers/metamask.js | 3 |
10 files changed, 105 insertions, 15 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index d07154bdf..a24fc8b57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Current Master +- Add two most recently used custom RPCs to network dropdown menu. - Add personal_sign method support. - Add ability to customize gas and gasPrice on the transaction approval screen. diff --git a/app/scripts/lib/controllers/preferences.js b/app/scripts/lib/controllers/preferences.js index c5e93a5b9..7bd2e5631 100644 --- a/app/scripts/lib/controllers/preferences.js +++ b/app/scripts/lib/controllers/preferences.js @@ -1,10 +1,11 @@ const ObservableStore = require('obs-store') -const normalizeAddress = require('eth-sig-util').normalize +const normalizeAddress = require('../sig-util').normalize +const extend = require('xtend') class PreferencesController { constructor (opts = {}) { - const initState = opts.initState || {} + const initState = extend({ frequentRpcList: [] }, opts.initState) this.store = new ObservableStore(initState) } @@ -12,7 +13,7 @@ class PreferencesController { // PUBLIC METHODS // - setSelectedAddress(_address) { + setSelectedAddress (_address) { return new Promise((resolve, reject) => { const address = normalizeAddress(_address) this.store.updateState({ selectedAddress: address }) @@ -20,14 +21,43 @@ class PreferencesController { }) } - getSelectedAddress(_address) { + getSelectedAddress (_address) { return this.store.getState().selectedAddress } + updateFrequentRpcList (_url) { + return this.addToFrequentRpcList(_url) + .then((rpcList) => { + this.store.updateState({ frequentRpcList: rpcList }) + return rpcList + }) + } + + addToFrequentRpcList (_url) { + let rpcList = this.getFrequentRpcList() + let index = rpcList.findIndex((element) => { return element === _url }) + if (index !== -1) { + rpcList.splice(index, 1) + } + if (_url !== 'http://localhost:8545') { + rpcList.push(_url) + } + if (rpcList.length > 2) { + rpcList.shift() + } + return Promise.resolve(rpcList) + } + + getFrequentRpcList () { + return this.store.getState().frequentRpcList + } + // // PRIVATE METHODS // + + } module.exports = PreferencesController diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index bd01a260d..cbef8924a 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -265,6 +265,7 @@ module.exports = class MetamaskController extends EventEmitter { // PreferencesController setSelectedAddress: nodeify(preferencesController.setSelectedAddress).bind(preferencesController), + updateFrequentRpcList: nodeify(preferencesController.updateFrequentRpcList).bind(preferencesController), // KeyringController setLocked: nodeify(keyringController.setLocked).bind(keyringController), diff --git a/development/states/first-time.json b/development/states/first-time.json index 108af9117..3554ee911 100644 --- a/development/states/first-time.json +++ b/development/states/first-time.json @@ -4,6 +4,7 @@ "isUnlocked": false, "rpcTarget": "https://rawtestrpc.metamask.io/", "identities": {}, + "frequentRpcList": [], "unapprovedTxs": {}, "currentFiat": "USD", "conversionRate": 12.7527416, diff --git a/test/unit/actions/config_test.js b/test/unit/actions/config_test.js index f851e4102..fea0cf0ba 100644 --- a/test/unit/actions/config_test.js +++ b/test/unit/actions/config_test.js @@ -11,6 +11,7 @@ describe ('config view actions', function() { var initialState = { metamask: { rpcTarget: 'foo', + frequentRpcList: [] }, appState: { currentView: { @@ -30,15 +31,36 @@ describe ('config view actions', function() { describe('SET_RPC_TARGET', function() { it('sets the state.metamask.rpcTarget property of the state to the action.value', function() { + const value = { + rpcTarget: 'foo', + frequentRpcList: ['foo'] + } const action = { type: actions.SET_RPC_TARGET, - value: 'bar', + value, } var result = reducers(initialState, action) assert.equal(result.metamask.provider.type, 'rpc') - assert.equal(result.metamask.provider.rpcTarget, action.value) + assert.equal(result.metamask.provider.rpcTarget, value.rpcTarget) + assert.equal(result.metamask.frequentRpcList[0], value.frequentRpcList[0]) + }) + + it('should handle multiple requests to change the rpc gracefully', function() { + const value = { + rpcTarget: 'foo', + frequentRpcList: ['foo'] + } + + const action = { + type: actions.SET_RPC_TARGET, + value, + } + + var result = reducers(initialState, action) + var secondResult = reducers(result, action) + assert.equal(secondResult.metamask.frequentRpcList.length, 1) }) }) -}) +}) diff --git a/test/unit/notice-controller-test.js b/test/unit/notice-controller-test.js index cf00daeba..73fdb2f2e 100644 --- a/test/unit/notice-controller-test.js +++ b/test/unit/notice-controller-test.js @@ -4,7 +4,7 @@ const rp = require('request-promise') const nock = require('nock') const configManagerGen = require('../lib/mock-config-manager') const NoticeController = require('../../app/scripts/notice-controller') -const STORAGE_KEY = 'metamask-persistance-key' +const STORAGE_KEY = 'metamask-persistence-key' describe('notice-controller', function() { var noticeController diff --git a/ui/app/actions.js b/ui/app/actions.js index 7f972fb37..337f05248 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -670,11 +670,19 @@ function markAccountsFound() { // function setRpcTarget (newRpc) { - log.debug(`background.setRpcTarget`) - background.setRpcTarget(newRpc) - return { - type: actions.SET_RPC_TARGET, - value: newRpc, + return (dispatch) => { + if (global.METAMASK_DEBUG) console.log(`background.setRpcTarget`) + background.setRpcTarget(newRpc) + background.updateFrequentRpcList(newRpc, (frequentRpcList) => { + const value = { + rpcTarget: newRpc, + frequentRpcList, + } + dispatch({ + type: actions.SET_RPC_TARGET, + value, + }) + }) } } diff --git a/ui/app/app.js b/ui/app/app.js index 63fab5db8..d8519def7 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -58,6 +58,7 @@ function mapStateToProps (state) { forgottenPassword: state.appState.forgottenPassword, lastUnreadNotice: state.metamask.lastUnreadNotice, lostAccounts: state.metamask.lostAccounts, + frequentRpcList: state.metamask.frequentRpcList || [], } } @@ -211,6 +212,7 @@ App.prototype.renderAppBar = function () { App.prototype.renderNetworkDropdown = function () { const props = this.props + const rpcList = props.frequentRpcList const state = this.state || {} const isOpen = state.isNetworkMenuOpen @@ -256,12 +258,15 @@ App.prototype.renderNetworkDropdown = function () { h(DropMenuItem, { label: 'Localhost 8545', closeMenu: () => this.setState({ isNetworkMenuOpen: false }), - action: () => props.dispatch(actions.setRpcTarget('http://localhost:8545')), + action: () => { + props.dispatch(actions.setRpcTarget('http://localhost:8545')) + }, icon: h('i.fa.fa-question-circle.fa-lg'), activeNetworkRender: props.provider.rpcTarget, }), this.renderCustomOption(props.provider), + this.renderCommonRpc(rpcList, props.provider), props.isUnlocked && h(DropMenuItem, { label: 'Custom RPC', @@ -510,3 +515,23 @@ App.prototype.renderCustomOption = function (provider) { }) } } + +App.prototype.renderCommonRpc = function (rpcList, provider) { + const { rpcTarget } = provider + const props = this.props + + return rpcList.map((rpc) => { + if ((rpc === 'http://localhost:8545') || (rpc === rpcTarget)) { + return null + } else { + return h(DropMenuItem, { + label: rpc, + closeMenu: () => this.setState({ isNetworkMenuOpen: false }), + action: () => props.dispatch(actions.setRpcTarget(rpc)), + icon: h('i.fa.fa-question-circle.fa-lg'), + activeNetworkRender: rpc, + }) + } + }) + +} diff --git a/ui/app/config.js b/ui/app/config.js index 65b1ed712..00a4cba88 100644 --- a/ui/app/config.js +++ b/ui/app/config.js @@ -5,6 +5,7 @@ const connect = require('react-redux').connect const actions = require('./actions') const currencies = require('./conversion.json').rows const validUrl = require('valid-url') + module.exports = connect(mapStateToProps)(ConfigScreen) function mapStateToProps (state) { diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index 3875cf6d1..7bf2969e7 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -55,9 +55,10 @@ function reduceMetamask (state, action) { case actions.SET_RPC_TARGET: return extend(metamaskState, { + frequentRpcList: action.value.frequentRpcList, provider: { type: 'rpc', - rpcTarget: action.value, + rpcTarget: action.value.rpcTarget, }, }) |