diff options
author | Dan J Miller <danjm.com@gmail.com> | 2019-05-10 01:27:14 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-10 01:27:14 +0800 |
commit | 13be683701bc46d8f1bcbaa301e2b7f01a34e29c (patch) | |
tree | 18974b5a8c5c9054904c903a2554a6d7ce1b79d7 /ui/app/pages/settings/networks-tab/network-form/network-form.component.js | |
parent | 094e4cf555c698bfef50ca6679cd1e98f4ea9aa1 (diff) | |
download | tangerine-wallet-browser-13be683701bc46d8f1bcbaa301e2b7f01a34e29c.tar.gz tangerine-wallet-browser-13be683701bc46d8f1bcbaa301e2b7f01a34e29c.tar.zst tangerine-wallet-browser-13be683701bc46d8f1bcbaa301e2b7f01a34e29c.zip |
New settings custom rpc form (#6490)
* Add networks tab to settings, with header.
* Adds network list to settings network tab.
* Adds form to settings networks tab and connects it to network list.
* Network tab: form adding and editing working
* Settings network form properly handles input errors
* Add translations for settings network form
* Clean up styles of settings network tab.
* Add popup-view styles and behaviour to settings network tab.
* Fix save button on settings network form
* Adds 'Add Network' button and addMode to settings networks tab
* Lint fix for settings networks tab addition
* Fix navigation in settings networks tab.
* Editing an rpcurl in networks tab does not create new network, just changes rpc of old
* Fix layout of settings tabs other than network
* Networks dropdown 'Custom Rpc' item links to networks tab in settings.
* Update settings sidebar networks subheader.
* Make networks tab buttons width consistent with input widths in extension view.
* Fix settings screen subheader height in popup view
* Fix height of add networks button in popup view
* Add optional label to chainId and symbol form labels in networks setting tab
* Style fixes for networks tab headers
* Add ability to customize block explorer used by custom rpc
* Stylistic improvements+fixes to custom rpc form.
* Hide cancel button.
* Highlight and show network form of provider by default.
* Standardize network subheader name to 'Networks'
* Update e2e tests for new settings network form
* Update unit tests for new rpcPrefs prop
* Extract blockexplorer url construction into method.
* Fix broken styles on non-network tabs in popup mode
* Fix block explorer url links for cases when provider in state has not been updated.
* Fix vertical spacing of network form
* Don't allow click of save button on network form if nothing has changed
* Ensure add network button is shown in popup view
* Lint fix for networks tab
* Fix block explorer url preference setting.
* Fix e2e tests for custom blockexplorer in account details modal changes.
* Update integration test states to include frequentRpcList property
* Fix some capitalizations in en/messages.json
* Remove some console.logs added during custom rpc form work
* Fix external account link text and url for modal and dropdown.
* Documentation, url validation, proptype required additions and lint fixes on network tab and form.
Diffstat (limited to 'ui/app/pages/settings/networks-tab/network-form/network-form.component.js')
-rw-r--r-- | ui/app/pages/settings/networks-tab/network-form/network-form.component.js | 225 |
1 files changed, 225 insertions, 0 deletions
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 new file mode 100644 index 000000000..5e455b65e --- /dev/null +++ b/ui/app/pages/settings/networks-tab/network-form/network-form.component.js @@ -0,0 +1,225 @@ +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' + +export default class NetworksTab extends PureComponent { + static contextTypes = { + t: PropTypes.func.isRequired, + metricsEvent: PropTypes.func.isRequired, + } + + static propTypes = { + editRpc: PropTypes.func.isRequired, + rpcUrl: PropTypes.string, + chainId: PropTypes.string, + ticker: PropTypes.string, + viewOnly: PropTypes.bool, + networkName: PropTypes.string, + onClear: PropTypes.func.isRequired, + setRpcTarget: PropTypes.func.isRequired, + networksTabIsInAddMode: PropTypes.bool, + blockExplorerUrl: PropTypes.string, + rpcPrefs: PropTypes.object, + } + + state = { + rpcUrl: this.props.rpcUrl, + chainId: this.props.chainId, + ticker: this.props.ticker, + networkName: this.props.networkName, + blockExplorerUrl: this.props.blockExplorerUrl, + errors: {}, + } + + componentDidUpdate (prevProps) { + const { rpcUrl: prevRpcUrl, networksTabIsInAddMode: prevAddMode } = prevProps + const { + rpcUrl, + chainId, + ticker, + networkName, + networksTabIsInAddMode, + blockExplorerUrl, + } = this.props + + if (!prevAddMode && networksTabIsInAddMode) { + this.setState({ + rpcUrl: '', + chainId: '', + ticker: '', + networkName: '', + blockExplorerUrl: '', + errors: {}, + }) + } else if (prevRpcUrl !== rpcUrl) { + this.setState({ rpcUrl, chainId, ticker, networkName, blockExplorerUrl, errors: {} }) + } + } + + componentWillUnmount () { + this.props.onClear() + this.setState({ + rpcUrl: '', + chainId: '', + ticker: '', + networkName: '', + blockExplorerUrl: '', + errors: {}, + }) + } + + stateIsUnchanged () { + const { + rpcUrl, + chainId, + ticker, + networkName, + blockExplorerUrl, + } = this.props + + const { + rpcUrl: stateRpcUrl, + chainId: stateChainId, + ticker: stateTicker, + networkName: stateNetworkName, + blockExplorerUrl: stateBlockExplorerUrl, + } = this.state + + return ( + stateRpcUrl === rpcUrl && + stateChainId === chainId && + stateTicker === ticker && + stateNetworkName === networkName && + stateBlockExplorerUrl === blockExplorerUrl + ) + } + + renderFormTextField (fieldKey, textFieldId, onChange, value, optionalTextFieldKey) { + const { errors } = this.state + const { viewOnly } = this.props + + return ( + <div className="networks-tab__network-form-row"> + <div className="networks-tab__network-form-label">{this.context.t(optionalTextFieldKey || fieldKey)}</div> + <TextField + type="text" + id={textFieldId} + onChange={onChange} + fullWidth + margin="dense" + value={value} + disabled={viewOnly} + error={errors[fieldKey]} + /> + </div> + ) + } + + setStateWithValue = (stateKey, validator) => { + return (e) => { + validator && validator(e.target.value, stateKey) + this.setState({ [stateKey]: e.target.value }) + } + } + + setErrorTo = (errorKey, errorVal) => { + this.setState({ + errors: { + ...this.state.errors, + [errorKey]: errorVal, + }, + }) + } + + validateChainId = (chainId) => { + this.setErrorTo('chainId', !!chainId && Number.isNaN(parseInt(chainId)) + ? `${this.context.t('invalidInput')} chainId` + : '' + ) + } + + validateUrl = (url, stateKey) => { + if (validUrl.isWebUri(url)) { + this.setErrorTo(stateKey, '') + } else { + const appendedRpc = `http://${url}` + const validWhenAppended = validUrl.isWebUri(appendedRpc) && !url.match(/^https?:\/\/$/) + + this.setErrorTo(stateKey, this.context.t(validWhenAppended ? 'uriErrorMsg' : 'invalidRPC')) + } + } + + render () { + const { setRpcTarget, viewOnly, rpcUrl: propsRpcUrl, editRpc, rpcPrefs = {} } = this.props + const { + networkName, + rpcUrl, + chainId, + ticker, + blockExplorerUrl, + errors, + } = this.state + + + return ( + <div className="networks-tab__network-form"> + {this.renderFormTextField( + 'networkName', + 'network-name', + this.setStateWithValue('networkName'), + networkName, + )} + {this.renderFormTextField( + 'rpcUrl', + 'rpc-url', + this.setStateWithValue('rpcUrl', this.validateUrl), + rpcUrl, + )} + {this.renderFormTextField( + 'chainId', + 'chainId', + this.setStateWithValue('chainId', this.validateChainId), + chainId, + 'optionalChainId', + )} + {this.renderFormTextField( + 'symbol', + 'network-ticker', + this.setStateWithValue('ticker'), + ticker, + 'optionalSymbol', + )} + {this.renderFormTextField( + 'blockExplorerUrl', + 'block-explorer-url', + this.setStateWithValue('blockExplorerUrl', this.validateUrl), + 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> + ) + } + +} |