aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Huang <thomas.b.huang@gmail.com>2018-08-02 01:40:31 +0800
committerThomas Huang <thomas.b.huang@gmail.com>2018-08-02 01:40:31 +0800
commit024ebe07e0c61e7185e84499a2f19885ac52e4a9 (patch)
tree88ed997d61c225573b7d75c357f5c11b6840a3ea
parent5b3927fe5b5243a89e5fd31ad069da9ea5c987e9 (diff)
parent4f02726fd9a2b7509dfd00eb4b23d9fc81eb5dcd (diff)
downloadtangerine-wallet-browser-024ebe07e0c61e7185e84499a2f19885ac52e4a9.tar
tangerine-wallet-browser-024ebe07e0c61e7185e84499a2f19885ac52e4a9.tar.gz
tangerine-wallet-browser-024ebe07e0c61e7185e84499a2f19885ac52e4a9.tar.bz2
tangerine-wallet-browser-024ebe07e0c61e7185e84499a2f19885ac52e4a9.tar.lz
tangerine-wallet-browser-024ebe07e0c61e7185e84499a2f19885ac52e4a9.tar.xz
tangerine-wallet-browser-024ebe07e0c61e7185e84499a2f19885ac52e4a9.tar.zst
tangerine-wallet-browser-024ebe07e0c61e7185e84499a2f19885ac52e4a9.zip
Merge branch 'develop' into network-remove-provider-engine-tests
-rw-r--r--README.md7
-rw-r--r--app/_locales/index.json4
-rw-r--r--app/_locales/ja/messages.json33
-rw-r--r--app/images/ethereum-metamask-chrome.pngbin0 -> 60022 bytes
-rw-r--r--app/manifest.json3
-rw-r--r--app/phishing.html60
-rw-r--r--app/scripts/contentscript.js5
-rw-r--r--app/scripts/controllers/transactions/tx-gas-utils.js10
-rw-r--r--app/scripts/lib/inpage-provider.js5
-rw-r--r--mascara/src/app/first-time/index.js20
-rw-r--r--old-ui/app/account-qr.js86
-rw-r--r--old-ui/app/app.js461
-rw-r--r--old-ui/app/components/app-bar.js432
-rw-r--r--old-ui/app/components/qr-code.js79
-rw-r--r--old-ui/app/components/shapeshift-form.js4
-rw-r--r--old-ui/app/components/transaction-list-item.js11
-rw-r--r--old-ui/app/css/index.css128
-rw-r--r--old-ui/app/new-ui-annoucement.js85
-rw-r--r--package-lock.json148
-rw-r--r--test/e2e/beta/from-import-beta-ui.spec.js60
-rw-r--r--test/e2e/beta/metamask-beta-ui.spec.js117
-rw-r--r--test/e2e/metamask.spec.js24
-rw-r--r--test/integration/lib/first-time.js5
-rw-r--r--ui/app/components/confirm-page-container/confirm-detail-row/index.scss7
-rw-r--r--ui/app/components/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js64
-rw-r--r--ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js7
-rw-r--r--ui/app/components/tx-list-item.js11
-rw-r--r--ui/app/helpers/confirm-transaction/util.js9
-rw-r--r--ui/app/selectors/confirm-transaction.js13
29 files changed, 1203 insertions, 695 deletions
diff --git a/README.md b/README.md
index 86d515377..38aceaf7e 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,6 @@
# MetaMask Browser Extension
[![Build Status](https://circleci.com/gh/MetaMask/metamask-extension.svg?style=shield&circle-token=a1ddcf3cd38e29267f254c9c59d556d513e3a1fd)](https://circleci.com/gh/MetaMask/metamask-extension) [![Coverage Status](https://coveralls.io/repos/github/MetaMask/metamask-extension/badge.svg?branch=master)](https://coveralls.io/github/MetaMask/metamask-extension?branch=master) [![Greenkeeper badge](https://badges.greenkeeper.io/MetaMask/metamask-extension.svg)](https://greenkeeper.io/) [![Stories in Ready](https://badge.waffle.io/MetaMask/metamask-extension.png?label=in%20progress&title=waffle.io)](https://waffle.io/MetaMask/metamask-extension)
-🚨 As of 7/25/18, the MetaMask extension has been removed from the Chrome Web Store. In the meantime, you can download the latest version of MetaMask on our [Releases](https://github.com/MetaMask/metamask-extension/releases) page and load it in Chrome by visiting `chrome://extensions`. For more detailed steps, see our [help center](https://consensys.zendesk.com/hc/en-us/articles/360004134152-How-to-Install-MetaMask-Manually). Follow [@metamask_io](https://twitter.com/metamask_io) on Twitter for updates. 🚨
-
## Support
If you're a user seeking support, [here is our support site](https://metamask.helpscoutdocs.com/).
@@ -29,8 +27,9 @@ If you're a web dapp developer, we've got two types of guides for you:
## Building locally
- Install [Node.js](https://nodejs.org/en/) version 8.11.3 and npm version 6.1.0
- - Install dependencies:
- - If you are using nvm (recommended) running `nvm use` will automatically choose the right node version for you.
+ - If you are using [nvm](https://github.com/creationix/nvm#installation) (recommended) running `nvm use` will automatically choose the right node version for you.
+ - Select npm 6.1.0: ```npm install -g npm@6.1.0```
+ - Install dependencies: ```npm install```
- Install gulp globally with `npm install -g gulp-cli`.
- Build the project to the `./dist/` folder with `gulp build`.
- Optionally, to rebuild on file changes, run `gulp dev`.
diff --git a/app/_locales/index.json b/app/_locales/index.json
index 7717502b7..f50c09f88 100644
--- a/app/_locales/index.json
+++ b/app/_locales/index.json
@@ -17,6 +17,6 @@
{ "code": "tml", "name": "Tamil" },
{ "code": "tr", "name": "Turkish" },
{ "code": "vi", "name": "Vietnamese" },
- { "code": "zh_CN", "name": "Mandarin" },
- { "code": "zh_TW", "name": "Taiwanese" }
+ { "code": "zh_CN", "name": "Chinese (Simplified)" },
+ { "code": "zh_TW", "name": "Chinese (Traditional)" }
]
diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json
index 75deeaddf..c9d192139 100644
--- a/app/_locales/ja/messages.json
+++ b/app/_locales/ja/messages.json
@@ -122,6 +122,9 @@
"copy": {
"message": "コピー"
},
+ "copyContractAddress": {
+ "message": "コントラクトアドレスをコピー"
+ },
"copyToClipboard": {
"message": "クリップボードへコピー"
},
@@ -395,6 +398,9 @@
"mainnet": {
"message": "Ethereumメインネットワーク"
},
+ "menu": {
+ "message": "メニュー"
+ },
"message": {
"message": "メッセージ"
},
@@ -464,6 +470,9 @@
"oldUIMessage": {
"message": "旧UIを表示しています。右上のドロップダウンメニューのオプションより、新UIへ切り替えが可能です。"
},
+ "openInTab": {
+ "message": "タブを開く"
+ },
"or": {
"message": "または",
"description": "choice between creating or importing a new account"
@@ -573,6 +582,15 @@
"searchResults": {
"message": "検索結果"
},
+ "newPassword8Chars": {
+ "message": "新しいパスワード (8桁以上)"
+ },
+ "select": {
+ "message": "選択"
+ },
+ "selectCurrency": {
+ "message": "通貨を選択"
+ },
"selectService": {
"message": "サービスを選択"
},
@@ -586,10 +604,14 @@
"message": "ETHの送信"
},
"sendTokens": {
- "message": "トークンを送る"
+ "message": "トークンを送信"
},
"onlySendToEtherAddress": {
- "message": "ETHはイーサリウムアカウントのみに送信できます。"
+ "message": "ETH はイーサリウムアカウントのみに送信できます。"
+ },
+ "onlySendTokensToAccountAddress": {
+ "message": "$1 はイーサリアムアカウントのみに送信できます。",
+ "description": "displays token symbol"
},
"searchTokens": {
"message": "トークンの検索"
@@ -690,10 +712,10 @@
"message": "パスワードの入力"
},
"uiWelcome": {
- "message": "新UIへようこそ!(ベータ版)"
+ "message": "新UIへようこそ! (ベータ版)"
},
"uiWelcomeMessage": {
- "message": "現在Metamaskの新しいUIをお使いになっています。トークン送信など、新たな機能を試してみましょう!何か問題があればご報告ください。"
+ "message": "現在、MetaMask の新しいUIをお使いになっています。トークン送信など、新たな機能を試してみましょう! 何か問題があればご報告ください。"
},
"unavailable": {
"message": "有効ではありません。"
@@ -720,6 +742,9 @@
"viewAccount": {
"message": "アカウントを見る"
},
+ "viewOnEtherscan": {
+ "message": "Etherscan で見る"
+ },
"warning": {
"message": "警告"
},
diff --git a/app/images/ethereum-metamask-chrome.png b/app/images/ethereum-metamask-chrome.png
new file mode 100644
index 000000000..0b886babb
--- /dev/null
+++ b/app/images/ethereum-metamask-chrome.png
Binary files differ
diff --git a/app/manifest.json b/app/manifest.json
index 52256c5b7..ed328f19f 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -67,7 +67,8 @@
"notifications"
],
"web_accessible_resources": [
- "inpage.js"
+ "inpage.js",
+ "phishing.html"
],
"externally_connectable": {
"matches": [
diff --git a/app/phishing.html b/app/phishing.html
new file mode 100644
index 000000000..86f2985cc
--- /dev/null
+++ b/app/phishing.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+
+<html>
+
+ <head>
+ <title>Phishing Warning</title>
+
+ <style>
+body {
+ background: #c50000;
+ padding: 50px;
+ display: flex;
+ justify-content: center;
+ font-family: sans-serif;
+}
+.centered {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ color: white;
+ max-width: 600px;
+}
+a {
+ color: white;
+}
+ </style>
+
+ <script>
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
+ ga('create', 'UA-37075177-6', 'auto');
+ ga('send', 'pageview');
+ //Send referral data to EAL
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
+ ga('create', 'UA-68598031-1', 'auto' {'allowLinker':true});
+ ga('send', 'pageview');
+ ga('require', 'linker');
+ ga('linker:autoLink', ['harrydenley.com', 'metamask.io'], false, true);
+ </script>
+
+ </head>
+
+ <body>
+ <div class="centered">
+
+ <img src="/images/ethereum-metamask-chrome.png" style="width:100%">
+ <h3>ATTENTION</h3>
+ <p>MetaMask believes this domain to have malicious intent and has prevented you from interacting with it.</p>
+ <p>This is because the site tested positive on the <a href="https://github.com/metamask/eth-phishing-detect">Ethereum Phishing Detector</a>.</p>
+ <p>You can turn MetaMask off to interact with this site, but it's advised not to.</p>
+ <p>If you think this domain is incorrectly flagged, <a href="https://github.com/metamask/eth-phishing-detect/issues/new">please file an issue</a>.</p>
+
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js
index 7b7114c35..b7496f318 100644
--- a/app/scripts/contentscript.js
+++ b/app/scripts/contentscript.js
@@ -197,6 +197,7 @@ function blacklistedDomainCheck () {
* Redirects the current page to a phishing information page
*/
function redirectToPhishingWarning () {
- console.log('MetaMask - redirecting to phishing warning')
- window.location.href = 'https://metamask.io/phishing.html'
+ console.log('MetaMask - routing to Phishing Warning component')
+ let extensionURL = extension.runtime.getURL('phishing.html')
+ window.location.href = extensionURL
}
diff --git a/app/scripts/controllers/transactions/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js
index 9bf2ae1e2..3dd45507f 100644
--- a/app/scripts/controllers/transactions/tx-gas-utils.js
+++ b/app/scripts/controllers/transactions/tx-gas-utils.js
@@ -30,14 +30,10 @@ class TxGasUtil {
try {
estimatedGasHex = await this.estimateTxGas(txMeta, block.gasLimit)
} catch (err) {
- const simulationFailed = (
- err.message.includes('Transaction execution error.') ||
- err.message.includes('gas required exceeds allowance or always failing transaction')
- )
- if (simulationFailed) {
- txMeta.simulationFails = true
- return txMeta
+ txMeta.simulationFails = {
+ reason: err.message,
}
+ return txMeta
}
this.setTxGas(txMeta, block.gasLimit, estimatedGasHex)
return txMeta
diff --git a/app/scripts/lib/inpage-provider.js b/app/scripts/lib/inpage-provider.js
index 4e65f0a23..6ef511453 100644
--- a/app/scripts/lib/inpage-provider.js
+++ b/app/scripts/lib/inpage-provider.js
@@ -54,6 +54,11 @@ function MetamaskInpageProvider (connectionStream) {
// also remap ids inbound and outbound
MetamaskInpageProvider.prototype.sendAsync = function (payload, cb) {
const self = this
+
+ if (payload.method === 'eth_signTypedData') {
+ console.warn('MetaMask: This experimental version of eth_signTypedData will be deprecated in the next release in favor of the standard as defined in EIP-712. See https://git.io/fNzPl for more information on the new standard.')
+ }
+
self.rpcEngine.handle(payload, cb)
}
diff --git a/mascara/src/app/first-time/index.js b/mascara/src/app/first-time/index.js
index dc254bb19..6e4dc74bb 100644
--- a/mascara/src/app/first-time/index.js
+++ b/mascara/src/app/first-time/index.js
@@ -3,7 +3,6 @@ import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import { withRouter, Switch, Route } from 'react-router-dom'
import { compose } from 'recompose'
-import classnames from 'classnames'
import CreatePasswordScreen from './create-password-screen'
import UniqueImageScreen from './unique-image-screen'
@@ -44,28 +43,9 @@ class FirstTimeFlow extends Component {
noActiveNotices: false,
};
- renderAppBar () {
- const { welcomeScreenSeen } = this.props
-
- return (
- <div className="alpha-warning__container">
- <h2 className={classnames({
- 'alpha-warning': welcomeScreenSeen,
- 'alpha-warning-welcome-screen': !welcomeScreenSeen,
- })}
- >
- Please be aware that this version is still under development
- </h2>
- </div>
- )
- }
-
render () {
- const { isPopup } = this.props
-
return (
<div className="flex-column flex-grow">
- { !isPopup && this.renderAppBar() }
<div className="first-time-flow">
<Switch>
<Route exact path={INITIALIZE_IMPORT_ACCOUNT_ROUTE} component={ImportAccountScreen} />
diff --git a/old-ui/app/account-qr.js b/old-ui/app/account-qr.js
new file mode 100644
index 000000000..b41cc5112
--- /dev/null
+++ b/old-ui/app/account-qr.js
@@ -0,0 +1,86 @@
+const PropTypes = require('prop-types')
+const {PureComponent} = require('react')
+const h = require('react-hyperscript')
+const {qrcode: qrCode} = require('qrcode-npm')
+const {connect} = require('react-redux')
+const {isHexPrefixed} = require('ethereumjs-util')
+const actions = require('../../ui/app/actions')
+const CopyButton = require('./components/copyButton')
+
+class AccountQrScreen extends PureComponent {
+ static defaultProps = {
+ warning: null,
+ }
+
+ static propTypes = {
+ dispatch: PropTypes.func.isRequired,
+ buyView: PropTypes.any.isRequired,
+ Qr: PropTypes.object.isRequired,
+ selectedAddress: PropTypes.string.isRequired,
+ warning: PropTypes.node,
+ }
+
+ render () {
+ const {dispatch, Qr, selectedAddress, warning} = this.props
+ const address = `${isHexPrefixed(Qr.data) ? 'ethereum:' : ''}${Qr.data}`
+ const qrImage = qrCode(4, 'M')
+
+ qrImage.addData(address)
+ qrImage.make()
+
+ return h('div.flex-column.full-width', {
+ style: {
+ alignItems: 'center',
+ boxSizing: 'border-box',
+ padding: '50px',
+ },
+ }, [
+ h('div.flex-row.full-width', {
+ style: {
+ alignItems: 'flex-start',
+ },
+ }, [
+ h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', {
+ onClick () {
+ dispatch(actions.backToAccountDetail(selectedAddress))
+ },
+ }),
+ ]),
+ h('div.qr-header', Qr.message),
+ warning && h('span.error.flex-center', {
+ style: {
+ textAlign: 'center',
+ width: '229px',
+ height: '82px',
+ },
+ }, [
+ this.props.warning,
+ ]),
+ h('div#qr-container.flex-column', {
+ style: {
+ marginTop: '25px',
+ marginBottom: '15px',
+ },
+ dangerouslySetInnerHTML: {
+ __html: qrImage.createTableTag(4),
+ },
+ }),
+ h('div.flex-row.full-width', [
+ h('h3.ellip-address.grow-tenx', Qr.data),
+ h(CopyButton, {
+ value: Qr.data,
+ }),
+ ]),
+ ])
+ }
+}
+
+function mapStateToProps (state) {
+ return {
+ Qr: state.appState.Qr,
+ buyView: state.appState.buyView,
+ warning: state.appState.warning,
+ }
+}
+
+module.exports = connect(mapStateToProps)(AccountQrScreen)
diff --git a/old-ui/app/app.js b/old-ui/app/app.js
index 0637e3b5b..d3e9e823b 100644
--- a/old-ui/app/app.js
+++ b/old-ui/app/app.js
@@ -14,6 +14,7 @@ const NewKeyChainScreen = require('./new-keychain')
const UnlockScreen = require('./unlock')
// accounts
const AccountDetailScreen = require('./account-detail')
+const AccountQrScreen = require('./account-qr')
const SendTransactionScreen = require('./send')
const ConfirmTxScreen = require('./conf-tx')
// notice
@@ -24,17 +25,13 @@ const ConfigScreen = require('./config')
const AddTokenScreen = require('./add-token')
const Import = require('./accounts/import')
const InfoScreen = require('./info')
+const NewUiAnnouncement = require('./new-ui-annoucement')
+const AppBar = require('./components/app-bar')
const Loading = require('./components/loading')
-const SandwichExpando = require('sandwich-expando')
-const Dropdown = require('./components/dropdown').Dropdown
-const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem
-const NetworkIndicator = require('./components/network')
const BuyView = require('./components/buy-button-subview')
-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 AccountDropdowns = require('./components/account-dropdowns').AccountDropdowns
module.exports = connect(mapStateToProps)(App)
@@ -86,13 +83,29 @@ function mapStateToProps (state) {
}
App.prototype.render = function () {
- var props = this.props
- const { isLoading, loadingMessage, transForward, network } = props
- const isLoadingNetwork = network === 'loading' && props.currentView.name !== 'config'
- const loadMessage = loadingMessage || isLoadingNetwork ?
- `Connecting to ${this.getNetworkName()}` : null
+ const {
+ currentView,
+ dispatch,
+ isLoading,
+ loadingMessage,
+ transForward,
+ network,
+ featureFlags,
+ } = this.props
+ const isLoadingNetwork = network === 'loading' && currentView.name !== 'config'
+ const loadMessage = loadingMessage || isLoadingNetwork
+ ? `Connecting to ${this.getNetworkName()}`
+ : null
log.debug('Main ui render function')
+ if (!featureFlags.skipAnnounceBetaUI) {
+ return (
+ h(NewUiAnnouncement, {
+ dispatch,
+ })
+ )
+ }
+
return (
h('.flex-column.full-height', {
style: {
@@ -102,12 +115,9 @@ App.prototype.render = function () {
alignItems: 'center',
},
}, [
-
- // app bar
- this.renderAppBar(),
- this.renderNetworkDropdown(),
- this.renderDropdown(),
-
+ h(AppBar, {
+ ...this.props,
+ }),
this.renderLoadingIndicator({ isLoading, isLoadingNetwork, loadMessage }),
// panel content
@@ -121,299 +131,6 @@ App.prototype.render = function () {
])
)
}
-
-App.prototype.renderAppBar = function () {
- if (window.METAMASK_UI_TYPE === 'notification') {
- return null
- }
-
- const props = this.props
- const state = this.state || {}
- const isNetworkMenuOpen = state.isNetworkMenuOpen || false
- const {isMascara, isOnboarding} = props
-
- // Do not render header if user is in mascara onboarding
- if (isMascara && isOnboarding) {
- return null
- }
-
- // Do not render header if user is in mascara buy ether
- if (isMascara && props.currentView.name === 'buyEth') {
- return null
- }
-
- return (
-
- h('.full-width', {
- height: '38px',
- }, [
-
- h('.app-header.flex-row.flex-space-between', {
- style: {
- alignItems: 'center',
- visibility: props.isUnlocked ? 'visible' : 'none',
- background: props.isUnlocked ? 'white' : 'none',
- height: '38px',
- position: 'relative',
- zIndex: 12,
- },
- }, [
-
- h('div.left-menu-section', {
- style: {
- display: 'flex',
- flexDirection: 'row',
- alignItems: 'center',
- },
- }, [
-
- // mini logo
- h('img', {
- height: 24,
- width: 24,
- src: './images/icon-128.png',
- }),
-
- h(NetworkIndicator, {
- network: this.props.network,
- provider: this.props.provider,
- onClick: (event) => {
- event.preventDefault()
- event.stopPropagation()
- this.setState({ isNetworkMenuOpen: !isNetworkMenuOpen })
- },
- }),
-
- ]),
-
- props.isUnlocked && h('div', {
- style: {
- display: 'flex',
- flexDirection: 'row',
- alignItems: 'center',
- },
- }, [
-
- props.isUnlocked && h(AccountDropdowns, {
- style: {},
- enableAccountsSelector: true,
- identities: this.props.identities,
- selected: this.props.selectedAddress,
- network: this.props.network,
- keyrings: this.props.keyrings,
- }, []),
-
- // hamburger
- props.isUnlocked && h(SandwichExpando, {
- className: 'sandwich-expando',
- width: 16,
- barHeight: 2,
- padding: 0,
- isOpen: state.isMainMenuOpen,
- color: 'rgb(247,146,30)',
- onClick: () => {
- this.setState({
- isMainMenuOpen: !state.isMainMenuOpen,
- })
- },
- }),
- ]),
- ]),
- ])
- )
-}
-
-App.prototype.renderNetworkDropdown = function () {
- const props = this.props
- const { provider: { type: providerType, rpcTarget: activeNetwork } } = props
- const rpcList = props.frequentRpcList
- const state = this.state || {}
- const isOpen = state.isNetworkMenuOpen
-
- return h(Dropdown, {
- useCssTransition: true,
- isOpen,
- onClickOutside: (event) => {
- const { classList } = event.target
- const isNotToggleElement = [
- classList.contains('menu-icon'),
- classList.contains('network-name'),
- classList.contains('network-indicator'),
- ].filter(bool => bool).length === 0
- // classes from three constituent nodes of the toggle element
-
- if (isNotToggleElement) {
- this.setState({ isNetworkMenuOpen: false })
- }
- },
- zIndex: 11,
- style: {
- position: 'absolute',
- left: '2px',
- top: '36px',
- },
- innerStyle: {
- padding: '2px 16px 2px 0px',
- },
- }, [
-
- h(
- DropdownMenuItem,
- {
- key: 'main',
- closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
- onClick: () => props.dispatch(actions.setProviderType('mainnet')),
- style: {
- fontSize: '18px',
- },
- },
- [
- h('.menu-icon.diamond'),
- 'Main Ethereum Network',
- providerType === 'mainnet' ? h('.check', '✓') : null,
- ]
- ),
-
- h(
- DropdownMenuItem,
- {
- key: 'ropsten',
- closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
- onClick: () => props.dispatch(actions.setProviderType('ropsten')),
- style: {
- fontSize: '18px',
- },
- },
- [
- h('.menu-icon.red-dot'),
- 'Ropsten Test Network',
- providerType === 'ropsten' ? h('.check', '✓') : null,
- ]
- ),
-
- h(
- DropdownMenuItem,
- {
- key: 'kovan',
- closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
- onClick: () => props.dispatch(actions.setProviderType('kovan')),
- style: {
- fontSize: '18px',
- },
- },
- [
- h('.menu-icon.hollow-diamond'),
- 'Kovan Test Network',
- providerType === 'kovan' ? h('.check', '✓') : null,
- ]
- ),
-
- h(
- DropdownMenuItem,
- {
- key: 'rinkeby',
- closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
- onClick: () => props.dispatch(actions.setProviderType('rinkeby')),
- style: {
- fontSize: '18px',
- },
- },
- [
- h('.menu-icon.golden-square'),
- 'Rinkeby Test Network',
- providerType === 'rinkeby' ? h('.check', '✓') : null,
- ]
- ),
-
- h(
- DropdownMenuItem,
- {
- key: 'default',
- closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
- onClick: () => props.dispatch(actions.setProviderType('localhost')),
- style: {
- fontSize: '18px',
- },
- },
- [
- h('i.fa.fa-question-circle.fa-lg.menu-icon'),
- 'Localhost 8545',
- activeNetwork === 'http://localhost:8545' ? h('.check', '✓') : null,
- ]
- ),
-
- this.renderCustomOption(props.provider),
- this.renderCommonRpc(rpcList, props.provider),
-
- h(
- DropdownMenuItem,
- {
- closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
- onClick: () => this.props.dispatch(actions.showConfigPage()),
- style: {
- fontSize: '18px',
- },
- },
- [
- h('i.fa.fa-question-circle.fa-lg.menu-icon'),
- 'Custom RPC',
- activeNetwork === 'custom' ? h('.check', '✓') : null,
- ]
- ),
-
- ])
-}
-
-App.prototype.renderDropdown = function () {
- const state = this.state || {}
- const isOpen = state.isMainMenuOpen
-
- return h(Dropdown, {
- useCssTransition: true,
- isOpen: isOpen,
- zIndex: 11,
- onClickOutside: (event) => {
- const classList = event.target.classList
- const parentClassList = event.target.parentElement.classList
-
- const isToggleElement = classList.contains('sandwich-expando') ||
- parentClassList.contains('sandwich-expando')
-
- if (isOpen && !isToggleElement) {
- this.setState({ isMainMenuOpen: false })
- }
- },
- style: {
- position: 'absolute',
- right: '2px',
- top: '38px',
- },
- innerStyle: {},
- }, [
- h(DropdownMenuItem, {
- closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
- onClick: () => { this.props.dispatch(actions.showConfigPage()) },
- }, 'Settings'),
-
- h(DropdownMenuItem, {
- closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
- onClick: () => { this.props.dispatch(actions.lockMetamask()) },
- }, 'Log Out'),
-
- h(DropdownMenuItem, {
- closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
- onClick: () => { this.props.dispatch(actions.showInfoPage()) },
- }, 'Info/Help'),
-
- h(DropdownMenuItem, {
- closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
- onClick: () => {
- this.props.dispatch(actions.setFeatureFlag('betaUI', true, 'BETA_UI_NOTIFICATION_MODAL'))
- },
- }, 'Try Beta!'),
- ])
-}
-
App.prototype.renderLoadingIndicator = function ({ isLoading, isLoadingNetwork, loadMessage }) {
const { isMascara } = this.props
@@ -425,25 +142,6 @@ App.prototype.renderLoadingIndicator = function ({ isLoading, isLoadingNetwork,
})
}
-App.prototype.renderBackButton = function (style, justArrow = false) {
- var props = this.props
- return (
- h('.flex-row', {
- key: 'leftArrow',
- style: style,
- onClick: () => props.dispatch(actions.goBackToInitView()),
- }, [
- h('i.fa.fa-arrow-left.cursor-pointer'),
- justArrow ? null : h('div.cursor-pointer', {
- style: {
- marginLeft: '3px',
- },
- onClick: () => props.dispatch(actions.goBackToInitView()),
- }, 'BACK'),
- ])
- )
-}
-
App.prototype.renderPrimary = function () {
log.debug('rendering primary')
var props = this.props
@@ -465,22 +163,6 @@ App.prototype.renderPrimary = function () {
key: 'NoticeScreen',
onConfirm: () => props.dispatch(actions.markNoticeRead(props.nextUnreadNotice)),
}),
-
- !props.isInitialized && h('.flex-row.flex-center.flex-grow', [
- h('p.pointer', {
- onClick: () => {
- global.platform.openExtensionInBrowser()
- props.dispatch(actions.setFeatureFlag('betaUI', true, 'BETA_UI_NOTIFICATION_MODAL'))
- },
- style: {
- fontSize: '0.8em',
- color: '#aeaeae',
- textDecoration: 'underline',
- marginTop: '32px',
- },
- }, 'Try Beta Version'),
- ]),
-
])
} else if (props.lostAccounts && props.lostAccounts.length > 0) {
log.debug('rendering notice screen for lost accounts view.')
@@ -580,31 +262,10 @@ App.prototype.renderPrimary = function () {
case 'qr':
log.debug('rendering show qr screen')
- return h('div', {
- style: {
- position: 'absolute',
- height: '100%',
- top: '0px',
- left: '0px',
- },
- }, [
- h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', {
- onClick: () => props.dispatch(actions.backToAccountDetail(props.selectedAddress)),
- style: {
- marginLeft: '10px',
- marginTop: '50px',
- },
- }),
- h('div', {
- style: {
- position: 'absolute',
- left: '44px',
- width: '285px',
- },
- }, [
- h(QrView, {key: 'qr'}),
- ]),
- ])
+ return h(AccountQrScreen, {
+ key: 'account-qr',
+ selectedAddress: props.selectedAddress,
+ })
default:
log.debug('rendering default, account detail screen')
@@ -623,41 +284,6 @@ App.prototype.toggleMetamaskActive = function () {
this.props.dispatch(actions.lockMetamask(false))
}
}
-
-App.prototype.renderCustomOption = function (provider) {
- const { rpcTarget, type } = provider
- const props = this.props
-
- if (type !== 'rpc') return null
-
- // Concatenate long URLs
- let label = rpcTarget
- if (rpcTarget.length > 31) {
- label = label.substr(0, 34) + '...'
- }
-
- switch (rpcTarget) {
-
- case 'http://localhost:8545':
- return null
-
- default:
- return h(
- DropdownMenuItem,
- {
- key: rpcTarget,
- onClick: () => props.dispatch(actions.setRpcTarget(rpcTarget)),
- closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
- },
- [
- h('i.fa.fa-question-circle.fa-lg.menu-icon'),
- label,
- h('.check', '✓'),
- ]
- )
- }
-}
-
App.prototype.getNetworkName = function () {
const { provider } = this.props
const providerName = provider.type
@@ -678,28 +304,3 @@ App.prototype.getNetworkName = function () {
return name
}
-
-App.prototype.renderCommonRpc = function (rpcList, provider) {
- const props = this.props
- const rpcTarget = provider.rpcTarget
-
- return rpcList.map((rpc) => {
- if ((rpc === 'http://localhost:8545') || (rpc === rpcTarget)) {
- return null
- } else {
- return h(
- DropdownMenuItem,
- {
- key: `common${rpc}`,
- closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
- onClick: () => props.dispatch(actions.setRpcTarget(rpc)),
- },
- [
- h('i.fa.fa-question-circle.fa-lg.menu-icon'),
- rpc,
- rpcTarget === rpc ? h('.check', '✓') : null,
- ]
- )
- }
- })
-}
diff --git a/old-ui/app/components/app-bar.js b/old-ui/app/components/app-bar.js
new file mode 100644
index 000000000..8ab647efd
--- /dev/null
+++ b/old-ui/app/components/app-bar.js
@@ -0,0 +1,432 @@
+const PropTypes = require('prop-types')
+const {Component} = require('react')
+const h = require('react-hyperscript')
+const actions = require('../../../ui/app/actions')
+const SandwichExpando = require('sandwich-expando')
+const {Dropdown} = require('./dropdown')
+const {DropdownMenuItem} = require('./dropdown')
+const NetworkIndicator = require('./network')
+const {AccountDropdowns} = require('./account-dropdowns')
+
+const LOCALHOST_RPC_URL = 'http://localhost:8545'
+
+module.exports = class AppBar extends Component {
+ static defaultProps = {
+ selectedAddress: undefined,
+ }
+
+ static propTypes = {
+ dispatch: PropTypes.func.isRequired,
+ frequentRpcList: PropTypes.array.isRequired,
+ isMascara: PropTypes.bool.isRequired,
+ isOnboarding: PropTypes.bool.isRequired,
+ identities: PropTypes.any.isRequired,
+ selectedAddress: PropTypes.string,
+ isUnlocked: PropTypes.bool.isRequired,
+ network: PropTypes.any.isRequired,
+ keyrings: PropTypes.any.isRequired,
+ provider: PropTypes.any.isRequired,
+ }
+
+ static renderSpace () {
+ return (
+ h('span', {
+ dangerouslySetInnerHTML: {
+ __html: '&nbsp;',
+ },
+ })
+ )
+ }
+
+ state = {
+ isNetworkMenuOpen: false,
+ }
+
+ renderAppBar () {
+ if (window.METAMASK_UI_TYPE === 'notification') {
+ return null
+ }
+
+ const props = this.props
+ const {isMascara, isOnboarding} = props
+
+ // Do not render header if user is in mascara onboarding
+ if (isMascara && isOnboarding) {
+ return null
+ }
+
+ // Do not render header if user is in mascara buy ether
+ if (isMascara && props.currentView.name === 'buyEth') {
+ return null
+ }
+
+ return (
+ h('div.app-bar', [
+ this.renderAppBarNewUiNotice(),
+ this.renderAppBarAppHeader(),
+ ])
+ )
+ }
+
+ renderAppBarNewUiNotice () {
+ const {dispatch} = this.props
+
+ return (
+ h('div.app-bar__new-ui-banner', {
+ style: {
+ height: '28px',
+ zIndex: 12,
+ },
+ }, [
+ 'Try the New MetaMask',
+ AppBar.renderSpace(),
+ h('span.banner__link', {
+ async onClick () {
+ await dispatch(actions.setFeatureFlag('betaUI', true))
+ global.platform.openExtensionInBrowser()
+ },
+ }, [
+ 'Now',
+ ]),
+ AppBar.renderSpace(),
+ 'or',
+ AppBar.renderSpace(),
+ h('span.banner__link', {
+ onClick () {
+ global.platform.openWindow({
+ url: 'https://medium.com/metamask/74dba32cc7f7',
+ })
+ },
+ }, [
+ 'Learn More',
+ ]),
+ ])
+ )
+ }
+
+ renderAppBarAppHeader () {
+ const {
+ identities,
+ selectedAddress,
+ isUnlocked,
+ network,
+ keyrings,
+ provider,
+ } = this.props
+ const {
+ isNetworkMenuOpen,
+ isMainMenuOpen,
+ } = this.state
+
+ return (
+ h('.full-width', {
+ style: {
+ display: 'flex',
+ flexDirection: 'column',
+ height: '38px',
+ },
+ }, [
+ h('.app-header.flex-row.flex-space-between', {
+ style: {
+ alignItems: 'center',
+ visibility: isUnlocked ? 'visible' : 'none',
+ background: isUnlocked ? 'white' : 'none',
+ height: '38px',
+ position: 'relative',
+ zIndex: 12,
+ },
+ }, [
+ h('div.left-menu-section', {
+ style: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ }, [
+ // mini logo
+ h('img', {
+ height: 24,
+ width: 24,
+ src: './images/icon-128.png',
+ }),
+ h(NetworkIndicator, {
+ network: network,
+ provider: provider,
+ onClick: (event) => {
+ event.preventDefault()
+ event.stopPropagation()
+ this.setState({ isNetworkMenuOpen: !isNetworkMenuOpen })
+ },
+ }),
+ ]),
+ isUnlocked && h('div', {
+ style: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ }, [
+ h(AccountDropdowns, {
+ style: {},
+ enableAccountsSelector: true,
+ identities: identities,
+ selected: selectedAddress,
+ network,
+ keyrings,
+ }, []),
+ h(SandwichExpando, {
+ className: 'sandwich-expando',
+ width: 16,
+ barHeight: 2,
+ padding: 0,
+ isOpen: isMainMenuOpen,
+ color: 'rgb(247,146,30)',
+ onClick: () => {
+ this.setState({
+ isMainMenuOpen: !isMainMenuOpen,
+ })
+ },
+ }),
+ ]),
+ ]),
+ ])
+ )
+ }
+
+ renderNetworkDropdown () {
+ const {
+ dispatch,
+ frequentRpcList: rpcList,
+ provider,
+ } = this.props
+ const {
+ type: providerType,
+ rpcTarget: activeNetwork,
+ } = provider
+ const isOpen = this.state.isNetworkMenuOpen
+
+ return h(Dropdown, {
+ useCssTransition: true,
+ isOpen,
+ onClickOutside: (event) => {
+ const { classList } = event.target
+ const isNotToggleElement = [
+ classList.contains('menu-icon'),
+ classList.contains('network-name'),
+ classList.contains('network-indicator'),
+ ].filter(bool => bool).length === 0
+ // classes from three constituent nodes of the toggle element
+
+ if (isNotToggleElement) {
+ this.setState({ isNetworkMenuOpen: false })
+ }
+ },
+ zIndex: 11,
+ style: {
+ position: 'absolute',
+ left: '2px',
+ top: '64px',
+ },
+ innerStyle: {
+ padding: '2px 16px 2px 0px',
+ },
+ }, [
+ h(DropdownMenuItem, {
+ key: 'main',
+ closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
+ onClick: () => dispatch(actions.setProviderType('mainnet')),
+ style: {
+ fontSize: '18px',
+ },
+ }, [
+ h('.menu-icon.diamond'),
+ 'Main Ethereum Network',
+ providerType === 'mainnet'
+ ? h('.check', '✓')
+ : null,
+ ]),
+ h(DropdownMenuItem, {
+ key: 'ropsten',
+ closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
+ onClick: () => dispatch(actions.setProviderType('ropsten')),
+ style: {
+ fontSize: '18px',
+ },
+ }, [
+ h('.menu-icon.red-dot'),
+ 'Ropsten Test Network',
+ providerType === 'ropsten'
+ ? h('.check', '✓')
+ : null,
+ ]),
+ h(DropdownMenuItem, {
+ key: 'kovan',
+ closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
+ onClick: () => dispatch(actions.setProviderType('kovan')),
+ style: {
+ fontSize: '18px',
+ },
+ }, [
+ h('.menu-icon.hollow-diamond'),
+ 'Kovan Test Network',
+ providerType === 'kovan'
+ ? h('.check', '✓')
+ : null,
+ ]),
+ h(DropdownMenuItem, {
+ key: 'rinkeby',
+ closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
+ onClick: () => dispatch(actions.setProviderType('rinkeby')),
+ style: {
+ fontSize: '18px',
+ },
+ }, [
+ h('.menu-icon.golden-square'),
+ 'Rinkeby Test Network',
+ providerType === 'rinkeby'
+ ? h('.check', '✓')
+ : null,
+ ]),
+ h(DropdownMenuItem, {
+ key: 'default',
+ closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
+ onClick: () => dispatch(actions.setProviderType('localhost')),
+ style: {
+ fontSize: '18px',
+ },
+ }, [
+ h('i.fa.fa-question-circle.fa-lg.menu-icon'),
+ 'Localhost 8545',
+ activeNetwork === LOCALHOST_RPC_URL
+ ? h('.check', '✓')
+ : null,
+ ]),
+
+ this.renderCustomOption(provider),
+ this.renderCommonRpc(rpcList, provider),
+
+ h(DropdownMenuItem, {
+ closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
+ onClick: () => dispatch(actions.showConfigPage()),
+ style: {
+ fontSize: '18px',
+ },
+ }, [
+ h('i.fa.fa-question-circle.fa-lg.menu-icon'),
+ 'Custom RPC',
+ activeNetwork === 'custom'
+ ? h('.check', '✓')
+ : null,
+ ]),
+ ])
+ }
+
+ renderCustomOption ({ rpcTarget, type }) {
+ const {dispatch} = this.props
+
+ if (type !== 'rpc') {
+ return null
+ }
+
+ // Concatenate long URLs
+ let label = rpcTarget
+ if (rpcTarget.length > 31) {
+ label = label.substr(0, 34) + '...'
+ }
+
+ switch (rpcTarget) {
+ case LOCALHOST_RPC_URL:
+ return null
+ default:
+ return h(DropdownMenuItem, {
+ key: rpcTarget,
+ onClick: () => dispatch(actions.setRpcTarget(rpcTarget)),
+ closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
+ }, [
+ h('i.fa.fa-question-circle.fa-lg.menu-icon'),
+ label,
+ h('.check', '✓'),
+ ])
+ }
+ }
+
+ renderCommonRpc (rpcList, {rpcTarget}) {
+ const {dispatch} = this.props
+
+ return rpcList.map((rpc) => {
+ if ((rpc === LOCALHOST_RPC_URL) || (rpc === rpcTarget)) {
+ return null
+ } else {
+ return h(DropdownMenuItem, {
+ key: `common${rpc}`,
+ closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
+ onClick: () => dispatch(actions.setRpcTarget(rpc)),
+ }, [
+ h('i.fa.fa-question-circle.fa-lg.menu-icon'),
+ rpc,
+ rpcTarget === rpc
+ ? h('.check', '✓')
+ : null,
+ ])
+ }
+ })
+ }
+
+ renderDropdown () {
+ const {dispatch} = this.props
+ const isOpen = this.state.isMainMenuOpen
+
+ return h(Dropdown, {
+ useCssTransition: true,
+ isOpen: isOpen,
+ zIndex: 11,
+ onClickOutside: (event) => {
+ const classList = event.target.classList
+ const parentClassList = event.target.parentElement.classList
+
+ const isToggleElement = classList.contains('sandwich-expando') ||
+ parentClassList.contains('sandwich-expando')
+
+ if (isOpen && !isToggleElement) {
+ this.setState({ isMainMenuOpen: false })
+ }
+ },
+ style: {
+ position: 'absolute',
+ right: '2px',
+ top: '66px',
+ },
+ innerStyle: {},
+ }, [
+ h(DropdownMenuItem, {
+ closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
+ onClick: () => { dispatch(actions.showConfigPage()) },
+ }, 'Settings'),
+
+ h(DropdownMenuItem, {
+ closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
+ onClick: () => { dispatch(actions.lockMetamask()) },
+ }, 'Log Out'),
+
+ h(DropdownMenuItem, {
+ closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
+ onClick: () => { dispatch(actions.showInfoPage()) },
+ }, 'Info/Help'),
+
+ h(DropdownMenuItem, {
+ closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
+ onClick: () => {
+ dispatch(actions.setFeatureFlag('betaUI', true, 'BETA_UI_NOTIFICATION_MODAL'))
+ },
+ }, 'Try Beta!'),
+ ])
+ }
+
+ render () {
+ return h('div.full-width', [
+ this.renderAppBar(),
+ this.renderNetworkDropdown(),
+ this.renderDropdown(),
+ ])
+ }
+}
diff --git a/old-ui/app/components/qr-code.js b/old-ui/app/components/qr-code.js
deleted file mode 100644
index 06b9aed9b..000000000
--- a/old-ui/app/components/qr-code.js
+++ /dev/null
@@ -1,79 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const qrCode = require('qrcode-npm').qrcode
-const inherits = require('util').inherits
-const connect = require('react-redux').connect
-const isHexPrefixed = require('ethereumjs-util').isHexPrefixed
-const CopyButton = require('./copyButton')
-
-module.exports = connect(mapStateToProps)(QrCodeView)
-
-function mapStateToProps (state) {
- return {
- Qr: state.appState.Qr,
- buyView: state.appState.buyView,
- warning: state.appState.warning,
- }
-}
-
-inherits(QrCodeView, Component)
-
-function QrCodeView () {
- Component.call(this)
-}
-
-QrCodeView.prototype.render = function () {
- const props = this.props
- const Qr = props.Qr
- const address = `${isHexPrefixed(Qr.data) ? 'ethereum:' : ''}${Qr.data}`
- const qrImage = qrCode(4, 'M')
- qrImage.addData(address)
- qrImage.make()
- return h('.main-container.flex-column', {
- key: 'qr',
- style: {
- justifyContent: 'center',
- paddingBottom: '45px',
- paddingLeft: '45px',
- paddingRight: '45px',
- alignItems: 'center',
- },
- }, [
- Array.isArray(Qr.message) ? h('.message-container', this.renderMultiMessage()) : h('.qr-header', Qr.message),
-
- this.props.warning ? this.props.warning && h('span.error.flex-center', {
- style: {
- textAlign: 'center',
- width: '229px',
- height: '82px',
- },
- },
- this.props.warning) : null,
-
- h('#qr-container.flex-column', {
- style: {
- marginTop: '25px',
- marginBottom: '15px',
- },
- dangerouslySetInnerHTML: {
- __html: qrImage.createTableTag(4),
- },
- }),
- h('.flex-row', [
- h('h3.ellip-address', {
- style: {
- width: '247px',
- },
- }, Qr.data),
- h(CopyButton, {
- value: Qr.data,
- }),
- ]),
- ])
-}
-
-QrCodeView.prototype.renderMultiMessage = function () {
- var Qr = this.props.Qr
- var multiMessage = Qr.message.map((message) => h('.qr-message', message))
- return multiMessage
-}
diff --git a/old-ui/app/components/shapeshift-form.js b/old-ui/app/components/shapeshift-form.js
index 97068db0a..14de309ab 100644
--- a/old-ui/app/components/shapeshift-form.js
+++ b/old-ui/app/components/shapeshift-form.js
@@ -3,7 +3,6 @@ const h = require('react-hyperscript')
const inherits = require('util').inherits
const connect = require('react-redux').connect
const actions = require('../../../ui/app/actions')
-const Qr = require('./qr-code')
const isValidAddress = require('../util').isValidAddress
module.exports = connect(mapStateToProps)(ShapeshiftForm)
@@ -11,7 +10,6 @@ function mapStateToProps (state) {
return {
warning: state.appState.warning,
isSubLoading: state.appState.isSubLoading,
- qrRequested: state.appState.qrRequested,
}
}
@@ -23,7 +21,7 @@ function ShapeshiftForm () {
}
ShapeshiftForm.prototype.render = function () {
- return this.props.qrRequested ? h(Qr, {key: 'qr'}) : this.renderMain()
+ return this.renderMain()
}
ShapeshiftForm.prototype.renderMain = function () {
diff --git a/old-ui/app/components/transaction-list-item.js b/old-ui/app/components/transaction-list-item.js
index e9280419a..f479ce666 100644
--- a/old-ui/app/components/transaction-list-item.js
+++ b/old-ui/app/components/transaction-list-item.js
@@ -36,14 +36,23 @@ TransactionListItem.prototype.showRetryButton = function () {
return false
}
+ let currentTxIsLatest = false
const currentNonce = txParams.nonce
const currentNonceTxs = transactions.filter(tx => tx.txParams.nonce === currentNonce)
const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted')
+ const currentSubmittedTxs = transactions.filter(tx => tx.status === 'submitted')
const lastSubmittedTxWithCurrentNonce = currentNonceSubmittedTxs[0]
const currentTxIsLatestWithNonce = lastSubmittedTxWithCurrentNonce &&
lastSubmittedTxWithCurrentNonce.id === transaction.id
+ if (currentSubmittedTxs.length > 0) {
+ const lastTx = currentSubmittedTxs.reduce((tx1, tx2) => {
+ if (tx1.submittedTime < tx2.submittedTime) return tx1
+ return tx2
+ })
+ currentTxIsLatest = lastTx.id === transaction.id
+ }
- return currentTxIsLatestWithNonce && Date.now() - submittedTime > 30000
+ return currentTxIsLatestWithNonce && Date.now() - submittedTime > 30000 && currentTxIsLatest
}
TransactionListItem.prototype.render = function () {
diff --git a/old-ui/app/css/index.css b/old-ui/app/css/index.css
index 7af713336..d209b4754 100644
--- a/old-ui/app/css/index.css
+++ b/old-ui/app/css/index.css
@@ -720,7 +720,131 @@ div.message-container > div:first-child {
transform: scale(1.1);
}
-//Notification Modal
+.new-ui-announcement {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ background: white;
+ color: #4D4D4D;
+ font-family: Roboto, Arial, sans-serif;
+ padding: 1.5rem;
+}
+
+.new-ui-announcement__announcement-header {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ padding-bottom: 1rem;
+}
+
+.new-ui-announcement__announcement-header a.close {
+ cursor: pointer;
+ font-size: 32px;
+ line-height: 17px;
+}
+
+.new-ui-announcement__announcement-header a.close:hover {
+ color: inherit;
+}
+
+.new-ui-announcement__announcement-header h1 {
+ color: #33A4E7;
+ text-transform: uppercase;
+ font-size: 18px;
+ font-weight: 400;
+}
+
+.new-ui-announcement__body {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ font-size: 10.5pt;
+ font-weight: 300;
+}
+
+.new-ui-announcement__body h1 {
+ font-size: 22px;
+ font-weight: 600;
+ padding-bottom: 1rem;
+}
+
+.new-ui-announcement__body a {
+ color: #33A4E7;
+}
+
+.new-ui-announcement__body .updates-list {
+ padding: .5rem 1rem;
+}
+
+.new-ui-announcement__body .updates-list h2 {
+ font-weight: 600;
+}
+
+.new-ui-announcement__body .updates-list ul {
+ list-style: disc inside;
+}
+
+.new-ui-announcement__footer {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.new-ui-announcement__footer h1 {
+ font-family: inherit;
+ font-weight: 600;
+}
+
+.new-ui-announcement__footer button:hover {
+ transform: none;
+}
+
+.new-ui-announcement__footer button.positive {
+ padding: 1rem;
+ margin: 1rem;
+ background: #33A4E7;
+ color: white;
+ text-transform: uppercase;
+ box-shadow: none;
+ border-radius: 5px;
+ font-family: inherit;
+ font-size: 13px;
+ font-weight: 400;
+ width: 90%;
+}
+
+.new-ui-announcement__footer button.negative {
+ margin: 0;
+ padding: 0;
+ background: white;
+ color: #33A4E7;
+ font-family: inherit;
+ font-size: 13px;
+ font-weight: 400;
+ box-shadow: none;
+}
+
+.app-bar {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+}
+
+.app-bar__new-ui-banner {
+ background: #33A4E7;
+ color: white;
+ font-size: 12px;
+ line-height: 12px;
+ padding: 8px;
+ font-family: Roboto, Arial, sans-serif;
+ font-weight: 400;
+ width: 100%;
+}
+
+.banner__link {
+ cursor: pointer;
+ text-decoration: underline;
+}
.notification-modal-wrapper {
display: flex;
@@ -812,4 +936,4 @@ div.message-container > div:first-child {
.notification-modal__link {
color: #2f9ae0;
-} \ No newline at end of file
+}
diff --git a/old-ui/app/new-ui-annoucement.js b/old-ui/app/new-ui-annoucement.js
new file mode 100644
index 000000000..59b126279
--- /dev/null
+++ b/old-ui/app/new-ui-annoucement.js
@@ -0,0 +1,85 @@
+const PropTypes = require('prop-types')
+const {PureComponent} = require('react')
+const h = require('react-hyperscript')
+const actions = require('../../ui/app/actions')
+
+module.exports = class NewUiAnnouncement extends PureComponent {
+ static propTypes = {
+ dispatch: PropTypes.func.isRequired,
+ };
+
+ close = async () => {
+ await this.props.dispatch(actions.setFeatureFlag('skipAnnounceBetaUI', true))
+ }
+
+ switchToNewUi = async () => {
+ const flag = 'betaUI'
+ const enabled = true
+ await this.props.dispatch(actions.setFeatureFlag(
+ flag,
+ enabled,
+ ))
+ await this.close()
+ global.platform.openExtensionInBrowser()
+ }
+
+ render () {
+ return (
+ h('div.new-ui-announcement', [
+ h('section.new-ui-announcement__announcement-header', [
+ h('h1', 'Announcement'),
+ h('a.close', {
+ onClick: this.close,
+ }, '×'),
+ ]),
+ h('section.new-ui-announcement__body', [
+ h('h1', 'A New Version of MetaMask'),
+ h('p', [
+ "We're excited to announce a brand-new version of MetaMask with enhanced features and functionality.",
+ ]),
+ h('div.updates-list', [
+ h('h2', 'Updates include'),
+ h('ul', [
+ h('li', 'New user interface'),
+ h('li', 'Full-screen mode'),
+ h('li', 'Better token support'),
+ h('li', 'Better gas controls'),
+ h('li', 'Advanced features for developers'),
+ h('li', 'New confirmation screens'),
+ h('li', 'And more!'),
+ ]),
+ ]),
+ h('p', [
+ 'You can still use the current version of MetaMask. The new version is still in beta, ' +
+ 'however we encourage you to try it out as we transition into this exciting new update.',
+ h('span', {
+ dangerouslySetInnerHTML: {
+ __html: '&nbsp;',
+ },
+ }),
+ h('a', {
+ href: 'https://medium.com/metamask/74dba32cc7f7',
+ onClick ({target}) {
+ const url = target.href
+ global.platform.openWindow({
+ url,
+ })
+ },
+ }, [
+ 'Learn more.',
+ ]),
+ ]),
+ ]),
+ h('section.new-ui-announcement__footer', [
+ h('h1', 'Ready to try the new MetaMask?'),
+ h('button.positive', {
+ onClick: this.switchToNewUi,
+ }, 'Try it now'),
+ h('button.negative', {
+ onClick: this.close,
+ }, 'No thanks, maybe later'),
+ ]),
+ ])
+ )
+ }
+}
diff --git a/package-lock.json b/package-lock.json
index f1f12705d..6e8c0ed73 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2068,7 +2068,7 @@
"anymatch": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
- "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
+ "integrity": "sha1-VT3Lj5HjyImEXf26NMd3IbkLnXo=",
"requires": {
"micromatch": "^2.1.5",
"normalize-path": "^2.0.0"
@@ -2085,7 +2085,7 @@
"aproba": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
- "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+ "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo="
},
"arch": {
"version": "2.1.0",
@@ -2140,7 +2140,7 @@
"arr-flatten": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
- "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
+ "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE="
},
"arr-map": {
"version": "2.0.2",
@@ -2547,7 +2547,7 @@
"await-semaphore": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/await-semaphore/-/await-semaphore-0.1.3.tgz",
- "integrity": "sha512-d1W2aNSYcz/sxYO4pMGX9vq65qOTu0P800epMud+6cYYX0QcT7zyqcxec3VWzpgvdXo57UWmVbZpLMjX2m1I7Q=="
+ "integrity": "sha1-K4gBjMjCjgYWeuHN/wJQTx+WiNM="
},
"aws-sign2": {
"version": "0.7.0",
@@ -3864,7 +3864,7 @@
"babylon": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
- "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
+ "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM="
},
"bach": {
"version": "1.2.0",
@@ -4135,12 +4135,12 @@
"bindings": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz",
- "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw=="
+ "integrity": "sha1-s0b27PapX1qBXFg5/HzbIlAvHtc="
},
"bip39": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/bip39/-/bip39-2.4.0.tgz",
- "integrity": "sha512-1++HywqIyPtWDo7gm4v0ylYbwkLvHkuwVSKbBlZBbTCP/mnkyrlARBny906VLAwxJbC5xw9EvuJasHFIZaIFMQ==",
+ "integrity": "sha1-oLitvxY/U0lfAPBdnt58JTaczxM=",
"requires": {
"create-hash": "^1.1.0",
"pbkdf2": "^3.0.9",
@@ -4197,7 +4197,7 @@
"bn.js": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
- "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA=="
+ "integrity": "sha1-LN4J617jQfSEdGuwMJsyU7GxRC8="
},
"body-parser": {
"version": "1.18.2",
@@ -4550,7 +4550,7 @@
"browserify-aes": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz",
- "integrity": "sha512-UGnTYAnB2a3YuYKIRy1/4FB2HdM866E0qC46JXvVTYKlBlZlnvfpSfY6OKfXZAkv70eJ2a1SqzpAo5CRhZGDFg==",
+ "integrity": "sha1-OLerVe24Bv8tzaGn8WIHc6R3xJ8=",
"requires": {
"buffer-xor": "^1.0.3",
"cipher-base": "^1.0.0",
@@ -5186,7 +5186,7 @@
"cipher-base": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
- "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=",
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -6015,7 +6015,7 @@
"copy-to-clipboard": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz",
- "integrity": "sha512-c3GdeY8qxCHGezVb1EFQfHYK/8NZRemgcTIzPq7PuxjHAf/raKibn2QdhHPb/y6q74PMgH6yizaDZlRmw6QyKw==",
+ "integrity": "sha1-9OgvSogw3ORma3643tDJvMMTq6k=",
"requires": {
"toggle-selection": "^1.0.3"
}
@@ -6064,7 +6064,7 @@
"coveralls": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.0.tgz",
- "integrity": "sha512-ZppXR9y5PraUOrf/DzHJY6gzNUhXYE3b9D43xEXs4QYZ7/Oe0Gy0CS+IPKWFfvQFXB3RG9QduaQUFehzSpGAFw==",
+ "integrity": "sha1-Iu9zAzBTgIDSm4wVHckUav3oipk=",
"dev": true,
"requires": {
"js-yaml": "^3.6.1",
@@ -6710,7 +6710,7 @@
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
"requires": {
"ms": "2.0.0"
}
@@ -7188,7 +7188,7 @@
"disc": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/disc/-/disc-1.3.3.tgz",
- "integrity": "sha512-ui/kegr2k3tDr2EU7cA9Ag+YofgmB3shwSFJuuf6r6Epom2cyHhd5jBtCOhwXKSDFMlYEMeSadujjRS2uSqRsw==",
+ "integrity": "sha1-YdRVGAwqEVRou4UBWjPnGoL8AsI=",
"requires": {
"bl": "^1.2.0",
"browser-unpack": "^1.2.0",
@@ -7565,7 +7565,7 @@
"duplexify": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.1.tgz",
- "integrity": "sha512-j5goxHTwVED1Fpe5hh3q9R93Kip0Bg2KVAt4f8CEYM3UEwYcPSvWbXaUQOzdX/HtiNomipv+gU7ASQPDbV7pGQ==",
+ "integrity": "sha1-ThUWvmiDi8kKSZlPCzmm5ZYL780=",
"requires": {
"end-of-stream": "^1.0.0",
"inherits": "^2.0.1",
@@ -7814,7 +7814,7 @@
"envify": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/envify/-/envify-4.1.0.tgz",
- "integrity": "sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw==",
+ "integrity": "sha1-85rT251oAbTmtHi2ECjT8LaBn34=",
"dev": true,
"requires": {
"esprima": "^4.0.0",
@@ -8414,12 +8414,13 @@
"resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-2.0.1.tgz",
"integrity": "sha512-lxHZOQspexk3DaGj4RBbWy4C/qNOWRnxpaJzNnYD3WEmC8shcJ4tHs7Xv878rzvILfJnSFSCCiKQhng1m80oBQ==",
"requires": {
+ "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
"ethereumjs-util": "^5.1.1"
},
"dependencies": {
"ethereumjs-abi": {
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
- "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
+ "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
"requires": {
"bn.js": "^4.10.0",
"ethereumjs-util": "^5.0.0"
@@ -8783,7 +8784,7 @@
"eth-phishing-detect": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/eth-phishing-detect/-/eth-phishing-detect-1.1.12.tgz",
- "integrity": "sha512-wzEqAB4mUY0gkrn+ZOlzyxHmsouKT6rrzYIxy/FFalqoZVvX/9McPdFwWkHCYrv4KzTKgJJh8tKzvMnTae8Naw==",
+ "integrity": "sha1-PbfojHVFEMlOZzbbhRCLkOIn/kE=",
"requires": {
"fast-levenshtein": "^2.0.6"
}
@@ -8842,6 +8843,23 @@
"xtend": "^4.0.1"
},
"dependencies": {
+ "eth-sig-util": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz",
+ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
+ "requires": {
+ "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
+ "ethereumjs-util": "^5.1.1"
+ }
+ },
+ "ethereumjs-abi": {
+ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
+ "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
+ "requires": {
+ "bn.js": "^4.10.0",
+ "ethereumjs-util": "^5.0.0"
+ }
+ },
"ethereumjs-util": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz",
@@ -8888,7 +8906,7 @@
"eth-block-tracker": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-1.1.3.tgz",
- "integrity": "sha512-gDIknKCbY9npDA0JmBYCMDPLBj6GUe7xHYI2YTOQVuM8et6N2FxqrS1KhtThPWAeTgFPFkvyOj4eSBaJR0Oekg==",
+ "integrity": "sha1-xGoPK87ZtJuIx/ORiFbX7Ff73Ck=",
"requires": {
"async-eventemitter": "^0.2.2",
"babelify": "^7.3.0",
@@ -9835,7 +9853,7 @@
"evp_bytestokey": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
- "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+ "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=",
"requires": {
"md5.js": "^1.3.4",
"safe-buffer": "^5.1.1"
@@ -11480,14 +11498,12 @@
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
- "optional": true
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -11507,8 +11523,7 @@
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
- "optional": true
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"console-control-strings": {
"version": "1.1.0",
@@ -11644,7 +11659,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -11994,7 +12008,7 @@
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0="
},
"function.prototype.name": {
"version": "1.1.0",
@@ -13066,7 +13080,7 @@
"globals": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
- "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ=="
+ "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo="
},
"globby": {
"version": "5.0.0",
@@ -13195,13 +13209,13 @@
"dev": true
},
"gulp": {
- "version": "github:gulpjs/gulp#71c094a51c7972d26f557899ddecab0210ef3776",
+ "version": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed",
"from": "github:gulpjs/gulp#4.0",
"requires": {
- "glob-watcher": "^4.0.0",
- "gulp-cli": "^2.0.0",
+ "glob-watcher": "^3.0.0",
+ "gulp-cli": "^1.0.0",
"undertaker": "^1.0.0",
- "vinyl-fs": "^3.0.0"
+ "vinyl-fs": "^2.0.0"
},
"dependencies": {
"gulp-cli": {
@@ -13418,7 +13432,7 @@
"gulp-eslint": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-4.0.0.tgz",
- "integrity": "sha512-+qsePo04v1O3JshpNvww9+bOgZEJ6Cc2/w3mEktfKz0NL0zsh1SWzjyIL2FIM2zzy6IYQYv+j8REZORF8dKX4g==",
+ "integrity": "sha1-FtnqTWlue3qdZe6xqlvEugoix/c=",
"requires": {
"eslint": "^4.0.0",
"gulp-util": "^3.0.8"
@@ -14731,7 +14745,7 @@
"hash.js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
- "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
+ "integrity": "sha1-NA3tvmKQGHFRweodd3o0SJNd+EY=",
"requires": {
"inherits": "^2.0.3",
"minimalistic-assert": "^1.0.0"
@@ -15387,7 +15401,7 @@
"idb-global": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/idb-global/-/idb-global-2.1.0.tgz",
- "integrity": "sha512-tJPsvisI6A1xQ6y+orXavjgm/7O6v0YT4wKfw8rwv635pIhsc1Wi2ZhcS+6nYmpyyeaTBC/xG0MWcD9iwCD3xg==",
+ "integrity": "sha1-Kj4J0e2d86g21ZruqZv3QEe4zI0=",
"requires": {
"obs-store": "^2.4.1"
},
@@ -15418,7 +15432,7 @@
"identicon.js": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/identicon.js/-/identicon.js-2.3.1.tgz",
- "integrity": "sha512-PsxOTpq2Mwj2dgpHW50vcBdSebozcL9xKLIqRVkh2c4lqbCB75pkpdDKoKkVtTfpha/rl4BubXm3Q90vxlmUxQ=="
+ "integrity": "sha1-Dxag3V5h4aiWmUAMwZKvREVQbls="
},
"idna-uts46": {
"version": "1.1.0",
@@ -16160,7 +16174,7 @@
"is-plain-object": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
- "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=",
"requires": {
"isobject": "^3.0.1"
},
@@ -16786,7 +16800,7 @@
"escodegen": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.0.tgz",
- "integrity": "sha512-v0MYvNQ32bzwoG2OSFzWAkuahDQHK92JBN0pTAALJ4RIxEZe766QJPDR8Hqy7XNUy5K3fnVL76OqYAdc4TZEIw==",
+ "integrity": "sha1-mBGi8mXcHNOJRCDuNxcGS2MriFI=",
"dev": true,
"requires": {
"esprima": "^3.1.3",
@@ -16970,7 +16984,7 @@
"json-rpc-middleware-stream": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-rpc-middleware-stream/-/json-rpc-middleware-stream-1.0.1.tgz",
- "integrity": "sha512-IR6cOO6B21NdLpiYblueB3O+g3UAYLIZd6ZgZfddVPl0z6vSECcpuiYnV5MmIMJY3D0fLYpJqOxYaEmLYQqTtA==",
+ "integrity": "sha1-ybigBcgK8y5t+LuI5r3RMASEpO0=",
"requires": {
"end-of-stream": "^1.4.0",
"eth-block-tracker": "^2.1.2",
@@ -17828,7 +17842,7 @@
"karma-chrome-launcher": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz",
- "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==",
+ "integrity": "sha1-zxudBxNswY/iOTJ9JGVMPbw2is8=",
"dev": true,
"requires": {
"fs-access": "^1.0.0",
@@ -20150,7 +20164,7 @@
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -20299,7 +20313,7 @@
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
- "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
"dev": true,
"requires": {
"ms": "2.0.0"
@@ -20308,7 +20322,7 @@
"supports-color": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
- "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
+ "integrity": "sha1-iD992rwWUUKyphQn8zUt7RldGj4=",
"dev": true,
"requires": {
"has-flag": "^2.0.0"
@@ -20319,7 +20333,7 @@
"mocha-eslint": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/mocha-eslint/-/mocha-eslint-4.1.0.tgz",
- "integrity": "sha512-y+TIaoozAiuksnsr/7GVw7F2nAqotrZ06SHIw8wMR6PVWipXre5Hz59bsqLX1n2Lqu2YDebUX1A4qF/rtmWsYQ==",
+ "integrity": "sha1-0I66mGZffOTr7w0nw6I1QJ67uK0=",
"dev": true,
"requires": {
"chalk": "^1.1.0",
@@ -21137,7 +21151,7 @@
"npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
- "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=",
"requires": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
@@ -23426,7 +23440,7 @@
"pbkdf2": {
"version": "3.0.14",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz",
- "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==",
+ "integrity": "sha1-o14TxkeZsGzhUyD0WcIw5o5zut4=",
"requires": {
"create-hash": "^1.1.2",
"create-hmac": "^1.1.4",
@@ -25260,7 +25274,7 @@
"private": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
- "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg=="
+ "integrity": "sha1-I4Hts2ifelPWUxkAYPz4ItLzaP8="
},
"process": {
"version": "0.5.2",
@@ -25280,7 +25294,7 @@
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
- "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=",
"requires": {
"asap": "~2.0.3"
}
@@ -25593,7 +25607,7 @@
"qs": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
- "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
+ "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg="
},
"query-string": {
"version": "5.1.1",
@@ -25853,7 +25867,7 @@
"randombytes": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz",
- "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==",
+ "integrity": "sha1-3ACaJGuNCaF3tLegrne8Vw9LG3k=",
"requires": {
"safe-buffer": "^5.1.0"
}
@@ -25954,7 +25968,7 @@
"react-transition-group": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-1.2.1.tgz",
- "integrity": "sha512-CWaL3laCmgAFdxdKbhhps+c0HRGF4c+hdM4H23+FI1QBNUyx/AMeIJGWorehPNSaKnQNOAxL7PQmqMu78CDj3Q==",
+ "integrity": "sha1-4R9yslf5IbITIpp3TfRmEjRsfKY=",
"requires": {
"chain-function": "^1.0.0",
"dom-helpers": "^3.2.0",
@@ -26257,7 +26271,7 @@
"react-redux": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.6.tgz",
- "integrity": "sha512-8taaaGu+J7PMJQDJrk/xiWEYQmdo3mkXw6wPr3K3LxvXis3Fymiq7c13S+Tpls/AyNUAsoONkU81AP0RA6y6Vw==",
+ "integrity": "sha1-I+06T5hjWdaLUhLqqmgeYNZXSUY=",
"requires": {
"hoist-non-react-statics": "^2.2.1",
"invariant": "^2.0.0",
@@ -26544,7 +26558,7 @@
"readable-stream": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
- "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
+ "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -26635,7 +26649,7 @@
"recompose": {
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/recompose/-/recompose-0.25.1.tgz",
- "integrity": "sha512-EwFAv6UBrHbLIsIKHUZJ+BKdjTmyEsIrRlGO3R7PKu0S7hkgNznVDRvb+1upQUntURtBvxhYnTVQ3AcWOlsmWA==",
+ "integrity": "sha1-XrnWz24lqf+tc8u65WWLW1XW5yg=",
"requires": {
"change-emitter": "^0.1.2",
"fbjs": "^0.8.1",
@@ -26733,7 +26747,7 @@
"redux": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz",
- "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==",
+ "integrity": "sha1-BrcxIyFZAdJdBlvjQusCa8HIU3s=",
"requires": {
"lodash": "^4.2.1",
"lodash-es": "^4.2.1",
@@ -26772,7 +26786,7 @@
"regenerate": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz",
- "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg=="
+ "integrity": "sha1-DDNtOYBVPXVcObWGrjsgqknIK38="
},
"regenerator-runtime": {
"version": "0.11.1",
@@ -26782,7 +26796,7 @@
"regenerator-transform": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
- "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==",
+ "integrity": "sha1-HkmWg3Ix2ot/PPQRTXG1aRoGgN0=",
"requires": {
"babel-runtime": "^6.18.0",
"babel-types": "^6.19.0",
@@ -26792,7 +26806,7 @@
"regex-cache": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
- "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+ "integrity": "sha1-db3FiioUls7EihKDW8VMjVYjNt0=",
"requires": {
"is-equal-shallow": "^0.1.3"
}
@@ -27457,7 +27471,7 @@
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
- "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+ "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM="
},
"safe-regex": {
"version": "1.1.0",
@@ -27787,12 +27801,12 @@
"semaphore": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/semaphore/-/semaphore-1.1.0.tgz",
- "integrity": "sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA=="
+ "integrity": "sha1-qq2LhrIP6OmzKxbcLuaCqM0mqKo="
},
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
- "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
+ "integrity": "sha1-4FnAnYVx8FQII3M0M1BdOi8AsY4="
},
"semver-diff": {
"version": "2.1.0",
@@ -27915,7 +27929,7 @@
"sha.js": {
"version": "2.4.9",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz",
- "integrity": "sha512-G8zektVqbiPHrylgew9Zg1VRB1L/DtXNUVAM6q4QLy8NE3qtHlFXTf8VLL4k1Yl6c7NMjtZUTdXV+X44nFaT6A==",
+ "integrity": "sha1-mPZIgEdLdPSji42p08Dy0QRjPn0=",
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -28991,7 +29005,7 @@
"stream-exhaust": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz",
- "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw=="
+ "integrity": "sha1-rNrI2lnvK8HheiwMz2wyDRIOVV0="
},
"stream-http": {
"version": "2.7.2",
@@ -30220,7 +30234,7 @@
"tape": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/tape/-/tape-4.8.0.tgz",
- "integrity": "sha512-TWILfEnvO7I8mFe35d98F6T5fbLaEtbFTG/lxWvid8qDfFTxt19EBijWmB4j3+Hoh5TfHE2faWs73ua+EphuBA==",
+ "integrity": "sha1-9qn+xBzFCh3lD6M2A6tYCZH2Bo4=",
"requires": {
"deep-equal": "~1.0.1",
"defined": "~1.0.0",
@@ -30990,7 +31004,7 @@
"ua-parser-js": {
"version": "0.7.17",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz",
- "integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g=="
+ "integrity": "sha1-6exflJi57JEOeuOsYmqAXE0J7Kw="
},
"uglify-js": {
"version": "2.8.29",
@@ -33464,7 +33478,7 @@
"which": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
- "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
+ "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=",
"requires": {
"isexe": "^2.0.0"
}
@@ -33477,7 +33491,7 @@
"wide-align": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz",
- "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
+ "integrity": "sha1-Vx4PGwYEY268DfwhsDObvjE0FxA=",
"requires": {
"string-width": "^1.0.2"
}
diff --git a/test/e2e/beta/from-import-beta-ui.spec.js b/test/e2e/beta/from-import-beta-ui.spec.js
index 11d28264c..532bc1ef1 100644
--- a/test/e2e/beta/from-import-beta-ui.spec.js
+++ b/test/e2e/beta/from-import-beta-ui.spec.js
@@ -9,9 +9,12 @@ const {
verboseReportOnFailure,
} = require('../func')
const {
+ checkBrowserForConsoleErrors,
+ closeAllWindowHandlesExcept,
+ verboseReportOnFailure,
findElement,
findElements,
- checkBrowserForConsoleErrors,
+ loadExtension,
} = require('./helpers')
@@ -23,6 +26,7 @@ describe('Using MetaMask with an existing account', function () {
const testSeedPhrase = 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'
const testAddress = '0xE18035BF8712672935FDB4e5e431b1a0183d2DFC'
const testPrivateKey2 = '14abe6f4aab7f9f626fe981c864d0adeb5685f289ac9270c27b8fd790b4235d6'
+ const tinyDelayMs = 500
const regularDelayMs = 1000
const largeDelayMs = regularDelayMs * 2
const waitingNewPageDelayMs = regularDelayMs * 10
@@ -61,27 +65,51 @@ describe('Using MetaMask with an existing account', function () {
describe('New UI setup', async function () {
it('switches to first tab', async function () {
+ await delay(tinyDelayMs)
const [firstTab] = await driver.getAllWindowHandles()
await driver.switchTo().window(firstTab)
await delay(regularDelayMs)
})
it('selects the new UI option', async () => {
- const button = await findElement(driver, By.xpath("//p[contains(text(), 'Try Beta Version')]"))
+ try {
+ const overlay = await findElement(driver, By.css('.full-flex-height'))
+ await driver.wait(until.stalenessOf(overlay))
+ } catch (e) {}
+
+ const button = await findElement(driver, By.xpath("//button[contains(text(), 'Try it now')]"))
await button.click()
await delay(regularDelayMs)
// Close all other tabs
- const [oldUi, infoPage, newUi] = await driver.getAllWindowHandles()
-
- const newUiOrInfoPage = newUi || infoPage
- await driver.switchTo().window(oldUi)
- await driver.close()
- if (infoPage !== newUiOrInfoPage) {
- await driver.switchTo().window(infoPage)
- await driver.close()
+ const [tab0, tab1, tab2] = await driver.getAllWindowHandles()
+ await driver.switchTo().window(tab0)
+ await delay(tinyDelayMs)
+
+ let selectedUrl = await driver.getCurrentUrl()
+ await delay(tinyDelayMs)
+ if (tab0 && selectedUrl.match(/popup.html/)) {
+ await closeAllWindowHandlesExcept(driver, tab0)
+ } else if (tab1) {
+ await driver.switchTo().window(tab1)
+ selectedUrl = await driver.getCurrentUrl()
+ await delay(tinyDelayMs)
+ if (selectedUrl.match(/popup.html/)) {
+ await closeAllWindowHandlesExcept(driver, tab1)
+ } else if (tab2) {
+ await driver.switchTo().window(tab2)
+ selectedUrl = await driver.getCurrentUrl()
+ selectedUrl.match(/popup.html/) && await closeAllWindowHandlesExcept(driver, tab2)
+ }
+ } else {
+ throw new Error('popup.html not found')
}
- await driver.switchTo().window(newUiOrInfoPage)
+ await delay(regularDelayMs)
+ const [appTab] = await driver.getAllWindowHandles()
+ await driver.switchTo().window(appTab)
+ await delay(tinyDelayMs)
+
+ await loadExtension(driver, extensionId)
await delay(regularDelayMs)
const continueBtn = await findElement(driver, By.css('.welcome-screen__button'))
@@ -185,6 +213,16 @@ describe('Using MetaMask with an existing account', function () {
})
describe('Add an account', () => {
+ it('switches to localhost', async () => {
+ const networkDropdown = await findElement(driver, By.css('.network-name'))
+ await networkDropdown.click()
+ await delay(regularDelayMs)
+
+ const [localhost] = await findElements(driver, By.xpath(`//span[contains(text(), 'Localhost')]`))
+ await localhost.click()
+ await delay(largeDelayMs * 2)
+ })
+
it('choose Create Account from the account menu', async () => {
await driver.findElement(By.css('.account-menu__icon')).click()
await delay(regularDelayMs)
diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js
index 37e556b55..98b4a2791 100644
--- a/test/e2e/beta/metamask-beta-ui.spec.js
+++ b/test/e2e/beta/metamask-beta-ui.spec.js
@@ -4,9 +4,11 @@ const webdriver = require('selenium-webdriver')
const { By, Key, until } = webdriver
const {
delay,
- createModifiedTestBuild,
- setupBrowserAndExtension,
- verboseReportOnFailure,
+ buildChromeWebDriver,
+ buildFirefoxWebdriver,
+ installWebExt,
+ getExtensionIdChrome,
+ getExtensionIdFirefox,
} = require('../func')
const {
assertElementNotPresent,
@@ -17,13 +19,13 @@ const {
loadExtension,
openNewPage,
switchToWindowWithTitle,
+ verboseReportOnFailure,
waitUntilXWindowHandles,
} = require('./helpers')
describe('MetaMask', function () {
- const browser = process.env.SELENIUM_BROWSER
+ let extensionId
let driver
- let extensionUri
let tokenAddress
const testSeedPhrase = 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'
@@ -35,18 +37,27 @@ describe('MetaMask', function () {
this.bail(true)
before(async function () {
- const srcPath = path.resolve(`dist/${browser}`)
- const { extPath } = await createModifiedTestBuild({ browser, srcPath })
- const installResult = await setupBrowserAndExtension({ browser, extPath })
- driver = installResult.driver
- extensionUri = installResult.extensionUri
-
- await driver.get(extensionUri)
- await delay(tinyDelayMs)
+ switch (process.env.SELENIUM_BROWSER) {
+ case 'chrome': {
+ const extPath = path.resolve('dist/chrome')
+ driver = buildChromeWebDriver(extPath)
+ extensionId = await getExtensionIdChrome(driver)
+ await driver.get(`chrome-extension://${extensionId}/popup.html`)
+ break
+ }
+ case 'firefox': {
+ const extPath = path.resolve('dist/firefox')
+ driver = buildFirefoxWebdriver()
+ await installWebExt(driver, extPath)
+ await delay(700)
+ extensionId = await getExtensionIdFirefox(driver)
+ await driver.get(`moz-extension://${extensionId}/popup.html`)
+ }
+ }
})
afterEach(async function () {
- if (browser === 'chrome') {
+ if (process.env.SELENIUM_BROWSER === 'chrome') {
const errors = await checkBrowserForConsoleErrors(driver)
if (errors.length) {
const errorReports = errors.map(err => err.message)
@@ -55,7 +66,7 @@ describe('MetaMask', function () {
}
}
if (this.currentTest.state === 'failed') {
- await verboseReportOnFailure({ browser, driver, title: this.currentTest.title })
+ await verboseReportOnFailure(driver, this.currentTest)
}
})
@@ -64,30 +75,11 @@ describe('MetaMask', function () {
})
describe('New UI setup', async function () {
- let networkSelector
it('switches to first tab', async function () {
+ await delay(tinyDelayMs)
const [firstTab] = await driver.getAllWindowHandles()
await driver.switchTo().window(firstTab)
await delay(regularDelayMs)
- try {
- networkSelector = await findElement(driver, By.css('#network_component'))
- } catch (e) {
- await loadExtension(driver, extensionUri)
- await delay(largeDelayMs * 2)
- networkSelector = await findElement(driver, By.css('#network_component'))
- }
- await delay(regularDelayMs)
- })
-
- it('uses the local network', async function () {
- await networkSelector.click()
- await delay(regularDelayMs)
-
- const networks = await findElements(driver, By.css('.dropdown-menu-item'))
- const localhost = networks[4]
- await driver.wait(until.elementTextMatches(localhost, /Localhost/))
- await localhost.click()
- await delay(regularDelayMs)
})
it('selects the new UI option', async () => {
@@ -96,27 +88,40 @@ describe('MetaMask', function () {
await driver.wait(until.stalenessOf(overlay))
} catch (e) {}
- const button = await findElement(driver, By.xpath("//p[contains(text(), 'Try Beta Version')]"))
+ const button = await findElement(driver, By.xpath("//button[contains(text(), 'Try it now')]"))
await button.click()
await delay(regularDelayMs)
// Close all other tabs
- const [oldUi, tab1, tab2] = await driver.getAllWindowHandles()
- await driver.switchTo().window(oldUi)
- await driver.close()
+ const [tab0, tab1, tab2] = await driver.getAllWindowHandles()
+ await driver.switchTo().window(tab0)
+ await delay(tinyDelayMs)
- await driver.switchTo().window(tab1)
- const tab1Url = await driver.getCurrentUrl()
- if (tab1Url.match(/metamask.io/)) {
- await driver.switchTo().window(tab1)
- await driver.close()
- await driver.switchTo().window(tab2)
- } else if (tab2) {
- await driver.switchTo().window(tab2)
- await driver.close()
+ let selectedUrl = await driver.getCurrentUrl()
+ await delay(tinyDelayMs)
+ if (tab0 && selectedUrl.match(/popup.html/)) {
+ await closeAllWindowHandlesExcept(driver, tab0)
+ } else if (tab1) {
await driver.switchTo().window(tab1)
+ selectedUrl = await driver.getCurrentUrl()
+ await delay(tinyDelayMs)
+ if (selectedUrl.match(/popup.html/)) {
+ await closeAllWindowHandlesExcept(driver, tab1)
+ } else if (tab2) {
+ await driver.switchTo().window(tab2)
+ selectedUrl = await driver.getCurrentUrl()
+ selectedUrl.match(/popup.html/) && await closeAllWindowHandlesExcept(driver, tab2)
+ }
+ } else {
+ throw new Error('popup.html not found')
}
await delay(regularDelayMs)
+ const [appTab] = await driver.getAllWindowHandles()
+ await driver.switchTo().window(appTab)
+ await delay(tinyDelayMs)
+
+ await loadExtension(driver, extensionId)
+ await delay(regularDelayMs)
const continueBtn = await findElement(driver, By.css('.welcome-screen__button'))
await continueBtn.click()
@@ -263,7 +268,7 @@ describe('MetaMask', function () {
await word11.click()
await delay(tinyDelayMs)
} catch (e) {
- await loadExtension(driver, extensionUri)
+ await loadExtension(driver, extensionId)
await retypeSeedPhrase(words, true)
}
}
@@ -378,6 +383,16 @@ describe('MetaMask', function () {
await delay(regularDelayMs)
})
+ it('switches to localhost', async () => {
+ const networkDropdown = await findElement(driver, By.css('.network-name'))
+ await networkDropdown.click()
+ await delay(regularDelayMs)
+
+ const [localhost] = await findElements(driver, By.xpath(`//span[contains(text(), 'Localhost')]`))
+ await localhost.click()
+ await delay(largeDelayMs * 2)
+ })
+
it('balance renders', async () => {
const balance = await findElement(driver, By.css('.balance-display .token-amount'))
await driver.wait(until.elementTextMatches(balance, /100.+ETH/))
@@ -636,7 +651,7 @@ describe('MetaMask', function () {
await delay(regularDelayMs)
await driver.switchTo().window(extension)
- await driver.get(extensionUri)
+ await loadExtension(driver, extensionId)
await delay(regularDelayMs)
const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
@@ -1011,4 +1026,4 @@ describe('MetaMask', function () {
await delay(regularDelayMs)
})
})
-})
+}) \ No newline at end of file
diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js
index d26786ca6..c59983c79 100644
--- a/test/e2e/metamask.spec.js
+++ b/test/e2e/metamask.spec.js
@@ -49,6 +49,18 @@ describe('Metamask popup page', function () {
await driver.switchTo().window(windowHandles[0])
})
+ it('does not select the new UI option', async () => {
+ await delay(300)
+ const button = await driver.findElement(By.xpath("//button[contains(text(), 'No thanks, maybe later')]"))
+ await button.click()
+ await delay(1000)
+ })
+
+ it('sets provider type to localhost', async function () {
+ await delay(300)
+ await setProviderType('localhost')
+ })
+
})
describe('Account Creation', () => {
@@ -118,9 +130,9 @@ describe('Metamask popup page', function () {
})
it('adds a second account', async function () {
- await driver.findElement(By.css('#app-content > div > div.full-width > div > div:nth-child(2) > span > div')).click()
+ await driver.findElement(By.css('div.full-width > div > div:nth-child(2) > span > div')).click()
await delay(300)
- await driver.findElement(By.css('#app-content > div > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(3) > span')).click()
+ await driver.findElement(By.css('div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(3) > span')).click()
})
it('shows account address', async function () {
@@ -131,7 +143,7 @@ describe('Metamask popup page', function () {
it('logs out of the vault', async () => {
await driver.findElement(By.css('.sandwich-expando')).click()
await delay(500)
- const logoutButton = await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)'))
+ const logoutButton = await driver.findElement(By.css('.menu-droppo > li:nth-child(3)'))
assert.equal(await logoutButton.getText(), 'Log Out')
await logoutButton.click()
})
@@ -163,7 +175,7 @@ describe('Metamask popup page', function () {
it('logs out', async function () {
await driver.findElement(By.css('.sandwich-expando')).click()
await delay(200)
- const logOut = await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)'))
+ const logOut = await driver.findElement(By.css('.menu-droppo > li:nth-child(3)'))
assert.equal(await logOut.getText(), 'Log Out')
await logOut.click()
await delay(300)
@@ -312,6 +324,10 @@ describe('Metamask popup page', function () {
})
})
+ async function setProviderType (type) {
+ await driver.executeScript('window.metamask.setProviderType(arguments[0])', type)
+ }
+
async function checkBrowserForConsoleErrors () {
const ignoredLogTypes = ['WARNING']
const ignoredErrorMessages = [
diff --git a/test/integration/lib/first-time.js b/test/integration/lib/first-time.js
index 052d89518..8cacd7f14 100644
--- a/test/integration/lib/first-time.js
+++ b/test/integration/lib/first-time.js
@@ -27,6 +27,11 @@ async function runFirstTimeUsageTest(assert, done) {
const app = $('#app-content')
+ // Selects new ui
+ const tryNewUIButton = (await findAsync(app, 'button.negative'))[0]
+ tryNewUIButton.click()
+ await timeout()
+
// recurse notices
while (true) {
const button = await findAsync(app, 'button')
diff --git a/ui/app/components/confirm-page-container/confirm-detail-row/index.scss b/ui/app/components/confirm-page-container/confirm-detail-row/index.scss
index 84d0d56ed..dd6f87c17 100644
--- a/ui/app/components/confirm-page-container/confirm-detail-row/index.scss
+++ b/ui/app/components/confirm-page-container/confirm-detail-row/index.scss
@@ -15,14 +15,21 @@
&__details {
flex: 1;
text-align: end;
+ min-width: 0;
}
&__fiat {
font-size: 1.5rem;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
&__eth {
color: $oslo-gray;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
&__header-text {
diff --git a/ui/app/components/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js b/ui/app/components/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js
new file mode 100644
index 000000000..6f2489071
--- /dev/null
+++ b/ui/app/components/confirm-page-container/confirm-detail-row/tests/confirm-detail-row.component.test.js
@@ -0,0 +1,64 @@
+import React from 'react'
+import assert from 'assert'
+import { shallow } from 'enzyme'
+import ConfirmDetailRow from '../confirm-detail-row.component.js'
+import sinon from 'sinon'
+
+const propsMethodSpies = {
+ onHeaderClick: sinon.spy(),
+}
+
+describe('Confirm Detail Row Component', function () {
+ let wrapper
+
+ beforeEach(() => {
+ wrapper = shallow(<ConfirmDetailRow
+ errorType={'mockErrorType'}
+ label={'mockLabel'}
+ showError={false}
+ fiatText = {'mockFiatText'}
+ ethText = {'mockEthText'}
+ fiatTextColor= {'mockColor'}
+ onHeaderClick= {propsMethodSpies.onHeaderClick}
+ headerText = {'mockHeaderText'}
+ headerTextClassName = {'mockHeaderClass'}
+ />)
+ })
+
+ describe('render', () => {
+ it('should render a div with a confirm-detail-row class', () => {
+ assert.equal(wrapper.find('div.confirm-detail-row').length, 1)
+ })
+
+ it('should render the label as a child of the confirm-detail-row__label', () => {
+ assert.equal(wrapper.find('.confirm-detail-row > .confirm-detail-row__label').childAt(0).text(), 'mockLabel')
+ })
+
+ it('should render the headerText as a child of the confirm-detail-row__header-text', () => {
+ assert.equal(wrapper.find('.confirm-detail-row__details > .confirm-detail-row__header-text').childAt(0).text(), 'mockHeaderText')
+ })
+
+ it('should render the fiatText as a child of the confirm-detail-row__fiat', () => {
+ assert.equal(wrapper.find('.confirm-detail-row__details > .confirm-detail-row__fiat').childAt(0).text(), 'mockFiatText')
+ })
+
+ it('should render the ethText as a child of the confirm-detail-row__eth', () => {
+ assert.equal(wrapper.find('.confirm-detail-row__details > .confirm-detail-row__eth').childAt(0).text(), 'mockEthText')
+ })
+
+ it('should set the fiatTextColor on confirm-detail-row__fiat', () => {
+ assert.equal(wrapper.find('.confirm-detail-row__fiat').props().style.color, 'mockColor')
+ })
+
+ it('should assure the confirm-detail-row__header-text classname is correct', () => {
+ assert.equal(wrapper.find('.confirm-detail-row__header-text').props().className, 'confirm-detail-row__header-text mockHeaderClass')
+ })
+
+ it('should call onHeaderClick when headerText div gets clicked', () => {
+ wrapper.find('.confirm-detail-row__header-text').props().onClick()
+ assert.equal(assert.equal(propsMethodSpies.onHeaderClick.callCount, 1))
+ })
+
+
+ })
+})
diff --git a/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js b/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js
index 365ae216e..acaed383a 100644
--- a/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js
+++ b/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js
@@ -5,6 +5,7 @@ import {
formatCurrency,
convertTokenToFiat,
addFiat,
+ roundExponential,
} from '../../../helpers/confirm-transaction/util'
export default class ConfirmTokenTransactionBase extends Component {
@@ -42,7 +43,8 @@ export default class ConfirmTokenTransactionBase extends Component {
return this.context.t('noConversionRateAvailable')
} else {
const fiatTransactionAmount = this.getFiatTransactionAmount()
- return formatCurrency(fiatTransactionAmount, currentCurrency)
+ const roundedFiatTransactionAmount = roundExponential(fiatTransactionAmount)
+ return formatCurrency(roundedFiatTransactionAmount, currentCurrency)
}
}
@@ -54,7 +56,8 @@ export default class ConfirmTokenTransactionBase extends Component {
} else {
const fiatTransactionAmount = this.getFiatTransactionAmount()
const fiatTotal = addFiat(fiatTransactionAmount, fiatTransactionTotal)
- return formatCurrency(fiatTotal, currentCurrency)
+ const roundedFiatTotal = roundExponential(fiatTotal)
+ return formatCurrency(roundedFiatTotal, currentCurrency)
}
}
diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js
index 0d693b805..1a639d0b9 100644
--- a/ui/app/components/tx-list-item.js
+++ b/ui/app/components/tx-list-item.js
@@ -213,14 +213,23 @@ TxListItem.prototype.showRetryButton = function () {
if (!txParams) {
return false
}
+ let currentTxIsLatest = false
const currentNonce = txParams.nonce
const currentNonceTxs = selectedAddressTxList.filter(tx => tx.txParams.nonce === currentNonce)
const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted')
+ const currentSubmittedTxs = selectedAddressTxList.filter(tx => tx.status === 'submitted')
const lastSubmittedTxWithCurrentNonce = currentNonceSubmittedTxs[currentNonceSubmittedTxs.length - 1]
const currentTxIsLatestWithNonce = lastSubmittedTxWithCurrentNonce &&
lastSubmittedTxWithCurrentNonce.id === transactionId
+ if (currentSubmittedTxs.length > 0) {
+ const lastTx = currentSubmittedTxs.reduce((tx1, tx2) => {
+ if (tx1.submittedTime < tx2.submittedTime) return tx1
+ return tx2
+ })
+ currentTxIsLatest = lastTx.id === transactionId
+ }
- return currentTxIsLatestWithNonce && Date.now() - transactionSubmittedTime > 30000
+ return currentTxIsLatestWithNonce && Date.now() - transactionSubmittedTime > 30000 && currentTxIsLatest
}
TxListItem.prototype.setSelectedToken = function (tokenAddress) {
diff --git a/ui/app/helpers/confirm-transaction/util.js b/ui/app/helpers/confirm-transaction/util.js
index f015b2bf5..a37778c19 100644
--- a/ui/app/helpers/confirm-transaction/util.js
+++ b/ui/app/helpers/confirm-transaction/util.js
@@ -3,6 +3,7 @@ import currencies from 'currency-formatter/currencies'
import abi from 'human-standard-token-abi'
import abiDecoder from 'abi-decoder'
import ethUtil from 'ethereumjs-util'
+import BigNumber from 'bignumber.js'
abiDecoder.addABI(abi)
@@ -137,3 +138,11 @@ export function convertTokenToFiat ({
export function hasUnconfirmedTransactions (state) {
return unconfirmedTransactionsCountSelector(state) > 0
}
+
+export function roundExponential (value) {
+ const PRECISION = 4
+ const bigNumberValue = new BigNumber(value)
+
+ // In JS, numbers with exponentials greater than 20 get displayed as an exponential.
+ return bigNumberValue.e > 20 ? Number(bigNumberValue.toPrecision(PRECISION)) : value
+}
diff --git a/ui/app/selectors/confirm-transaction.js b/ui/app/selectors/confirm-transaction.js
index 8f8e0ea74..9548cf75e 100644
--- a/ui/app/selectors/confirm-transaction.js
+++ b/ui/app/selectors/confirm-transaction.js
@@ -1,6 +1,7 @@
import { createSelector } from 'reselect'
import txHelper from '../../lib/tx-helper'
import { calcTokenAmount } from '../token-util'
+import { roundExponential } from '../helpers/confirm-transaction/util'
const unapprovedTxsSelector = state => state.metamask.unapprovedTxs
const unapprovedMsgsSelector = state => state.metamask.unapprovedMsgs
@@ -133,7 +134,8 @@ export const tokenAmountAndToAddressSelector = createSelector(
const toParam = params.find(param => param.name === TOKEN_PARAM_TO)
const valueParam = params.find(param => param.name === TOKEN_PARAM_VALUE)
toAddress = toParam ? toParam.value : params[0].value
- tokenAmount = valueParam ? Number(valueParam.value) : Number(params[1].value)
+ const value = valueParam ? Number(valueParam.value) : Number(params[1].value)
+ tokenAmount = roundExponential(value)
}
return {
@@ -151,7 +153,8 @@ export const approveTokenAmountAndToAddressSelector = createSelector(
if (params && params.length) {
toAddress = params.find(param => param.name === TOKEN_PARAM_SPENDER).value
- tokenAmount = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value)
+ const value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value)
+ tokenAmount = roundExponential(value)
}
return {
@@ -170,11 +173,13 @@ export const sendTokenTokenAmountAndToAddressSelector = createSelector(
if (params && params.length) {
toAddress = params.find(param => param.name === TOKEN_PARAM_TO).value
- tokenAmount = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value)
+ let value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value)
if (tokenDecimals) {
- tokenAmount = calcTokenAmount(tokenAmount, tokenDecimals)
+ value = calcTokenAmount(value, tokenDecimals)
}
+
+ tokenAmount = roundExponential(value)
}
return {