Fix network form save behavior (#9851)

* Fix chainId display in network form on save

* Disable save button while submitting

* Ensure submission state if encountering error during onSubmit
feature/default_network_editable
Erik Marks 4 years ago committed by GitHub
commit 6b38017b23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 172
      ui/app/pages/settings/networks-tab/network-form/network-form.component.js

@ -9,6 +9,14 @@ import Tooltip from '../../../../components/ui/tooltip'
import { isPrefixedFormattedHexString } from '../../../../../../app/scripts/lib/util' import { isPrefixedFormattedHexString } from '../../../../../../app/scripts/lib/util'
import { jsonRpcRequest } from '../../../../helpers/utils/util' import { jsonRpcRequest } from '../../../../helpers/utils/util'
const FORM_STATE_KEYS = [
'rpcUrl',
'chainId',
'ticker',
'networkName',
'blockExplorerUrl',
]
export default class NetworkForm extends PureComponent { export default class NetworkForm extends PureComponent {
static contextTypes = { static contextTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
@ -35,25 +43,17 @@ export default class NetworkForm extends PureComponent {
state = { state = {
rpcUrl: this.props.rpcUrl, rpcUrl: this.props.rpcUrl,
chainId: this.getDisplayChainIdFromProps(), chainId: this.getDisplayChainId(this.props.chainId),
ticker: this.props.ticker, ticker: this.props.ticker,
networkName: this.props.networkName, networkName: this.props.networkName,
blockExplorerUrl: this.props.blockExplorerUrl, blockExplorerUrl: this.props.blockExplorerUrl,
errors: {}, errors: {},
isSubmitting: false,
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
const { const { networksTabIsInAddMode: prevAddMode } = prevProps
rpcUrl: prevRpcUrl, const { networksTabIsInAddMode } = this.props
networksTabIsInAddMode: prevAddMode,
} = prevProps
const {
rpcUrl,
ticker,
networkName,
networksTabIsInAddMode,
blockExplorerUrl,
} = this.props
if (!prevAddMode && networksTabIsInAddMode) { if (!prevAddMode && networksTabIsInAddMode) {
this.setState({ this.setState({
@ -63,16 +63,15 @@ export default class NetworkForm extends PureComponent {
networkName: '', networkName: '',
blockExplorerUrl: '', blockExplorerUrl: '',
errors: {}, errors: {},
isSubmitting: false,
}) })
} else if (prevRpcUrl !== rpcUrl) { } else {
this.setState({ for (const key of FORM_STATE_KEYS) {
rpcUrl, if (prevProps[key] !== this.props[key]) {
chainId: this.getDisplayChainIdFromProps(), this.resetForm()
ticker, break
networkName, }
blockExplorerUrl, }
errors: {},
})
} }
} }
@ -93,86 +92,100 @@ export default class NetworkForm extends PureComponent {
} }
resetForm() { resetForm() {
const { rpcUrl, ticker, networkName, blockExplorerUrl } = this.props const {
rpcUrl,
chainId,
ticker,
networkName,
blockExplorerUrl,
} = this.props
this.setState({ this.setState({
rpcUrl, rpcUrl,
chainId: this.getDisplayChainIdFromProps(), chainId: this.getDisplayChainId(chainId),
ticker, ticker,
networkName, networkName,
blockExplorerUrl, blockExplorerUrl,
errors: {}, errors: {},
isSubmitting: false,
}) })
} }
/** /**
* Ensures that the chainId is always displayed in decimal, even though * Attempts to convert the given chainId to a decimal string, for display
* it's stored in hexadecimal. * purposes.
* *
* Should be called to get the chainId whenever props are used to set the * Should be called with the props chainId whenever it is used to set the
* component's state. * component's state.
* *
* @returns {string} The props chainId in decimal. * @param {unknown} chainId - The chainId to convert.
* @returns {string} The props chainId in decimal, or the original value if
* it can't be converted.
*/ */
getDisplayChainIdFromProps() { getDisplayChainId(chainId) {
const { chainId: propsChainId } = this.props if (!chainId || typeof chainId !== 'string' || !chainId.startsWith('0x')) {
return chainId
if (
!propsChainId ||
typeof propsChainId !== 'string' ||
!propsChainId.startsWith('0x')
) {
return propsChainId
} }
return new BigNumber(propsChainId, 16).toString(10) return new BigNumber(chainId, 16).toString(10)
} }
onSubmit = async () => { onSubmit = async () => {
const { this.setState({
setRpcTarget, isSubmitting: true,
rpcUrl: propsRpcUrl, })
editRpc,
rpcPrefs = {},
onClear,
networksTabIsInAddMode,
} = this.props
const {
networkName,
rpcUrl,
chainId: stateChainId,
ticker,
blockExplorerUrl,
} = this.state
const formChainId = stateChainId.trim().toLowerCase() try {
// Ensure chainId is a 0x-prefixed, lowercase hex string const {
let chainId = formChainId setRpcTarget,
if (!chainId.startsWith('0x')) { rpcUrl: propsRpcUrl,
chainId = `0x${new BigNumber(chainId, 10).toString(16)}` editRpc,
} rpcPrefs = {},
onClear,
networksTabIsInAddMode,
} = this.props
const {
networkName,
rpcUrl,
chainId: stateChainId,
ticker,
blockExplorerUrl,
} = this.state
if (!(await this.validateChainIdOnSubmit(formChainId, chainId, rpcUrl))) { const formChainId = stateChainId.trim().toLowerCase()
return // Ensure chainId is a 0x-prefixed, lowercase hex string
} let chainId = formChainId
if (!chainId.startsWith('0x')) {
chainId = `0x${new BigNumber(chainId, 10).toString(16)}`
}
if (propsRpcUrl && rpcUrl !== propsRpcUrl) { if (!(await this.validateChainIdOnSubmit(formChainId, chainId, rpcUrl))) {
await editRpc(propsRpcUrl, rpcUrl, chainId, ticker, networkName, { this.setState({
blockExplorerUrl: blockExplorerUrl || rpcPrefs.blockExplorerUrl, isSubmitting: false,
...rpcPrefs, })
}) return
} else { }
await setRpcTarget(rpcUrl, chainId, ticker, networkName, {
blockExplorerUrl: blockExplorerUrl || rpcPrefs.blockExplorerUrl,
...rpcPrefs,
})
}
if (networksTabIsInAddMode) { // After this point, isSubmitting will be reset in componentDidUpdate
onClear() if (propsRpcUrl && rpcUrl !== propsRpcUrl) {
} else { await editRpc(propsRpcUrl, rpcUrl, chainId, ticker, networkName, {
...rpcPrefs,
blockExplorerUrl: blockExplorerUrl || rpcPrefs.blockExplorerUrl,
})
} else {
await setRpcTarget(rpcUrl, chainId, ticker, networkName, {
...rpcPrefs,
blockExplorerUrl: blockExplorerUrl || rpcPrefs.blockExplorerUrl,
})
}
if (networksTabIsInAddMode) {
onClear()
}
} catch (error) {
this.setState({ this.setState({
chainId: this.getDisplayChainIdFromProps(), isSubmitting: false,
}) })
throw error
} }
} }
@ -197,6 +210,10 @@ export default class NetworkForm extends PureComponent {
}) })
} }
isSubmitting() {
return this.state.isSubmitting
}
stateIsUnchanged() { stateIsUnchanged() {
const { const {
rpcUrl, rpcUrl,
@ -220,7 +237,7 @@ export default class NetworkForm extends PureComponent {
const chainIdIsUnchanged = const chainIdIsUnchanged =
typeof propsChainId === 'string' && typeof propsChainId === 'string' &&
propsChainId.toLowerCase().startsWith('0x') && propsChainId.toLowerCase().startsWith('0x') &&
stateChainId === this.getDisplayChainIdFromProps() stateChainId === this.getDisplayChainId(propsChainId)
return ( return (
stateRpcUrl === rpcUrl && stateRpcUrl === rpcUrl &&
@ -424,6 +441,7 @@ export default class NetworkForm extends PureComponent {
!networksTabIsInAddMode && !isCurrentRpcTarget && !viewOnly !networksTabIsInAddMode && !isCurrentRpcTarget && !viewOnly
const isSubmitDisabled = const isSubmitDisabled =
this.isSubmitting() ||
this.stateIsUnchanged() || this.stateIsUnchanged() ||
!rpcUrl || !rpcUrl ||
!chainId || !chainId ||

Loading…
Cancel
Save