mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
parent
a47370057e
commit
18179fd345
@ -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."
|
||||
},
|
||||
|
@ -366,6 +366,9 @@
|
||||
"defaultNetwork": {
|
||||
"message": "預設乙太幣交易網路為主網路"
|
||||
},
|
||||
"delete": {
|
||||
"message": "刪除"
|
||||
},
|
||||
"denExplainer": {
|
||||
"message": "您的 DEN 是 MetaMask 中您的的密碼加密儲存庫。"
|
||||
},
|
||||
|
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -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)}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -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>
|
||||
)
|
||||
|
@ -35,6 +35,15 @@ const defaultNetworksData = [
|
||||
ticker: 'ETH',
|
||||
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',
|
||||
|
@ -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) => {
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user