aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/_locales/en/messages.json3
-rw-r--r--app/_locales/zh_TW/messages.json3
-rw-r--r--test/e2e/beta/metamask-beta-ui.spec.js16
-rw-r--r--ui/app/components/ui/page-container/page-container-footer/page-container-footer.component.js4
-rw-r--r--ui/app/pages/settings/index.scss10
-rw-r--r--ui/app/pages/settings/networks-tab/index.scss30
-rw-r--r--ui/app/pages/settings/networks-tab/network-form/network-form.component.js128
-rw-r--r--ui/app/pages/settings/networks-tab/networks-tab.component.js80
-rw-r--r--ui/app/pages/settings/networks-tab/networks-tab.constants.js9
-rw-r--r--ui/app/pages/settings/networks-tab/networks-tab.container.js4
-rw-r--r--ui/app/pages/settings/settings.component.js2
11 files changed, 229 insertions, 60 deletions
diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index a0b084eb2..774ae4c85 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -454,6 +454,9 @@
"defaultNetwork": {
"message": "The default network for Ether transactions is Main Net."
},
+ "delete": {
+ "message": "Delete"
+ },
"denExplainer": {
"message": "Your DEN is your password-encrypted storage within MetaMask."
},
diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json
index c645f2af1..4df95f72f 100644
--- a/app/_locales/zh_TW/messages.json
+++ b/app/_locales/zh_TW/messages.json
@@ -366,6 +366,9 @@
"defaultNetwork": {
"message": "預設乙太幣交易網路為主網路"
},
+ "delete": {
+ "message": "刪除"
+ },
"denExplainer": {
"message": "您的 DEN 是 MetaMask 中您的的密碼加密儲存庫。"
},
diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js
index 06778ab99..15087c57f 100644
--- a/test/e2e/beta/metamask-beta-ui.spec.js
+++ b/test/e2e/beta/metamask-beta-ui.spec.js
@@ -1478,7 +1478,7 @@ describe('MetaMask', function () {
await customRpcInput.clear()
await customRpcInput.sendKeys(customRpcUrl)
- const customRpcSave = await findElement(driver, By.css('.page-container__footer-button'))
+ const customRpcSave = await findElement(driver, By.css('.network-form__footer .btn-secondary'))
await customRpcSave.click()
await delay(largeDelayMs * 2)
})
@@ -1504,5 +1504,19 @@ describe('MetaMask', function () {
assert.equal(customRpcs.length, customRpcUrls.length)
})
+
+ it('deletes a custom RPC', async () => {
+ const networkListItems = await findElements(driver, By.css('.networks-tab__networks-list-name'))
+ const lastNetworkListItem = networkListItems[networkListItems.length - 1]
+ await lastNetworkListItem.click()
+ await delay(100)
+
+ const deleteButton = await findElement(driver, By.css('.btn-danger'))
+ await deleteButton.click()
+ await delay(regularDelayMs)
+ const newNetworkListItems = await findElements(driver, By.css('.networks-tab__networks-list-name'))
+
+ assert.equal(networkListItems.length - 1, newNetworkListItems.length)
+ })
})
})
diff --git a/ui/app/components/ui/page-container/page-container-footer/page-container-footer.component.js b/ui/app/components/ui/page-container/page-container-footer/page-container-footer.component.js
index 4ef203521..a2cf0100b 100644
--- a/ui/app/components/ui/page-container/page-container-footer/page-container-footer.component.js
+++ b/ui/app/components/ui/page-container/page-container-footer/page-container-footer.component.js
@@ -8,6 +8,7 @@ export default class PageContainerFooter extends Component {
children: PropTypes.node,
onCancel: PropTypes.func,
cancelText: PropTypes.string,
+ cancelButtonType: PropTypes.string,
onSubmit: PropTypes.func,
submitText: PropTypes.string,
disabled: PropTypes.bool,
@@ -29,6 +30,7 @@ export default class PageContainerFooter extends Component {
disabled,
submitButtonType,
hideCancel,
+ cancelButtonType,
} = this.props
return (
@@ -36,7 +38,7 @@ export default class PageContainerFooter extends Component {
<header>
{!hideCancel && <Button
- type="default"
+ type={cancelButtonType || 'default'}
large
className="page-container__footer-button"
onClick={e => onCancel(e)}
diff --git a/ui/app/pages/settings/index.scss b/ui/app/pages/settings/index.scss
index 66959ba93..c516a84bb 100644
--- a/ui/app/pages/settings/index.scss
+++ b/ui/app/pages/settings/index.scss
@@ -28,6 +28,10 @@
font-size: 20px;
border-bottom: 1px solid $alto;
margin-right: 24px;
+ height: 72px;
+ align-items: center;
+ display: flex;
+ flex-flow: row nowrap;
@media screen and (max-width: 575px) {
display: none;
@@ -52,9 +56,7 @@
font-family: Roboto;
font-style: normal;
font-weight: normal;
- font-size: 24px;
- line-height: 24px;
- color: black;
+ font-size: 20px;
@media screen and (max-width: 575px) {
font-size: 16px;
@@ -123,7 +125,7 @@
&__body {
padding: 12px 24px;
-
+
@media screen and (min-width: 576px) {
padding: 12px;
}
diff --git a/ui/app/pages/settings/networks-tab/index.scss b/ui/app/pages/settings/networks-tab/index.scss
index b0020437d..bf83c7a14 100644
--- a/ui/app/pages/settings/networks-tab/index.scss
+++ b/ui/app/pages/settings/networks-tab/index.scss
@@ -12,7 +12,7 @@
}
&__body {
- padding: 12px 24px;
+ padding-right: 24px;
height: 100%;
display: flex;
flex-direction: column;
@@ -118,12 +118,12 @@
}
&__add-network-header-button-wrapper {
- padding-top: 15px;
- padding-bottom: 21px;
justify-content: center;
.button {
- width: 178px;
+ width: 138px;
+ padding: 10px;
+ line-height: 20px;
}
@media screen and (max-width: 575px) {
@@ -197,4 +197,24 @@
font-weight: bold;
color: #000000;
}
-} \ No newline at end of file
+}
+
+.network-form {
+ &__footer {
+ display: flex;
+ flex-flow: row nowrap;
+ margin: .75rem 0;
+
+ .btn-default {
+ margin-right: .375rem;
+ }
+
+ .btn-secondary {
+ margin-left: .375rem;
+ }
+
+ .btn-danger {
+ margin-right: 3.75rem;
+ }
+ }
+}
diff --git a/ui/app/pages/settings/networks-tab/network-form/network-form.component.js b/ui/app/pages/settings/networks-tab/network-form/network-form.component.js
index 5e455b65e..388e2665f 100644
--- a/ui/app/pages/settings/networks-tab/network-form/network-form.component.js
+++ b/ui/app/pages/settings/networks-tab/network-form/network-form.component.js
@@ -1,10 +1,10 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import validUrl from 'valid-url'
-import PageContainerFooter from '../../../../components/ui/page-container/page-container-footer'
import TextField from '../../../../components/ui/text-field'
+import Button from '../../../../components/ui/button'
-export default class NetworksTab extends PureComponent {
+export default class NetworkForm extends PureComponent {
static contextTypes = {
t: PropTypes.func.isRequired,
metricsEvent: PropTypes.func.isRequired,
@@ -12,6 +12,7 @@ export default class NetworksTab extends PureComponent {
static propTypes = {
editRpc: PropTypes.func.isRequired,
+ delRpcTarget: PropTypes.func.isRequired,
rpcUrl: PropTypes.string,
chainId: PropTypes.string,
ticker: PropTypes.string,
@@ -20,6 +21,7 @@ export default class NetworksTab extends PureComponent {
onClear: PropTypes.func.isRequired,
setRpcTarget: PropTypes.func.isRequired,
networksTabIsInAddMode: PropTypes.bool,
+ isCurrentRpcTarget: PropTypes.bool,
blockExplorerUrl: PropTypes.string,
rpcPrefs: PropTypes.object,
}
@@ -70,6 +72,71 @@ export default class NetworksTab extends PureComponent {
})
}
+ resetForm () {
+ const {
+ rpcUrl,
+ chainId,
+ ticker,
+ networkName,
+ blockExplorerUrl,
+ } = this.props
+
+ this.setState({ rpcUrl, chainId, ticker, networkName, blockExplorerUrl, errors: {} })
+ }
+
+ onSubmit = () => {
+ const {
+ setRpcTarget,
+ rpcUrl: propsRpcUrl,
+ editRpc,
+ rpcPrefs = {},
+ onClear,
+ networksTabIsInAddMode,
+ } = this.props
+ const {
+ networkName,
+ rpcUrl,
+ chainId,
+ ticker,
+ blockExplorerUrl,
+ } = this.state
+ if (propsRpcUrl && rpcUrl !== propsRpcUrl) {
+ editRpc(propsRpcUrl, rpcUrl, chainId, ticker, networkName, {
+ blockExplorerUrl: blockExplorerUrl || rpcPrefs.blockExplorerUrl,
+ ...rpcPrefs,
+ })
+ } else {
+ setRpcTarget(rpcUrl, chainId, ticker, networkName, {
+ blockExplorerUrl: blockExplorerUrl || rpcPrefs.blockExplorerUrl,
+ ...rpcPrefs,
+ })
+ }
+
+ if (networksTabIsInAddMode) {
+ onClear()
+ }
+ }
+
+ onCancel = () => {
+ const {
+ networksTabIsInAddMode,
+ onClear,
+ } = this.props
+
+ if (networksTabIsInAddMode) {
+ onClear()
+ } else {
+ this.resetForm()
+ }
+ }
+
+ onDelete = () => {
+ const { delRpcTarget, rpcUrl, onClear } = this.props
+ delRpcTarget(rpcUrl)
+ this.resetForm()
+ onClear()
+ }
+
stateIsUnchanged () {
const {
rpcUrl,
@@ -152,16 +219,23 @@ export default class NetworksTab extends PureComponent {
}
render () {
- const { setRpcTarget, viewOnly, rpcUrl: propsRpcUrl, editRpc, rpcPrefs = {} } = this.props
+ const { t } = this.context
+ const {
+ viewOnly,
+ isCurrentRpcTarget,
+ networksTabIsInAddMode,
+ } = this.props
const {
networkName,
rpcUrl,
- chainId,
+ chainId = '',
ticker,
blockExplorerUrl,
errors,
} = this.state
+ const isSubmitDisabled = viewOnly || this.stateIsUnchanged() || Object.values(errors).some(x => x) || !rpcUrl
+ const deletable = !networksTabIsInAddMode && !isCurrentRpcTarget && !viewOnly
return (
<div className="networks-tab__network-form">
@@ -198,26 +272,32 @@ export default class NetworksTab extends PureComponent {
blockExplorerUrl,
'optionalBlockExplorerUrl',
)}
- <PageContainerFooter
- cancelText={this.context.t('cancel')}
- hideCancel={true}
- onSubmit={() => {
- if (propsRpcUrl && rpcUrl !== propsRpcUrl) {
- editRpc(propsRpcUrl, rpcUrl, chainId, ticker, networkName, {
- blockExplorerUrl: blockExplorerUrl || rpcPrefs.blockExplorerUrl,
- ...rpcPrefs,
- })
- } else {
- setRpcTarget(rpcUrl, chainId, ticker, networkName, {
- blockExplorerUrl: blockExplorerUrl || rpcPrefs.blockExplorerUrl,
- ...rpcPrefs,
- })
- }
- }}
- submitText={this.context.t('save')}
- submitButtonType={'confirm'}
- disabled={viewOnly || this.stateIsUnchanged() || Object.values(errors).some(x => x) || !rpcUrl}
- />
+ <div className="network-form__footer">
+ {
+ deletable && (
+ <Button
+ type="danger"
+ onClick={this.onDelete}
+ >
+ { t('delete') }
+ </Button>
+ )
+ }
+ <Button
+ type="default"
+ onClick={this.onCancel}
+ disabled={viewOnly || this.stateIsUnchanged()}
+ >
+ { t('cancel') }
+ </Button>
+ <Button
+ type="secondary"
+ disabled={isSubmitDisabled}
+ onClick={this.onSubmit}
+ >
+ { t('save') }
+ </Button>
+ </div>
</div>
)
}
diff --git a/ui/app/pages/settings/networks-tab/networks-tab.component.js b/ui/app/pages/settings/networks-tab/networks-tab.component.js
index 2f921a892..f6c8443cf 100644
--- a/ui/app/pages/settings/networks-tab/networks-tab.component.js
+++ b/ui/app/pages/settings/networks-tab/networks-tab.component.js
@@ -25,6 +25,7 @@ export default class NetworksTab extends PureComponent {
setNetworksTabAddMode: PropTypes.func.isRequired,
setRpcTarget: PropTypes.func.isRequired,
setSelectedSettingsRpcUrl: PropTypes.func.isRequired,
+ delRpcTarget: PropTypes.func.isRequired,
providerUrl: PropTypes.string,
providerType: PropTypes.string,
networkDefaultedToProvider: PropTypes.bool,
@@ -62,7 +63,7 @@ export default class NetworksTab extends PureComponent {
<span className="settings-page__sub-header-text">{ this.context.t('networks') }</span>
<div className="networks-tab__add-network-header-button-wrapper">
<Button
- type="primary"
+ type="secondary"
onClick={event => {
event.preventDefault()
setSelectedSettingsRpcUrl(null)
@@ -125,19 +126,41 @@ export default class NetworksTab extends PureComponent {
renderNetworksList () {
const { networksToRender, selectedNetwork, networkIsSelected, networksTabIsInAddMode, networkDefaultedToProvider } = this.props
-
+ console.log(networksToRender)
return (
- <div className={classnames('networks-tab__networks-list', {
- 'networks-tab__networks-list--selection': (networkIsSelected && !networkDefaultedToProvider) || networksTabIsInAddMode,
- })}>
+ <div
+ className={classnames('networks-tab__networks-list', {
+ 'networks-tab__networks-list--selection': (networkIsSelected && !networkDefaultedToProvider) || networksTabIsInAddMode,
+ })}
+ >
{ networksToRender.map(network => this.renderNetworkListItem(network, selectedNetwork.rpcUrl)) }
+ {
+ networksTabIsInAddMode && (
+ <div
+ className="networks-tab__networks-list-item"
+ >
+ <NetworkDropdownIcon
+ backgroundColor="white"
+ innerBorder="1px solid rgb(106, 115, 125)"
+ />
+ <div
+ className="networks-tab__networks-list-name networks-tab__networks-list-name--selected"
+ >
+ { this.context.t('newNetwork') }
+ </div>
+ <div className="networks-tab__networks-list-arrow" />
+ </div>
+ )
+ }
</div>
)
}
renderNetworksTabContent () {
+ const { t } = this.context
const {
setRpcTarget,
+ delRpcTarget,
setSelectedSettingsRpcUrl,
setNetworksTabAddMode,
selectedNetwork: {
@@ -153,30 +176,39 @@ export default class NetworksTab extends PureComponent {
networksTabIsInAddMode,
editRpc,
networkDefaultedToProvider,
+ providerUrl,
} = this.props
+
const envIsPopup = getEnvironmentType() === ENVIRONMENT_TYPE_POPUP
+ const shouldRenderNetworkForm = networksTabIsInAddMode || !envIsPopup || (envIsPopup && !networkDefaultedToProvider)
return (
<div className="networks-tab__content">
- {this.renderNetworksList()}
- {networksTabIsInAddMode || !envIsPopup || (envIsPopup && !networkDefaultedToProvider)
- ? <NetworkForm
- setRpcTarget={setRpcTarget}
- editRpc={editRpc}
- networkName={label || labelKey && this.context.t(labelKey) || ''}
- rpcUrl={rpcUrl}
- chainId={chainId}
- ticker={ticker}
- onClear={() => {
- setNetworksTabAddMode(false)
- setSelectedSettingsRpcUrl(null)
- }}
- viewOnly={viewOnly}
- networksTabIsInAddMode={networksTabIsInAddMode}
- rpcPrefs={rpcPrefs}
- blockExplorerUrl={blockExplorerUrl}
- />
- : null
+ { this.renderNetworksList() }
+ {
+ shouldRenderNetworkForm
+ ? (
+ <NetworkForm
+ setRpcTarget={setRpcTarget}
+ editRpc={editRpc}
+ networkName={label || labelKey && t(labelKey) || ''}
+ rpcUrl={rpcUrl}
+ chainId={chainId}
+ ticker={ticker}
+ onClear={() => {
+ setNetworksTabAddMode(false)
+ setSelectedSettingsRpcUrl(null)
+ }}
+ delRpcTarget={delRpcTarget}
+ viewOnly={viewOnly}
+ isCurrentRpcTarget={providerUrl === rpcUrl}
+ networksTabIsInAddMode={networksTabIsInAddMode}
+ rpcPrefs={rpcPrefs}
+ blockExplorerUrl={blockExplorerUrl}
+ cancelText={t('cancel')}
+ />
+ )
+ : null
}
</div>
)
diff --git a/ui/app/pages/settings/networks-tab/networks-tab.constants.js b/ui/app/pages/settings/networks-tab/networks-tab.constants.js
index d3d1a01cc..1a49ca04f 100644
--- a/ui/app/pages/settings/networks-tab/networks-tab.constants.js
+++ b/ui/app/pages/settings/networks-tab/networks-tab.constants.js
@@ -36,6 +36,15 @@ const defaultNetworksData = [
blockExplorerUrl: 'https://rinkeby.etherscan.io',
},
{
+ labelKey: 'goerli',
+ iconColor: '#3099f2',
+ providerType: 'goerli',
+ rpcUrl: 'https://api.infura.io/v1/jsonrpc/goerli',
+ chainId: '5',
+ ticker: 'ETH',
+ blockExplorerUrl: 'https://goerli.etherscan.io',
+ },
+ {
labelKey: 'localhost',
iconColor: 'white',
border: '1px solid #6A737D',
diff --git a/ui/app/pages/settings/networks-tab/networks-tab.container.js b/ui/app/pages/settings/networks-tab/networks-tab.container.js
index a5d71f714..9e1098922 100644
--- a/ui/app/pages/settings/networks-tab/networks-tab.container.js
+++ b/ui/app/pages/settings/networks-tab/networks-tab.container.js
@@ -8,6 +8,7 @@ import {
displayWarning,
setNetworksTabAddMode,
editRpc,
+ delRpcTarget,
} from '../../../store/actions'
import { defaultNetworksData } from './networks-tab.constants'
const defaultNetworks = defaultNetworksData.map(network => ({ ...network, viewOnly: true }))
@@ -63,6 +64,9 @@ const mapDispatchToProps = dispatch => {
setRpcTarget: (newRpc, chainId, ticker, nickname, rpcPrefs) => {
dispatch(updateAndSetCustomRpc(newRpc, chainId, ticker, nickname, rpcPrefs))
},
+ delRpcTarget: (target) => {
+ dispatch(delRpcTarget(target))
+ },
displayWarning: warning => dispatch(displayWarning(warning)),
setNetworksTabAddMode: isInAddMode => dispatch(setNetworksTabAddMode(isInAddMode)),
editRpc: (oldRpc, newRpc, chainId, ticker, nickname, rpcPrefs) => {
diff --git a/ui/app/pages/settings/settings.component.js b/ui/app/pages/settings/settings.component.js
index a2f137264..7f2045244 100644
--- a/ui/app/pages/settings/settings.component.js
+++ b/ui/app/pages/settings/settings.component.js
@@ -89,7 +89,7 @@ class SettingsPage extends PureComponent {
const { t } = this.context
const { location: { pathname } } = this.props
- return (
+ return pathname !== NETWORKS_ROUTE && (
<div className="settings-page__subheader">
{t(ROUTES_TO_I18N_KEYS[pathname] || 'general')}
</div>