From b17a799de6b04e6971eb3a33e7baa76f8236cad9 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 23 Oct 2017 12:10:49 -0700 Subject: Update network.js --- app/scripts/controllers/network.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/network.js b/app/scripts/controllers/network.js index 7f0cbd379..2259efaeb 100644 --- a/app/scripts/controllers/network.js +++ b/app/scripts/controllers/network.js @@ -53,7 +53,7 @@ module.exports = class NetworkController extends EventEmitter { lookupNetwork () { // Prevent firing when provider is not defined. if (!this.ethQuery || !this.ethQuery.sendAsync) { - return + return console.warn('NetworkController - lookupNetwork aborted due to missing ethQuery') } this.ethQuery.sendAsync({ method: 'net_version' }, (err, network) => { if (err) return this.setNetworkState('loading') -- cgit From 5ce94e69b311428d9d2f9b5502c02d3b960e380e Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 31 Oct 2017 09:59:26 -0700 Subject: Add useful error when duplicate web3 is detected. Fixes #2507 --- CHANGELOG.md | 2 ++ app/scripts/inpage.js | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee9548606..968b8ab58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Detect when multiple web3 extensions are active, and provide useful error. + ## 3.12.0 2017-10-25 - Add support for alternative ENS TLDs (Ethereum Name Service Top-Level Domains). diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index b6889b00f..9261e7d64 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -31,6 +31,13 @@ var inpageProvider = new MetamaskInpageProvider(metamaskStream) // setup web3 // +if (typeof window.web3 !== 'undefined') { + throw new Error(`MetaMask detected another web3. + MetaMask will not work reliably with another web3 extension. + This usually happens if you have two MetaMasks installed, + or MetaMask and another web3 extension. Please remove one + and try again.`) +} var web3 = new Web3(inpageProvider) web3.setProvider = function () { log.debug('MetaMask - overrode web3.setProvider') -- cgit From db321d95ccdfa059b42f6a068be50b91cfd8ed2b Mon Sep 17 00:00:00 2001 From: Dan Finlay <542863+danfinlay@users.noreply.github.com> Date: Fri, 17 Nov 2017 11:27:02 -0800 Subject: Point issue template at new support center --- ISSUE_TEMPLATE | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ISSUE_TEMPLATE b/ISSUE_TEMPLATE index d0ff3c08e..b56d08d95 100644 --- a/ISSUE_TEMPLATE +++ b/ISSUE_TEMPLATE @@ -1,7 +1,7 @@ +
+ + + + +
+ +
+ + + diff --git a/old-ui/index.js b/old-ui/index.js new file mode 100644 index 000000000..ae05cbe67 --- /dev/null +++ b/old-ui/index.js @@ -0,0 +1,58 @@ +const render = require('react-dom').render +const h = require('react-hyperscript') +const Root = require('./app/root') +const actions = require('./app/actions') +const configureStore = require('./app/store') +const txHelper = require('./lib/tx-helper') +global.log = require('loglevel') + +module.exports = launchMetamaskUi + + +log.setLevel(global.METAMASK_DEBUG ? 'debug' : 'warn') + +function launchMetamaskUi (opts, cb) { + var accountManager = opts.accountManager + actions._setBackgroundConnection(accountManager) + // check if we are unlocked first + accountManager.getState(function (err, metamaskState) { + if (err) return cb(err) + const store = startApp(metamaskState, accountManager, opts) + cb(null, store) + }) +} + +function startApp (metamaskState, accountManager, opts) { + // parse opts + const store = configureStore({ + + // metamaskState represents the cross-tab state + metamask: metamaskState, + + // appState represents the current tab's popup state + appState: {}, + + // Which blockchain we are using: + networkVersion: opts.networkVersion, + }) + + // if unconfirmed txs, start on txConf page + const unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.unapprovedTypedMessages, metamaskState.network) + if (unapprovedTxsAll.length > 0) { + store.dispatch(actions.showConfTxPage()) + } + + accountManager.on('update', function (metamaskState) { + store.dispatch(actions.updateMetamaskState(metamaskState)) + }) + + // start app + render( + h(Root, { + // inject initial state + store: store, + } + ), opts.container) + + return store +} diff --git a/old-ui/lib/contract-namer.js b/old-ui/lib/contract-namer.js new file mode 100644 index 000000000..f05e770cc --- /dev/null +++ b/old-ui/lib/contract-namer.js @@ -0,0 +1,33 @@ +/* CONTRACT NAMER + * + * Takes an address, + * Returns a nicname if we have one stored, + * otherwise returns null. + */ + +const contractMap = require('eth-contract-metadata') +const ethUtil = require('ethereumjs-util') + +module.exports = function (addr, identities = {}) { + const checksummed = ethUtil.toChecksumAddress(addr) + if (contractMap[checksummed] && contractMap[checksummed].name) { + return contractMap[checksummed].name + } + + const address = addr.toLowerCase() + const ids = hashFromIdentities(identities) + return addrFromHash(address, ids) +} + +function hashFromIdentities (identities) { + const result = {} + for (const key in identities) { + result[key] = identities[key].name + } + return result +} + +function addrFromHash (addr, hash) { + const address = addr.toLowerCase() + return hash[address] || null +} diff --git a/old-ui/lib/etherscan-prefix-for-network.js b/old-ui/lib/etherscan-prefix-for-network.js new file mode 100644 index 000000000..2c1904f1c --- /dev/null +++ b/old-ui/lib/etherscan-prefix-for-network.js @@ -0,0 +1,21 @@ +module.exports = function (network) { + const net = parseInt(network) + let prefix + switch (net) { + case 1: // main net + prefix = '' + break + case 3: // ropsten test net + prefix = 'ropsten.' + break + case 4: // rinkeby test net + prefix = 'rinkeby.' + break + case 42: // kovan test net + prefix = 'kovan.' + break + default: + prefix = '' + } + return prefix +} diff --git a/old-ui/lib/icon-factory.js b/old-ui/lib/icon-factory.js new file mode 100644 index 000000000..27a74de66 --- /dev/null +++ b/old-ui/lib/icon-factory.js @@ -0,0 +1,65 @@ +var iconFactory +const isValidAddress = require('ethereumjs-util').isValidAddress +const toChecksumAddress = require('ethereumjs-util').toChecksumAddress +const contractMap = require('eth-contract-metadata') + +module.exports = function (jazzicon) { + if (!iconFactory) { + iconFactory = new IconFactory(jazzicon) + } + return iconFactory +} + +function IconFactory (jazzicon) { + this.jazzicon = jazzicon + this.cache = {} +} + +IconFactory.prototype.iconForAddress = function (address, diameter) { + const addr = toChecksumAddress(address) + if (iconExistsFor(addr)) { + return imageElFor(addr) + } + + return this.generateIdenticonSvg(address, diameter) +} + +// returns svg dom element +IconFactory.prototype.generateIdenticonSvg = function (address, diameter) { + var cacheId = `${address}:${diameter}` + // check cache, lazily generate and populate cache + var identicon = this.cache[cacheId] || (this.cache[cacheId] = this.generateNewIdenticon(address, diameter)) + // create a clean copy so you can modify it + var cleanCopy = identicon.cloneNode(true) + return cleanCopy +} + +// creates a new identicon +IconFactory.prototype.generateNewIdenticon = function (address, diameter) { + var numericRepresentation = jsNumberForAddress(address) + var identicon = this.jazzicon(diameter, numericRepresentation) + return identicon +} + +// util + +function iconExistsFor (address) { + return contractMap[address] && isValidAddress(address) && contractMap[address].logo +} + +function imageElFor (address) { + const contract = contractMap[address] + const fileName = contract.logo + const path = `images/contract/${fileName}` + const img = document.createElement('img') + img.src = path + img.style.width = '75%' + return img +} + +function jsNumberForAddress (address) { + var addr = address.slice(2, 10) + var seed = parseInt(addr, 16) + return seed +} + diff --git a/old-ui/lib/lost-accounts-notice.js b/old-ui/lib/lost-accounts-notice.js new file mode 100644 index 000000000..948b13db6 --- /dev/null +++ b/old-ui/lib/lost-accounts-notice.js @@ -0,0 +1,23 @@ +const summary = require('../app/util').addressSummary + +module.exports = function (lostAccounts) { + return { + date: new Date().toDateString(), + title: 'Account Problem Caught', + body: `MetaMask has fixed a bug where some accounts were previously mis-generated. This was a rare issue, but you were affected! + +We have successfully imported the accounts that were mis-generated, but they will no longer be recovered with your normal seed phrase. + +We have marked the affected accounts as "Loose", and recommend you transfer ether and tokens away from those accounts, or export & back them up elsewhere. + +Your affected accounts are: +${lostAccounts.map(acct => ` - ${summary(acct)}`).join('\n')} + +These accounts have been marked as "Loose" so they will be easy to recognize in the account list. + +For more information, please read [our blog post.][1] + +[1]: https://medium.com/metamask/metamask-3-migration-guide-914b79533cdd#.7d8ktj4h3 + `, + } +} diff --git a/old-ui/lib/persistent-form.js b/old-ui/lib/persistent-form.js new file mode 100644 index 000000000..d4dc20b03 --- /dev/null +++ b/old-ui/lib/persistent-form.js @@ -0,0 +1,61 @@ +const inherits = require('util').inherits +const Component = require('react').Component +const defaultKey = 'persistent-form-default' +const eventName = 'keyup' + +module.exports = PersistentForm + +function PersistentForm () { + Component.call(this) +} + +inherits(PersistentForm, Component) + +PersistentForm.prototype.componentDidMount = function () { + const fields = document.querySelectorAll('[data-persistent-formid]') + const store = this.getPersistentStore() + + for (var i = 0; i < fields.length; i++) { + const field = fields[i] + const key = field.getAttribute('data-persistent-formid') + const cached = store[key] + if (cached !== undefined) { + field.value = cached + } + + field.addEventListener(eventName, this.persistentFieldDidUpdate.bind(this)) + } +} + +PersistentForm.prototype.getPersistentStore = function () { + let store = window.localStorage[this.persistentFormParentId || defaultKey] + if (store && store !== 'null') { + store = JSON.parse(store) + } else { + store = {} + } + return store +} + +PersistentForm.prototype.setPersistentStore = function (newStore) { + window.localStorage[this.persistentFormParentId || defaultKey] = JSON.stringify(newStore) +} + +PersistentForm.prototype.persistentFieldDidUpdate = function (event) { + const field = event.target + const store = this.getPersistentStore() + const key = field.getAttribute('data-persistent-formid') + const val = field.value + store[key] = val + this.setPersistentStore(store) +} + +PersistentForm.prototype.componentWillUnmount = function () { + const fields = document.querySelectorAll('[data-persistent-formid]') + for (var i = 0; i < fields.length; i++) { + const field = fields[i] + field.removeEventListener(eventName, this.persistentFieldDidUpdate.bind(this)) + } + this.setPersistentStore({}) +} + diff --git a/old-ui/lib/tx-helper.js b/old-ui/lib/tx-helper.js new file mode 100644 index 000000000..de3f00d2d --- /dev/null +++ b/old-ui/lib/tx-helper.js @@ -0,0 +1,27 @@ +const valuesFor = require('../app/util').valuesFor + +module.exports = function (unapprovedTxs, unapprovedMsgs, personalMsgs, typedMessages, network) { + log.debug('tx-helper called with params:') + log.debug({ unapprovedTxs, unapprovedMsgs, personalMsgs, typedMessages, network }) + + const txValues = network ? valuesFor(unapprovedTxs).filter(txMeta => txMeta.metamaskNetworkId === network) : valuesFor(unapprovedTxs) + log.debug(`tx helper found ${txValues.length} unapproved txs`) + + const msgValues = valuesFor(unapprovedMsgs) + log.debug(`tx helper found ${msgValues.length} unsigned messages`) + let allValues = txValues.concat(msgValues) + + const personalValues = valuesFor(personalMsgs) + log.debug(`tx helper found ${personalValues.length} unsigned personal messages`) + allValues = allValues.concat(personalValues) + + const typedValues = valuesFor(typedMessages) + log.debug(`tx helper found ${typedValues.length} unsigned typed messages`) + allValues = allValues.concat(typedValues) + + allValues = allValues.sort((a, b) => { + return a.time > b.time + }) + + return allValues +} -- cgit From 7f795240706c013dc4a9ece0e9c9e33897c7fc71 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 14 Nov 2017 12:34:55 -0330 Subject: Add UI selection --- app/scripts/controllers/preferences.js | 17 ++++++++++ app/scripts/metamask-controller.js | 1 + app/scripts/popup.js | 1 + old-ui/app/app.js | 45 ++++++++++++------------- ui/app/actions.js | 29 ++++++++++++++++ ui/app/app.js | 60 +++++++++++++++++++--------------- ui/app/css/index.scss | 1 + ui/app/css/itcss/components/menu.scss | 2 +- ui/app/reducers/metamask.js | 6 ++++ ui/app/root.js | 4 +-- ui/app/select-app.js | 21 ++++++++++++ 11 files changed, 136 insertions(+), 51 deletions(-) create mode 100644 ui/app/select-app.js diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 0aed4dbdf..0dd9eae1b 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -10,6 +10,7 @@ class PreferencesController { currentAccountTab: 'history', tokens: [], useBlockie: false, + featureFlags: {}, }, opts.initState) this.store = new ObservableStore(initState) } @@ -100,6 +101,22 @@ class PreferencesController { getFrequentRpcList () { return this.store.getState().frequentRpcList } + + setFeatureFlag (feature, activated) { + const currentFeatureFlags = this.store.getState().featureFlags + const updatedFeatureFlags = { + ...currentFeatureFlags, + [feature]: activated, + } + + this.store.updateState({ featureFlags: updatedFeatureFlags }) + console.log(`!!! updatedFeatureFlags`, updatedFeatureFlags); + return Promise.resolve(updatedFeatureFlags) + } + + getFeatureFlags () { + return this.store.getState().featureFlags + } // // PRIVATE METHODS // diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 4dce89e3a..8966ba393 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -341,6 +341,7 @@ module.exports = class MetamaskController extends EventEmitter { addToken: nodeify(preferencesController.addToken, preferencesController), removeToken: nodeify(preferencesController.removeToken, preferencesController), setCurrentAccountTab: nodeify(preferencesController.setCurrentAccountTab, preferencesController), + setFeatureFlag: nodeify(preferencesController.setFeatureFlag, preferencesController), // AddressController setAddressBook: nodeify(addressBookController.setAddressBook, addressBookController), diff --git a/app/scripts/popup.js b/app/scripts/popup.js index 5f17f0651..8cef06931 100644 --- a/app/scripts/popup.js +++ b/app/scripts/popup.js @@ -12,6 +12,7 @@ const notificationManager = new NotificationManager() global.platform = new ExtensionPlatform() // inject css +console.log(`MetaMaskUiCss`, MetaMaskUiCss); const css = MetaMaskUiCss() injectCss(css) diff --git a/old-ui/app/app.js b/old-ui/app/app.js index e3f72793c..dcf19a0a9 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -93,31 +93,32 @@ App.prototype.render = function () { log.debug('Main ui render function') return ( - - h('.flex-column.full-height', { - style: { - // Windows was showing a vertical scroll bar: - overflow: 'hidden', - position: 'relative', - alignItems: 'center', - }, - }, [ - - // app bar - this.renderAppBar(), - this.renderNetworkDropdown(), - this.renderDropdown(), - - this.renderLoadingIndicator({ isLoading, isLoadingNetwork, loadMessage }), - - // panel content - h('.app-primary' + (transForward ? '.from-right' : '.from-left'), { + h('.old-ui', [ + h('.flex-column.full-height', { style: { - width: '100%', + // Windows was showing a vertical scroll bar: + overflow: 'hidden', + position: 'relative', + alignItems: 'center', }, }, [ - this.renderPrimary(), - ]), + + // app bar + this.renderAppBar(), + this.renderNetworkDropdown(), + this.renderDropdown(), + + this.renderLoadingIndicator({ isLoading, isLoadingNetwork, loadMessage }), + + // panel content + h('.app-primary' + (transForward ? '.from-right' : '.from-left'), { + style: { + width: '100%', + }, + }, [ + this.renderPrimary(), + ]), + ]) ]) ) } diff --git a/ui/app/actions.js b/ui/app/actions.js index e79f4373e..745b8779e 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -237,6 +237,11 @@ var actions = { SET_USE_BLOCKIE: 'SET_USE_BLOCKIE', setUseBlockie, + + // Feature Flags + setFeatureFlag, + updateFeatureFlags, + UPDATE_FEATURE_FLAGS: 'UPDATE_FEATURE_FLAGS', } module.exports = actions @@ -1506,6 +1511,30 @@ function updateTokenExchangeRate (token = '') { } } +function setFeatureFlag (feature, activated) { + return (dispatch) => { + dispatch(actions.showLoadingIndication()) + return new Promise((resolve, reject) => { + background.setFeatureFlag(feature, activated, (err, updatedFeatureFlags) => { + dispatch(actions.hideLoadingIndication()) + if (err) { + dispatch(actions.displayWarning(err.message)) + reject(err) + } + dispatch(actions.updateFeatureFlags(updatedFeatureFlags)) + resolve(updatedFeatureFlags) + }) + }) + } +} + +function updateFeatureFlags (updatedFeatureFlags) { + return { + type: actions.UPDATE_FEATURE_FLAGS, + value: updatedFeatureFlags, + } +} + // Call Background Then Update // // A function generator for a common pattern wherein: diff --git a/ui/app/app.js b/ui/app/app.js index e90c3e98e..7e1eb200f 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -116,40 +116,41 @@ App.prototype.render = function () { log.debug('Main ui render function') return ( + h('.new-ui', [ + h('.flex-column.full-height', { + style: { + overflowX: 'hidden', + position: 'relative', + alignItems: 'center', + }, + }, [ - h('.flex-column.full-height', { - style: { - overflowX: 'hidden', - position: 'relative', - alignItems: 'center', - }, - }, [ - - // global modal - h(Modal, {}, []), + // global modal + h(Modal, {}, []), - // app bar - this.renderAppBar(), + // app bar + this.renderAppBar(), - // sidebar - this.renderSidebar(), + // sidebar + this.renderSidebar(), - // network dropdown - h(NetworkDropdown, { - provider: this.props.provider, - frequentRpcList: this.props.frequentRpcList, - }, []), + // network dropdown + h(NetworkDropdown, { + provider: this.props.provider, + frequentRpcList: this.props.frequentRpcList, + }, []), - h(AccountMenu), + h(AccountMenu), - (isLoading || isLoadingNetwork) && h(Loading, { - loadingMessage: loadMessage, - }), + (isLoading || isLoadingNetwork) && h(Loading, { + loadingMessage: loadMessage, + }), - // this.renderLoadingIndicator({ isLoading, isLoadingNetwork, loadMessage }), + // this.renderLoadingIndicator({ isLoading, isLoadingNetwork, loadMessage }), - // content - this.renderPrimary(), + // content + this.renderPrimary(), + ]) ]) ) } @@ -268,6 +269,13 @@ App.prototype.renderAppBar = function () { }, }, 'MetaMask'), + h('span', { + style: {}, + onClick: () => { + props.dispatch(actions.setFeatureFlag('betaUI', false)) + }, + }, 'Leave Beta') + ]), h('div.header__right-actions', [ diff --git a/ui/app/css/index.scss b/ui/app/css/index.scss index 01899ccad..445c819ff 100644 --- a/ui/app/css/index.scss +++ b/ui/app/css/index.scss @@ -4,6 +4,7 @@ http://www.creativebloq.com/web-design/manage-large-css-projects-itcss-101517528 https://www.xfive.co/blog/itcss-scalable-maintainable-css-architecture/ */ + @import './itcss/settings/index.scss'; @import './itcss/tools/index.scss'; @import './itcss/generic/index.scss'; diff --git a/ui/app/css/itcss/components/menu.scss b/ui/app/css/itcss/components/menu.scss index 17e24de98..77c49bbcf 100644 --- a/ui/app/css/itcss/components/menu.scss +++ b/ui/app/css/itcss/components/menu.scss @@ -11,7 +11,7 @@ flex-flow: row nowrap; align-items: center; position: relative; - z-index: 200; + z-index: 201; font-weight: 200; @media screen and (max-width: 575px) { diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index fb53bbaef..6d6068d05 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -37,6 +37,7 @@ function reduceMetamask (state, action) { }, coinOptions: {}, useBlockie: false, + featureFlags: {}, }, state.metamask) switch (action.type) { @@ -320,6 +321,11 @@ function reduceMetamask (state, action) { useBlockie: action.value, }) + case actions.UPDATE_FEATURE_FLAGS: + return extend(metamaskState, { + featureFlags: action.value, + }) + default: return metamaskState diff --git a/ui/app/root.js b/ui/app/root.js index 9e7314b20..21d6d1829 100644 --- a/ui/app/root.js +++ b/ui/app/root.js @@ -2,7 +2,7 @@ const inherits = require('util').inherits const Component = require('react').Component const Provider = require('react-redux').Provider const h = require('react-hyperscript') -const App = require('./app') +const SelectedApp = require('./select-app') module.exports = Root @@ -15,7 +15,7 @@ Root.prototype.render = function () { h(Provider, { store: this.props.store, }, [ - h(App), + h(SelectedApp), ]) ) diff --git a/ui/app/select-app.js b/ui/app/select-app.js new file mode 100644 index 000000000..3cba44052 --- /dev/null +++ b/ui/app/select-app.js @@ -0,0 +1,21 @@ +const inherits = require('util').inherits +const Component = require('react').Component +const connect = require('react-redux').connect +const h = require('react-hyperscript') +const App = require('./app') +const OldApp = require('../../old-ui/app/app') + +function mapStateToProps (state) { + return { betaUI: state.metamask.featureFlags.betaUI } +} + +module.exports = connect(mapStateToProps)(SelectedApp) + +inherits(SelectedApp, Component) +function SelectedApp () { Component.call(this) } + +SelectedApp.prototype.render = function () { + const { betaUI } = this.props + const Selected = betaUI ? App : OldApp + return h(Selected) +} -- cgit From f7ad015f5bd3b037b73d7792d0a09d7e0382a511 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 15 Nov 2017 14:05:18 -0330 Subject: Use newui actions in old-ui --- old-ui/app/account-detail.js | 2 +- old-ui/app/accounts/import/index.js | 2 +- old-ui/app/accounts/import/json.js | 2 +- old-ui/app/accounts/import/private-key.js | 2 +- old-ui/app/add-token.js | 2 +- old-ui/app/app.js | 3 ++- old-ui/app/components/account-dropdowns.js | 2 +- old-ui/app/components/account-export.js | 2 +- old-ui/app/components/buy-button-subview.js | 3 ++- old-ui/app/components/coinbase-form.js | 2 +- old-ui/app/components/pending-tx.js | 2 +- old-ui/app/components/qr-code.js | 1 + old-ui/app/components/shapeshift-form.js | 2 +- old-ui/app/components/shift-list-item.js | 2 +- old-ui/app/conf-tx.js | 2 +- old-ui/app/config.js | 2 +- old-ui/app/first-time/init-menu.js | 2 +- old-ui/app/info.js | 2 +- old-ui/app/keychains/hd/create-vault-complete.js | 2 +- old-ui/app/keychains/hd/recover-seed/confirmation.js | 2 +- old-ui/app/keychains/hd/restore-vault.js | 2 +- old-ui/app/reducers/app.js | 2 +- old-ui/app/reducers/metamask.js | 2 +- old-ui/app/send.js | 2 +- old-ui/app/settings.js | 2 +- old-ui/app/unlock.js | 2 +- 26 files changed, 28 insertions(+), 25 deletions(-) diff --git a/old-ui/app/account-detail.js b/old-ui/app/account-detail.js index d4f707e0b..933f6d6a4 100644 --- a/old-ui/app/account-detail.js +++ b/old-ui/app/account-detail.js @@ -3,7 +3,7 @@ const extend = require('xtend') const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect -const actions = require('./actions') +const actions = require('../../ui/app/actions') const valuesFor = require('./util').valuesFor const Identicon = require('./components/identicon') const EthBalance = require('./components/eth-balance') diff --git a/old-ui/app/accounts/import/index.js b/old-ui/app/accounts/import/index.js index 46260c3e7..3502efe93 100644 --- a/old-ui/app/accounts/import/index.js +++ b/old-ui/app/accounts/import/index.js @@ -2,7 +2,7 @@ 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') +const actions = require('../../../../ui/app/actions') import Select from 'react-select' // Subviews diff --git a/old-ui/app/accounts/import/json.js b/old-ui/app/accounts/import/json.js index 158a3c923..8d6bd7f7b 100644 --- a/old-ui/app/accounts/import/json.js +++ b/old-ui/app/accounts/import/json.js @@ -2,7 +2,7 @@ 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') +const actions = require('../../../../ui/app/actions') const FileInput = require('react-simple-file-input').default const HELP_LINK = 'https://github.com/MetaMask/faq/blob/master/README.md#q-i-cant-use-the-import-feature-for-uploading-a-json-file-the-window-keeps-closing-when-i-try-to-select-a-file' diff --git a/old-ui/app/accounts/import/private-key.js b/old-ui/app/accounts/import/private-key.js index 68ccee58e..105191105 100644 --- a/old-ui/app/accounts/import/private-key.js +++ b/old-ui/app/accounts/import/private-key.js @@ -2,7 +2,7 @@ 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') +const actions = require('../../../../ui/app/actions') module.exports = connect(mapStateToProps)(PrivateKeyImportView) diff --git a/old-ui/app/add-token.js b/old-ui/app/add-token.js index 9354a4cad..8778f312e 100644 --- a/old-ui/app/add-token.js +++ b/old-ui/app/add-token.js @@ -2,7 +2,7 @@ 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') +const actions = require('../../ui/app/actions') const Tooltip = require('./components/tooltip.js') diff --git a/old-ui/app/app.js b/old-ui/app/app.js index dcf19a0a9..b1a9d68ba 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -2,7 +2,7 @@ const inherits = require('util').inherits const Component = require('react').Component const connect = require('react-redux').connect const h = require('react-hyperscript') -const actions = require('./actions') +const actions = require('../../ui/app/actions') // mascara const MascaraFirstTime = require('../../mascara/src/app/first-time').default const MascaraBuyEtherScreen = require('../../mascara/src/app/first-time/buy-ether-screen').default @@ -556,6 +556,7 @@ App.prototype.renderPrimary = function () { case 'qr': log.debug('rendering show qr screen') + console.log(`QrView`, QrView); return h('div', { style: { position: 'absolute', diff --git a/old-ui/app/components/account-dropdowns.js b/old-ui/app/components/account-dropdowns.js index 0c34a5154..c0ebe3c60 100644 --- a/old-ui/app/components/account-dropdowns.js +++ b/old-ui/app/components/account-dropdowns.js @@ -1,7 +1,7 @@ const Component = require('react').Component const PropTypes = require('react').PropTypes const h = require('react-hyperscript') -const actions = require('../actions') +const actions = require('../../../ui/app/actions') const genAccountLink = require('etherscan-link').createAccountLink const connect = require('react-redux').connect const Dropdown = require('./dropdown').Dropdown diff --git a/old-ui/app/components/account-export.js b/old-ui/app/components/account-export.js index 32b103c86..51b85b786 100644 --- a/old-ui/app/components/account-export.js +++ b/old-ui/app/components/account-export.js @@ -3,7 +3,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const exportAsFile = require('../util').exportAsFile const copyToClipboard = require('copy-to-clipboard') -const actions = require('../actions') +const actions = require('../../../ui/app/actions') const ethUtil = require('ethereumjs-util') const connect = require('react-redux').connect diff --git a/old-ui/app/components/buy-button-subview.js b/old-ui/app/components/buy-button-subview.js index 15281171c..843627c33 100644 --- a/old-ui/app/components/buy-button-subview.js +++ b/old-ui/app/components/buy-button-subview.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect -const actions = require('../actions') +const actions = require('../../../ui/app/actions') const CoinbaseForm = require('./coinbase-form') const ShapeshiftForm = require('./shapeshift-form') const Loading = require('./loading') @@ -247,6 +247,7 @@ BuyButtonSubview.prototype.backButtonContext = function () { if (this.props.context === 'confTx') { this.props.dispatch(actions.showConfTxPage(false)) } else { + console.log(`actions.goHome`, actions.goHome); this.props.dispatch(actions.goHome()) } } diff --git a/old-ui/app/components/coinbase-form.js b/old-ui/app/components/coinbase-form.js index f44d86045..35b2111ff 100644 --- a/old-ui/app/components/coinbase-form.js +++ b/old-ui/app/components/coinbase-form.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect -const actions = require('../actions') +const actions = require('../../../ui/app/actions') module.exports = connect(mapStateToProps)(CoinbaseForm) diff --git a/old-ui/app/components/pending-tx.js b/old-ui/app/components/pending-tx.js index 5b1b367c6..366121ce0 100644 --- a/old-ui/app/components/pending-tx.js +++ b/old-ui/app/components/pending-tx.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const actions = require('../actions') +const actions = require('../../../ui/app/actions') const clone = require('clone') const ethUtil = require('ethereumjs-util') diff --git a/old-ui/app/components/qr-code.js b/old-ui/app/components/qr-code.js index 06b9aed9b..fa38dcd92 100644 --- a/old-ui/app/components/qr-code.js +++ b/old-ui/app/components/qr-code.js @@ -25,6 +25,7 @@ function QrCodeView () { QrCodeView.prototype.render = function () { const props = this.props const Qr = props.Qr + console.log(`QrCodeView Qr`, Qr); const address = `${isHexPrefixed(Qr.data) ? 'ethereum:' : ''}${Qr.data}` const qrImage = qrCode(4, 'M') qrImage.addData(address) diff --git a/old-ui/app/components/shapeshift-form.js b/old-ui/app/components/shapeshift-form.js index c5993e3d3..a54987c04 100644 --- a/old-ui/app/components/shapeshift-form.js +++ b/old-ui/app/components/shapeshift-form.js @@ -2,7 +2,7 @@ const PersistentForm = require('../../lib/persistent-form') const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect -const actions = require('../actions') +const actions = require('../../../ui/app/actions') const Qr = require('./qr-code') const isValidAddress = require('../util').isValidAddress module.exports = connect(mapStateToProps)(ShapeshiftForm) diff --git a/old-ui/app/components/shift-list-item.js b/old-ui/app/components/shift-list-item.js index b555dee84..5454a90bc 100644 --- a/old-ui/app/components/shift-list-item.js +++ b/old-ui/app/components/shift-list-item.js @@ -4,7 +4,7 @@ const h = require('react-hyperscript') const connect = require('react-redux').connect const vreme = new (require('vreme'))() const explorerLink = require('etherscan-link').createExplorerLink -const actions = require('../actions') +const actions = require('../../../ui/app/actions') const addressSummary = require('../util').addressSummary const CopyButton = require('./copyButton') diff --git a/old-ui/app/conf-tx.js b/old-ui/app/conf-tx.js index cb1afedfe..15c937b1c 100644 --- a/old-ui/app/conf-tx.js +++ b/old-ui/app/conf-tx.js @@ -2,7 +2,7 @@ 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') +const actions = require('../../ui/app/actions') const NetworkIndicator = require('./components/network') const txHelper = require('../lib/tx-helper') const isPopupOrNotification = require('../../app/scripts/lib/is-popup-or-notification') diff --git a/old-ui/app/config.js b/old-ui/app/config.js index c14fa1d28..c698417ba 100644 --- a/old-ui/app/config.js +++ b/old-ui/app/config.js @@ -2,7 +2,7 @@ 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') +const actions = require('../../ui/app/actions') const infuraCurrencies = require('./infura-conversion.json').objects.sort((a, b) => { return a.quote.name.toLocaleLowerCase().localeCompare(b.quote.name.toLocaleLowerCase()) }) diff --git a/old-ui/app/first-time/init-menu.js b/old-ui/app/first-time/init-menu.js index cc7c51bd3..4f1d5d186 100644 --- a/old-ui/app/first-time/init-menu.js +++ b/old-ui/app/first-time/init-menu.js @@ -4,7 +4,7 @@ const Component = require('react').Component const connect = require('react-redux').connect const h = require('react-hyperscript') const Mascot = require('../components/mascot') -const actions = require('../actions') +const actions = require('../../../ui/app/actions') const Tooltip = require('../components/tooltip') const getCaretCoordinates = require('textarea-caret') diff --git a/old-ui/app/info.js b/old-ui/app/info.js index 24c211c1f..db9f30f23 100644 --- a/old-ui/app/info.js +++ b/old-ui/app/info.js @@ -2,7 +2,7 @@ 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') +const actions = require('../../ui/app/actions') module.exports = connect(mapStateToProps)(InfoScreen) diff --git a/old-ui/app/keychains/hd/create-vault-complete.js b/old-ui/app/keychains/hd/create-vault-complete.js index 5ab5d4c33..736e922b7 100644 --- a/old-ui/app/keychains/hd/create-vault-complete.js +++ b/old-ui/app/keychains/hd/create-vault-complete.js @@ -2,7 +2,7 @@ const inherits = require('util').inherits const Component = require('react').Component const connect = require('react-redux').connect const h = require('react-hyperscript') -const actions = require('../../actions') +const actions = require('../../../../ui/app/actions') const exportAsFile = require('../../util').exportAsFile module.exports = connect(mapStateToProps)(CreateVaultCompleteScreen) diff --git a/old-ui/app/keychains/hd/recover-seed/confirmation.js b/old-ui/app/keychains/hd/recover-seed/confirmation.js index 4335186a5..eb0298a09 100644 --- a/old-ui/app/keychains/hd/recover-seed/confirmation.js +++ b/old-ui/app/keychains/hd/recover-seed/confirmation.js @@ -3,7 +3,7 @@ const inherits = require('util').inherits const Component = require('react').Component const connect = require('react-redux').connect const h = require('react-hyperscript') -const actions = require('../../../actions') +const actions = require('../../../../../ui/app/actions') module.exports = connect(mapStateToProps)(RevealSeedConfirmation) diff --git a/old-ui/app/keychains/hd/restore-vault.js b/old-ui/app/keychains/hd/restore-vault.js index 06e51d9b3..222172dfd 100644 --- a/old-ui/app/keychains/hd/restore-vault.js +++ b/old-ui/app/keychains/hd/restore-vault.js @@ -2,7 +2,7 @@ const inherits = require('util').inherits const PersistentForm = require('../../../lib/persistent-form') const connect = require('react-redux').connect const h = require('react-hyperscript') -const actions = require('../../actions') +const actions = require('../../../../ui/app/actions') module.exports = connect(mapStateToProps)(RestoreVaultScreen) diff --git a/old-ui/app/reducers/app.js b/old-ui/app/reducers/app.js index 8558d6dca..0d7419f9a 100644 --- a/old-ui/app/reducers/app.js +++ b/old-ui/app/reducers/app.js @@ -1,5 +1,5 @@ const extend = require('xtend') -const actions = require('../actions') +const actions = require('../../../ui/app/actions') const txHelper = require('../../lib/tx-helper') module.exports = reduceApp diff --git a/old-ui/app/reducers/metamask.js b/old-ui/app/reducers/metamask.js index 13ac9e611..68ad975a7 100644 --- a/old-ui/app/reducers/metamask.js +++ b/old-ui/app/reducers/metamask.js @@ -1,5 +1,5 @@ const extend = require('xtend') -const actions = require('../actions') +const actions = require('../../../ui/app/actions') const MetamascaraPlatform = require('../../../app/scripts/platforms/window') module.exports = reduceMetamask diff --git a/old-ui/app/send.js b/old-ui/app/send.js index e59c1130e..9ab064aea 100644 --- a/old-ui/app/send.js +++ b/old-ui/app/send.js @@ -3,7 +3,7 @@ const PersistentForm = require('../lib/persistent-form') const h = require('react-hyperscript') const connect = require('react-redux').connect const Identicon = require('./components/identicon') -const actions = require('./actions') +const actions = require('../../ui/app/actions') const util = require('./util') const numericBalance = require('./util').numericBalance const addressSummary = require('./util').addressSummary diff --git a/old-ui/app/settings.js b/old-ui/app/settings.js index 454cc95e0..8df37c555 100644 --- a/old-ui/app/settings.js +++ b/old-ui/app/settings.js @@ -2,7 +2,7 @@ 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') +const actions = require('../../ui/app/actions') module.exports = connect(mapStateToProps)(AppSettingsPage) diff --git a/old-ui/app/unlock.js b/old-ui/app/unlock.js index 4180791c4..a1f791552 100644 --- a/old-ui/app/unlock.js +++ b/old-ui/app/unlock.js @@ -2,7 +2,7 @@ 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') +const actions = require('../../ui/app/actions') const getCaretCoordinates = require('textarea-caret') const EventEmitter = require('events').EventEmitter -- cgit From ce14ee2ffcc784849ab42797d5c999b76ed57a78 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 15 Nov 2017 14:09:03 -0330 Subject: New-ui actions accomodates old-ui. --- ui/app/actions.js | 17 ++++++++++------- ui/app/reducers/metamask.js | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/ui/app/actions.js b/ui/app/actions.js index 745b8779e..bdacf3092 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -993,9 +993,10 @@ function showConfigPage (transitionForward = true) { } } -function showAddTokenPage () { +function showAddTokenPage (transitionForward = true) { return { type: actions.SHOW_ADD_TOKEN_PAGE, + value: transitionForward, } } @@ -1277,7 +1278,8 @@ function exportAccount (password, address) { return reject(err) } - dispatch(self.exportAccountComplete()) + // dispatch(self.exportAccountComplete()) + dispatch(self.showPrivateKey(result)) return resolve(result) }) @@ -1444,7 +1446,7 @@ function reshowQrCode (data, coin) { dispatch(actions.showLoadingIndication()) shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_eth`}, (mktResponse) => { if (mktResponse.error) return dispatch(actions.displayWarning(mktResponse.error)) - + var message = [ `Deposit your ${coin} to the address bellow:`, `Deposit Limit: ${mktResponse.limit}`, @@ -1452,10 +1454,11 @@ function reshowQrCode (data, coin) { ] dispatch(actions.hideLoadingIndication()) - return dispatch(actions.showModal({ - name: 'SHAPESHIFT_DEPOSIT_TX', - Qr: { data, message }, - })) + return dispatch(actions.showQrView(data, message)) + // return dispatch(actions.showModal({ + // name: 'SHAPESHIFT_DEPOSIT_TX', + // Qr: { data, message }, + // })) }) } } diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index 6d6068d05..c496625c7 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -311,7 +311,7 @@ function reduceMetamask (state, action) { return extend(metamaskState, { tokenExchangeRates: { ...metamaskState.tokenExchangeRates, - [marketinfo.pair]: ssMarketInfo, + [ssMarketInfo.pair]: ssMarketInfo, }, coinOptions, }) -- cgit From db06e7e649c5bdc98063bfeb7d7cbff999543c32 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 15 Nov 2017 14:09:54 -0330 Subject: Css selected in background based on betaUI state. --- app/scripts/popup.js | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/app/scripts/popup.js b/app/scripts/popup.js index 8cef06931..d0952af6a 100644 --- a/app/scripts/popup.js +++ b/app/scripts/popup.js @@ -1,5 +1,6 @@ const injectCss = require('inject-css') -const MetaMaskUiCss = require('../../ui/css') +const OldMetaMaskUiCss = require('../../old-ui/css') +const NewMetaMaskUiCss = require('../../ui/css') const startPopup = require('./popup-core') const PortStream = require('./lib/port-stream.js') const isPopupOrNotification = require('./lib/is-popup-or-notification') @@ -11,11 +12,6 @@ const notificationManager = new NotificationManager() // create platform global global.platform = new ExtensionPlatform() -// inject css -console.log(`MetaMaskUiCss`, MetaMaskUiCss); -const css = MetaMaskUiCss() -injectCss(css) - // identify window type (popup, notification) const windowType = isPopupOrNotification() global.METAMASK_UI_TYPE = windowType @@ -29,8 +25,21 @@ const connectionStream = new PortStream(extensionPort) const container = document.getElementById('app-content') startPopup({ container, connectionStream }, (err, store) => { if (err) return displayCriticalError(err) + + let betaUIState = store.getState().metamask.featureFlags.betaUI + let css = betaUIState ? NewMetaMaskUiCss() : OldMetaMaskUiCss() + let deleteInjectedCss = injectCss(css) + let newBetaUIState + store.subscribe(() => { const state = store.getState() + newBetaUIState = state.metamask.featureFlags.betaUI + if (newBetaUIState !== betaUIState) { + deleteInjectedCss() + betaUIState = newBetaUIState + css = betaUIState ? NewMetaMaskUiCss() : OldMetaMaskUiCss() + deleteInjectedCss = injectCss(css) + } if (state.appState.shouldClose) notificationManager.closePopup() }) }) -- cgit From 84321b2d9b08a2b0f3e773cfb6f6d11dff9f7d4c Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 16 Nov 2017 15:58:59 -0330 Subject: Lint fix --- app/scripts/controllers/preferences.js | 2 +- ui/app/app.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 0dd9eae1b..de9006044 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -110,7 +110,7 @@ class PreferencesController { } this.store.updateState({ featureFlags: updatedFeatureFlags }) - console.log(`!!! updatedFeatureFlags`, updatedFeatureFlags); + return Promise.resolve(updatedFeatureFlags) } diff --git a/ui/app/app.js b/ui/app/app.js index 7e1eb200f..7cee07ea5 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -150,7 +150,7 @@ App.prototype.render = function () { // content this.renderPrimary(), - ]) + ]), ]) ) } @@ -274,7 +274,7 @@ App.prototype.renderAppBar = function () { onClick: () => { props.dispatch(actions.setFeatureFlag('betaUI', false)) }, - }, 'Leave Beta') + }, 'Leave Beta'), ]), -- cgit From 730d7f84ca8c202674677a6a6a94290e57ad9e3a Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 4 Dec 2017 15:30:45 -0330 Subject: Update newUI UI for switching back to old UI. --- ui/app/app.js | 7 ------- ui/app/settings.js | 25 ++++++++++++++++++++++++- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/ui/app/app.js b/ui/app/app.js index 7cee07ea5..88a5c8458 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -269,13 +269,6 @@ App.prototype.renderAppBar = function () { }, }, 'MetaMask'), - h('span', { - style: {}, - onClick: () => { - props.dispatch(actions.setFeatureFlag('betaUI', false)) - }, - }, 'Leave Beta'), - ]), h('div.header__right-actions', [ diff --git a/ui/app/settings.js b/ui/app/settings.js index caa36d2b8..ba59f1c76 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -229,6 +229,26 @@ class Settings extends Component { ) } + renderOldUI () { + const { setFeatureFlagToBeta } = this.props + + return ( + h('div.settings__content-row', [ + h('div.settings__content-item', 'Use old UI'), + h('div.settings__content-item', [ + h('div.settings__content-item-col', [ + h('button.settings__clear-button.settings__clear-button--red', { + onClick (event) { + event.preventDefault() + setFeatureFlagToBeta() + }, + }, 'Use old UI'), + ]), + ]), + ]) + ) + } + renderSettingsContent () { const { warning } = this.props @@ -241,10 +261,11 @@ class Settings extends Component { this.renderNewRpcUrl(), this.renderStateLogs(), this.renderSeedWords(), + this.renderOldUI(), ]) ) } - + renderLogo () { return ( h('div.settings__info-logo-wrapper', [ @@ -362,6 +383,7 @@ Settings.propTypes = { setRpcTarget: PropTypes.func, displayWarning: PropTypes.func, revealSeedConfirmation: PropTypes.func, + setFeatureFlagToBeta: PropTypes.func, warning: PropTypes.string, goHome: PropTypes.func, } @@ -381,6 +403,7 @@ const mapDispatchToProps = dispatch => { displayWarning: warning => dispatch(actions.displayWarning(warning)), revealSeedConfirmation: () => dispatch(actions.revealSeedConfirmation()), setUseBlockie: value => dispatch(actions.setUseBlockie(value)), + setFeatureFlagToBeta: () => dispatch(actions.setFeatureFlag('betaUI', false)), } } -- cgit From 9db00fa507c04180f6425cc3b1e3187afa193ab8 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 4 Dec 2017 22:30:11 -0330 Subject: Show user notifications after switch between UIs --- old-ui/app/config.js | 4 +- old-ui/app/css/index.css | 47 ++++++++++++++++++++++++ ui/app/actions.js | 4 ++ ui/app/components/modals/modal.js | 37 +++++++++++++++++++ ui/app/components/modals/notification-modal.js | 51 ++++++++++++++++++++++++++ ui/app/css/itcss/components/modal.scss | 36 ++++++++++++++++++ ui/app/css/itcss/components/settings.scss | 5 +++ ui/app/settings.js | 4 +- 8 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 ui/app/components/modals/notification-modal.js diff --git a/old-ui/app/config.js b/old-ui/app/config.js index c698417ba..acd101947 100644 --- a/old-ui/app/config.js +++ b/old-ui/app/config.js @@ -8,7 +8,7 @@ const infuraCurrencies = require('./infura-conversion.json').objects.sort((a, b) }) const validUrl = require('valid-url') const exportAsFile = require('./util').exportAsFile - +const Modal = require('../../ui/app/components/modals/index').Modal module.exports = connect(mapStateToProps)(ConfigScreen) @@ -32,6 +32,8 @@ ConfigScreen.prototype.render = function () { return ( h('.flex-column.flex-grow', [ + h(Modal, {}, []), + // subtitle and nav h('.section-title.flex-row.flex-center', [ h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { diff --git a/old-ui/app/css/index.css b/old-ui/app/css/index.css index 0630c4c12..c2f2b6070 100644 --- a/old-ui/app/css/index.css +++ b/old-ui/app/css/index.css @@ -705,3 +705,50 @@ div.message-container > div:first-child { .pop-hover:hover { transform: scale(1.1); } + +//Notification Modal + +.notification-modal-wrapper { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; + position: relative; + border: 1px solid #dedede; + box-shadow: 0 0 2px 2px #dedede; + font-family: Roboto; +} + +.notification-modal-header { + background: #f6f6f6; + width: 100%; + display: flex; + justify-content: center; + padding: 30px; + font-size: 22px; + color: #1b344d; + height: 79px; +} + +.notification-modal-message { + padding: 20px; +} + +.notification-modal-message { + width: 100%; + display: flex; + justify-content: center; + font-size: 17px; + color: #1b344d; +} + +.modal-close-x::after { + content: '\00D7'; + font-size: 2em; + color: #9b9b9b; + position: absolute; + top: 25px; + right: 17.5px; + font-family: sans-serif; + cursor: pointer; +} \ No newline at end of file diff --git a/ui/app/actions.js b/ui/app/actions.js index bdacf3092..bba2a014f 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -1515,6 +1515,9 @@ function updateTokenExchangeRate (token = '') { } function setFeatureFlag (feature, activated) { + const notificationType = activated + ? 'BETA_UI_NOTIFICATION_MODAL' + : 'OLD_UI_NOTIFICATION_MODAL' return (dispatch) => { dispatch(actions.showLoadingIndication()) return new Promise((resolve, reject) => { @@ -1525,6 +1528,7 @@ function setFeatureFlag (feature, activated) { reject(err) } dispatch(actions.updateFeatureFlags(updatedFeatureFlags)) + dispatch(actions.showModal({ name: notificationType })) resolve(updatedFeatureFlags) }) }) diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index f2909f3c3..2ff6accaa 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -16,6 +16,7 @@ const NewAccountModal = require('./new-account-modal') const ShapeshiftDepositTxModal = require('./shapeshift-deposit-tx-modal.js') const HideTokenConfirmationModal = require('./hide-token-confirmation-modal') const CustomizeGasModal = require('../customize-gas-modal') +const NotifcationModal = require('./notification-modal') const accountModalStyle = { mobileModalStyle: { @@ -133,6 +134,42 @@ const MODALS = { }, }, + BETA_UI_NOTIFICATION_MODAL: { + contents: [ + h(NotifcationModal, { + header: 'Welcome to the New UI (Beta)', + message: `You are now using the new Metamask UI. Take a look around, try out new features like sending tokens, + and let us know if you have any issues.`, + }), + ], + mobileModalStyle: { + width: '95%', + top: isPopupOrNotification() === 'popup' ? '52vh' : '36.5vh', + }, + laptopModalStyle: { + width: '449px', + top: 'calc(33% + 45px)', + }, + }, + + OLD_UI_NOTIFICATION_MODAL: { + contents: [ + h(NotifcationModal, { + header: 'Old UI', + message: `You have returned to the old UI. You can switch back to the New UI through the option in the top + right dropdown menu.`, + }), + ], + mobileModalStyle: { + width: '95%', + top: isPopupOrNotification() === 'popup' ? '52vh' : '36.5vh', + }, + laptopModalStyle: { + width: '449px', + top: 'calc(33% + 45px)', + }, + }, + NEW_ACCOUNT: { contents: [ h(NewAccountModal, {}, []), diff --git a/ui/app/components/modals/notification-modal.js b/ui/app/components/modals/notification-modal.js new file mode 100644 index 000000000..239144b0c --- /dev/null +++ b/ui/app/components/modals/notification-modal.js @@ -0,0 +1,51 @@ +const { Component } = require('react') +const PropTypes = require('prop-types') +const h = require('react-hyperscript') +const { connect } = require('react-redux') +const actions = require('../../actions') + +class NotificationModal extends Component { + render () { + const { + header, + message, + } = this.props + + return h('div', [ + h('div.notification-modal-wrapper', { + }, [ + + h('div.notification-modal-header', {}, [ + header, + ]), + + h('div.notification-modal-message-wrapper', {}, [ + h('div.notification-modal-message', {}, [ + message, + ]), + ]), + + h('div.modal-close-x', { + onClick: this.props.hideModal, + }), + + ]), + ]) + } +} + +NotificationModal.propTypes = { + hideModal: PropTypes.func, + header: PropTypes.string, + message: PropTypes.string, +} + +const mapDispatchToProps = dispatch => { + return { + hideModal: () => { + dispatch(actions.hideModal()) + }, + } +} + +module.exports = connect(null, mapDispatchToProps)(NotificationModal) diff --git a/ui/app/css/itcss/components/modal.scss b/ui/app/css/itcss/components/modal.scss index b69bd5c7e..9b64564d6 100644 --- a/ui/app/css/itcss/components/modal.scss +++ b/ui/app/css/itcss/components/modal.scss @@ -563,3 +563,39 @@ } } } + +//Notification Modal + +.notification-modal-wrapper { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; + position: relative; + border: 1px solid $alto; + box-shadow: 0 0 2px 2px $alto; + font-family: Roboto; +} + +.notification-modal-header { + background: $wild-sand; + width: 100%; + display: flex; + justify-content: center; + padding: 30px; + font-size: 22px; + color: $nile-blue; + height: 79px; +} + +.notification-modal-message { + padding: 20px; +} + +.notification-modal-message { + width: 100%; + display: flex; + justify-content: center; + font-size: 17px; + color: $nile-blue; +} \ No newline at end of file diff --git a/ui/app/css/itcss/components/settings.scss b/ui/app/css/itcss/components/settings.scss index 2f29d8017..d60ebd934 100644 --- a/ui/app/css/itcss/components/settings.scss +++ b/ui/app/css/itcss/components/settings.scss @@ -145,6 +145,11 @@ color: $monzo; } +.settings__clear-button--orange { + border: 1px solid rgba(247, 134, 28, 1); + color: rgba(247, 134, 28, 1); +} + .settings__info-logo-wrapper { height: 80px; margin-bottom: 20px; diff --git a/ui/app/settings.js b/ui/app/settings.js index ba59f1c76..ca7535d26 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -228,7 +228,7 @@ class Settings extends Component { ]) ) } - + renderOldUI () { const { setFeatureFlagToBeta } = this.props @@ -237,7 +237,7 @@ class Settings extends Component { h('div.settings__content-item', 'Use old UI'), h('div.settings__content-item', [ h('div.settings__content-item-col', [ - h('button.settings__clear-button.settings__clear-button--red', { + h('button.settings__clear-button.settings__clear-button--orange', { onClick (event) { event.preventDefault() setFeatureFlagToBeta() -- cgit From ae2a4d78e8c7733da1963965e38e154351d54a20 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 5 Dec 2017 17:21:14 -0330 Subject: Exponentional backoff on transaction retry in pending-tx-tracker --- app/scripts/controllers/transactions.js | 6 ++++++ app/scripts/lib/pending-tx-tracker.js | 16 ++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index a861c0342..063ba8f65 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -72,6 +72,12 @@ module.exports = class TransactionController extends EventEmitter { }) this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager)) this.pendingTxTracker.on('tx:confirmed', this.txStateManager.setTxStatusConfirmed.bind(this.txStateManager)) + this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => { + if (!txMeta.firstRetryBlockNumber) { + txMeta.firstRetryBlockNumber = latestBlockNumber + this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry') + } + }) this.pendingTxTracker.on('tx:retry', (txMeta) => { if (!('retryCount' in txMeta)) txMeta.retryCount = 0 txMeta.retryCount++ diff --git a/app/scripts/lib/pending-tx-tracker.js b/app/scripts/lib/pending-tx-tracker.js index 0d7c6a92c..60c837040 100644 --- a/app/scripts/lib/pending-tx-tracker.js +++ b/app/scripts/lib/pending-tx-tracker.js @@ -65,7 +65,7 @@ module.exports = class PendingTransactionTracker extends EventEmitter { } - resubmitPendingTxs () { + resubmitPendingTxs (block) { const pending = this.getPendingTransactions() // only try resubmitting if their are transactions to resubmit if (!pending.length) return @@ -101,13 +101,25 @@ module.exports = class PendingTransactionTracker extends EventEmitter { })) } - async _resubmitTx (txMeta) { + async _resubmitTx (txMeta, latestBlockNumber) { + if (!txMeta.firstRetryBlockNumber) { + this.emit('tx:block-update', txMeta, latestBlockNumber) + } + if (Date.now() > txMeta.time + this.retryTimePeriod) { const hours = (this.retryTimePeriod / 3.6e+6).toFixed(1) const err = new Error(`Gave up submitting after ${hours} hours.`) return this.emit('tx:failed', txMeta.id, err) } + const firstRetryBlockNumber = txMeta.firstRetryBlockNumber + const txBlockDistance = Number.parseInt(latestBlockNumber, 16) - Number.parseInt(firstRetryBlockNumber, 16) + + const retryCount = txMeta.retryCount || 0 + + // Exponential backoff to limit retries at publishing + if (txBlockDistance <= Math.pow(2, retryCount) - 1) return + // Only auto-submit already-signed txs: if (!('rawTx' in txMeta)) return -- cgit From 871d9fd9fb8417a2dd47abafe68ae07e4903ba6e Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 6 Dec 2017 13:02:38 -0330 Subject: Fix undefined latestBlockNumber in _resubmitTx --- app/scripts/lib/pending-tx-tracker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/pending-tx-tracker.js b/app/scripts/lib/pending-tx-tracker.js index 60c837040..62d621ac1 100644 --- a/app/scripts/lib/pending-tx-tracker.js +++ b/app/scripts/lib/pending-tx-tracker.js @@ -69,7 +69,7 @@ module.exports = class PendingTransactionTracker extends EventEmitter { const pending = this.getPendingTransactions() // only try resubmitting if their are transactions to resubmit if (!pending.length) return - pending.forEach((txMeta) => this._resubmitTx(txMeta).catch((err) => { + pending.forEach((txMeta) => this._resubmitTx(txMeta, block.number).catch((err) => { /* Dont marked as failed if the error is a "known" transaction warning "there is already a transaction with the same sender-nonce -- cgit From ea23da9e75c92cbf82d0daa19847d2035361a656 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 6 Dec 2017 13:07:31 -0330 Subject: Correct note for updateTx after block-update event in transaction.js --- app/scripts/controllers/transactions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 063ba8f65..ce709bd28 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -75,7 +75,7 @@ module.exports = class TransactionController extends EventEmitter { this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => { if (!txMeta.firstRetryBlockNumber) { txMeta.firstRetryBlockNumber = latestBlockNumber - this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry') + this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:block-update') } }) this.pendingTxTracker.on('tx:retry', (txMeta) => { -- cgit From f58aae3f2ba3d8a129b2c09dc3b45369c488fd04 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 6 Dec 2017 13:21:09 -0330 Subject: firstRetryBlockNumber defaults to latestBlockNumber if undefined on txMeta in _resubmitTx --- app/scripts/lib/pending-tx-tracker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/pending-tx-tracker.js b/app/scripts/lib/pending-tx-tracker.js index 62d621ac1..dc6e526fd 100644 --- a/app/scripts/lib/pending-tx-tracker.js +++ b/app/scripts/lib/pending-tx-tracker.js @@ -112,7 +112,7 @@ module.exports = class PendingTransactionTracker extends EventEmitter { return this.emit('tx:failed', txMeta.id, err) } - const firstRetryBlockNumber = txMeta.firstRetryBlockNumber + const firstRetryBlockNumber = txMeta.firstRetryBlockNumber || latestBlockNumber const txBlockDistance = Number.parseInt(latestBlockNumber, 16) - Number.parseInt(firstRetryBlockNumber, 16) const retryCount = txMeta.retryCount || 0 -- cgit From af8fcb67778fadd7056c0930eeb9d22eb28b0e69 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 6 Dec 2017 14:10:11 -0330 Subject: Update resubmitPendingTxs tests. --- test/unit/pending-tx-test.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/unit/pending-tx-test.js b/test/unit/pending-tx-test.js index 4b5170dfe..7069554f7 100644 --- a/test/unit/pending-tx-test.js +++ b/test/unit/pending-tx-test.js @@ -206,6 +206,7 @@ describe('PendingTransactionTracker', function () { }) describe('#resubmitPendingTxs', function () { + const blockStub = { number: '0x0' }; beforeEach(function () { const txMeta2 = txMeta3 = txMeta txList = [txMeta, txMeta2, txMeta3].map((tx) => { @@ -223,7 +224,7 @@ describe('PendingTransactionTracker', function () { Promise.all(txList.map((tx) => tx.processed)) .then((txCompletedList) => done()) .catch(done) - pendingTxTracker.resubmitPendingTxs() + pendingTxTracker.resubmitPendingTxs(blockStub) }) it('should not emit \'tx:failed\' if the txMeta throws a known txError', function (done) { knownErrors =[ @@ -250,7 +251,7 @@ describe('PendingTransactionTracker', function () { .then((txCompletedList) => done()) .catch(done) - pendingTxTracker.resubmitPendingTxs() + pendingTxTracker.resubmitPendingTxs(blockStub) }) it('should emit \'tx:warning\' if it encountered a real error', function (done) { pendingTxTracker.once('tx:warning', (txMeta, err) => { @@ -268,7 +269,7 @@ describe('PendingTransactionTracker', function () { .then((txCompletedList) => done()) .catch(done) - pendingTxTracker.resubmitPendingTxs() + pendingTxTracker.resubmitPendingTxs(blockStub) }) }) describe('#_resubmitTx', function () { -- cgit From 3356c15d04d947c92a2c19690384396651c352e5 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 6 Dec 2017 14:11:14 -0330 Subject: Add tests for exponential backoff code in _resubmitTx --- test/unit/pending-tx-test.js | 80 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/test/unit/pending-tx-test.js b/test/unit/pending-tx-test.js index 7069554f7..393601a57 100644 --- a/test/unit/pending-tx-test.js +++ b/test/unit/pending-tx-test.js @@ -273,24 +273,70 @@ describe('PendingTransactionTracker', function () { }) }) describe('#_resubmitTx', function () { - it('should publishing the transaction', function (done) { - const enoughBalance = '0x100000' - pendingTxTracker.getBalance = (address) => { - assert.equal(address, txMeta.txParams.from, 'Should pass the address') - return enoughBalance - } - pendingTxTracker.publishTransaction = async (rawTx) => { - assert.equal(rawTx, txMeta.rawTx, 'Should pass the rawTx') - } + const mockFirstRetryBlockNumber = '0x1' + let txMetaToTestExponentialBackoff + + beforeEach(() => { + pendingTxTracker.getBalance = (address) => { + assert.equal(address, txMeta.txParams.from, 'Should pass the address') + return enoughBalance + } + pendingTxTracker.publishTransaction = async (rawTx) => { + assert.equal(rawTx, txMeta.rawTx, 'Should pass the rawTx') + } + sinon.spy(pendingTxTracker, 'publishTransaction') + + txMetaToTestExponentialBackoff = Object.assign({}, txMeta, { + retryCount: 4, + firstRetryBlockNumber: mockFirstRetryBlockNumber, + }) + }) - // Stubbing out current account state: - // Adding the fake tx: - pendingTxTracker._resubmitTx(txMeta) - .then(() => done()) - .catch((err) => { - assert.ifError(err, 'should not throw an error') - done(err) + afterEach(() => { + pendingTxTracker.publishTransaction.reset() + }) + + it('should publish the transaction', function (done) { + const enoughBalance = '0x100000' + + // Stubbing out current account state: + // Adding the fake tx: + pendingTxTracker._resubmitTx(txMeta) + .then(() => done()) + .catch((err) => { + assert.ifError(err, 'should not throw an error') + done(err) + }) + + assert.equal(pendingTxTracker.publishTransaction.callCount, 1, 'Should call publish transaction') + }) + + it('should not publish the transaction if the limit of retries has been exceeded', function (done) { + const enoughBalance = '0x100000' + const mockLatestBlockNumber = '0x5' + + pendingTxTracker._resubmitTx(txMetaToTestExponentialBackoff, mockLatestBlockNumber) + .then(() => done()) + .catch((err) => { + assert.ifError(err, 'should not throw an error') + done(err) + }) + + assert.equal(pendingTxTracker.publishTransaction.callCount, 0, 'Should NOT call publish transaction') + }) + + it('should publish the transaction if the number of blocks since last retry exceeds the last set limit', function (done) { + const enoughBalance = '0x100000' + const mockLatestBlockNumber = '0x11' + + pendingTxTracker._resubmitTx(txMetaToTestExponentialBackoff, mockLatestBlockNumber) + .then(() => done()) + .catch((err) => { + assert.ifError(err, 'should not throw an error') + done(err) + }) + + assert.equal(pendingTxTracker.publishTransaction.callCount, 1, 'Should call publish transaction') }) - }) }) }) -- cgit From bd5ce9461e5119c13ab8be29db5cdfc57228bac8 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 6 Dec 2017 20:49:45 -0330 Subject: User is automatically added to new UI if they meet conditions at time of login. --- ui/app/select-app.js | 32 +++++++++++++++++++++++++++++--- ui/app/selectors.js | 18 ++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/ui/app/select-app.js b/ui/app/select-app.js index 3cba44052..ffa31b767 100644 --- a/ui/app/select-app.js +++ b/ui/app/select-app.js @@ -4,18 +4,44 @@ const connect = require('react-redux').connect const h = require('react-hyperscript') const App = require('./app') const OldApp = require('../../old-ui/app/app') +const { autoAddToBetaUI } = require('./selectors') +const { setFeatureFlag } = require('./actions') function mapStateToProps (state) { - return { betaUI: state.metamask.featureFlags.betaUI } + return { + betaUI: state.metamask.featureFlags.betaUI, + autoAdd: autoAddToBetaUI(state), + isUnlocked: state.metamask.isUnlocked, + } } -module.exports = connect(mapStateToProps)(SelectedApp) +function mapDispatchToProps (dispatch) { + return { + setFeatureFlagToBeta: () => dispatch(setFeatureFlag('betaUI', true)), + } +} +module.exports = connect(mapStateToProps, mapDispatchToProps)(SelectedApp) inherits(SelectedApp, Component) -function SelectedApp () { Component.call(this) } +function SelectedApp () { + this.state = { + autoAdd: false, + } + Component.call(this) +} + +SelectedApp.prototype.componentWillReceiveProps = function (nextProps) { + const { isUnlocked, setFeatureFlagToBeta } = this.props + + if (!isUnlocked && nextProps.isUnlocked && nextProps.autoAdd) { + this.setState({ autoAdd: nextProps.autoAdd }) + setFeatureFlagToBeta() + } +} SelectedApp.prototype.render = function () { const { betaUI } = this.props + const { autoAdd } = this.state const Selected = betaUI ? App : OldApp return h(Selected) } diff --git a/ui/app/selectors.js b/ui/app/selectors.js index a5f9a75d8..8aea7864a 100644 --- a/ui/app/selectors.js +++ b/ui/app/selectors.js @@ -24,6 +24,7 @@ const selectors = { getSendAmount, getSelectedTokenToFiatRate, getSelectedTokenContract, + autoAddToBetaUI, } module.exports = selectors @@ -158,3 +159,20 @@ function getSelectedTokenContract (state) { ? global.eth.contract(abi).at(selectedToken.address) : null } + +function autoAddToBetaUI (state) { + const autoAddTransactionThreshold = 12 + const autoAddAccountsThreshold = 2 + const autoAddTokensThreshold = 1 + + const numberOfTransactions = state.metamask.selectedAddressTxList.length + const numberOfAccounts = Object.keys(state.metamask.accounts).length + const numberOfTokensAdded = state.metamask.tokens.length + + const userPassesThreshold = (numberOfTransactions > autoAddTransactionThreshold) && + (numberOfAccounts > autoAddAccountsThreshold) && + (numberOfTokensAdded > autoAddTokensThreshold) + const userIsNotInBeta = !state.metamask.featureFlags.betaUI + + return userIsNotInBeta && userPassesThreshold +} \ No newline at end of file -- cgit From ec6c3c33bdbe2d90dc71649d0cc5fb3c07d96af7 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 5 Dec 2017 13:11:59 -0330 Subject: Merge branch 'master' into NewUI-flat-merge-with-master --- CHANGELOG.md | 6 +++ ISSUE_TEMPLATE | 6 +-- app/scripts/background.js | 9 +++-- app/scripts/controllers/network.js | 2 +- app/scripts/inpage.js | 7 ++++ app/scripts/lib/inpage-provider.js | 4 +- app/scripts/metamask-controller.js | 47 ++++++++++++++++++++--- app/scripts/migrations/020.js | 41 ++++++++++++++++++++ app/scripts/migrations/index.js | 1 + app/scripts/notice-controller.js | 44 +++++++++++++-------- gulpfile.js | 8 +++- mascara/src/app/first-time/notice-screen.js | 2 +- notices/archive/notice_3.md | 11 ++++++ notices/notice-nonce.json | 2 +- notices/notices.json | 2 +- package.json | 6 ++- test/integration/lib/mascara-first-time.js | 59 ++++++++++++----------------- test/unit/metamask-controller-test.js | 33 ++++++++++++++++ ui/app/first-time/init-menu.js | 7 +++- 19 files changed, 226 insertions(+), 71 deletions(-) create mode 100644 app/scripts/migrations/020.js create mode 100644 notices/archive/notice_3.md diff --git a/CHANGELOG.md b/CHANGELOG.md index ee9548606..009cd5f7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Current Master +## 3.12.1 2017-11-29 + +- Fix bug where a user could be shown two different seed phrases. +- Detect when multiple web3 extensions are active, and provide useful error. +- Adds notice about seed phrase backup. + ## 3.12.0 2017-10-25 - Add support for alternative ENS TLDs (Ethereum Name Service Top-Level Domains). diff --git a/ISSUE_TEMPLATE b/ISSUE_TEMPLATE index d0ff3c08e..b56d08d95 100644 --- a/ISSUE_TEMPLATE +++ b/ISSUE_TEMPLATE @@ -1,7 +1,7 @@