diff options
author | Dan J Miller <danjm.com@gmail.com> | 2019-06-17 22:05:47 +0800 |
---|---|---|
committer | Whymarrh Whitby <whymarrh.whitby@gmail.com> | 2019-06-17 22:05:47 +0800 |
commit | 18179fd34551680bd65df7c0c3caaa5945d1e94d (patch) | |
tree | 13618080a568ed2d8be0c61e9ced62b6eb9963ea | |
parent | a47370057e9453e49c1d83a17fcdda275affb940 (diff) | |
download | tangerine-wallet-browser-18179fd34551680bd65df7c0c3caaa5945d1e94d.tar.gz tangerine-wallet-browser-18179fd34551680bd65df7c0c3caaa5945d1e94d.tar.zst tangerine-wallet-browser-18179fd34551680bd65df7c0c3caaa5945d1e94d.zip |
Add delete to custom RPC form (#6718, #6650)
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> |