mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-26 12:29:06 +01:00
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
This commit is contained in:
commit
6b38017b23
@ -9,6 +9,14 @@ import Tooltip from '../../../../components/ui/tooltip'
|
||||
import { isPrefixedFormattedHexString } from '../../../../../../app/scripts/lib/util'
|
||||
import { jsonRpcRequest } from '../../../../helpers/utils/util'
|
||||
|
||||
const FORM_STATE_KEYS = [
|
||||
'rpcUrl',
|
||||
'chainId',
|
||||
'ticker',
|
||||
'networkName',
|
||||
'blockExplorerUrl',
|
||||
]
|
||||
|
||||
export default class NetworkForm extends PureComponent {
|
||||
static contextTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
@ -35,25 +43,17 @@ export default class NetworkForm extends PureComponent {
|
||||
|
||||
state = {
|
||||
rpcUrl: this.props.rpcUrl,
|
||||
chainId: this.getDisplayChainIdFromProps(),
|
||||
chainId: this.getDisplayChainId(this.props.chainId),
|
||||
ticker: this.props.ticker,
|
||||
networkName: this.props.networkName,
|
||||
blockExplorerUrl: this.props.blockExplorerUrl,
|
||||
errors: {},
|
||||
isSubmitting: false,
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
rpcUrl: prevRpcUrl,
|
||||
networksTabIsInAddMode: prevAddMode,
|
||||
} = prevProps
|
||||
const {
|
||||
rpcUrl,
|
||||
ticker,
|
||||
networkName,
|
||||
networksTabIsInAddMode,
|
||||
blockExplorerUrl,
|
||||
} = this.props
|
||||
const { networksTabIsInAddMode: prevAddMode } = prevProps
|
||||
const { networksTabIsInAddMode } = this.props
|
||||
|
||||
if (!prevAddMode && networksTabIsInAddMode) {
|
||||
this.setState({
|
||||
@ -63,16 +63,15 @@ export default class NetworkForm extends PureComponent {
|
||||
networkName: '',
|
||||
blockExplorerUrl: '',
|
||||
errors: {},
|
||||
isSubmitting: false,
|
||||
})
|
||||
} else if (prevRpcUrl !== rpcUrl) {
|
||||
this.setState({
|
||||
rpcUrl,
|
||||
chainId: this.getDisplayChainIdFromProps(),
|
||||
ticker,
|
||||
networkName,
|
||||
blockExplorerUrl,
|
||||
errors: {},
|
||||
})
|
||||
} else {
|
||||
for (const key of FORM_STATE_KEYS) {
|
||||
if (prevProps[key] !== this.props[key]) {
|
||||
this.resetForm()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,86 +92,100 @@ export default class NetworkForm extends PureComponent {
|
||||
}
|
||||
|
||||
resetForm() {
|
||||
const { rpcUrl, ticker, networkName, blockExplorerUrl } = this.props
|
||||
const {
|
||||
rpcUrl,
|
||||
chainId,
|
||||
ticker,
|
||||
networkName,
|
||||
blockExplorerUrl,
|
||||
} = this.props
|
||||
|
||||
this.setState({
|
||||
rpcUrl,
|
||||
chainId: this.getDisplayChainIdFromProps(),
|
||||
chainId: this.getDisplayChainId(chainId),
|
||||
ticker,
|
||||
networkName,
|
||||
blockExplorerUrl,
|
||||
errors: {},
|
||||
isSubmitting: false,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the chainId is always displayed in decimal, even though
|
||||
* it's stored in hexadecimal.
|
||||
* Attempts to convert the given chainId to a decimal string, for display
|
||||
* 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.
|
||||
*
|
||||
* @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() {
|
||||
const { chainId: propsChainId } = this.props
|
||||
|
||||
if (
|
||||
!propsChainId ||
|
||||
typeof propsChainId !== 'string' ||
|
||||
!propsChainId.startsWith('0x')
|
||||
) {
|
||||
return propsChainId
|
||||
getDisplayChainId(chainId) {
|
||||
if (!chainId || typeof chainId !== 'string' || !chainId.startsWith('0x')) {
|
||||
return chainId
|
||||
}
|
||||
return new BigNumber(propsChainId, 16).toString(10)
|
||||
return new BigNumber(chainId, 16).toString(10)
|
||||
}
|
||||
|
||||
onSubmit = async () => {
|
||||
const {
|
||||
setRpcTarget,
|
||||
rpcUrl: propsRpcUrl,
|
||||
editRpc,
|
||||
rpcPrefs = {},
|
||||
onClear,
|
||||
networksTabIsInAddMode,
|
||||
} = this.props
|
||||
const {
|
||||
networkName,
|
||||
rpcUrl,
|
||||
chainId: stateChainId,
|
||||
ticker,
|
||||
blockExplorerUrl,
|
||||
} = this.state
|
||||
this.setState({
|
||||
isSubmitting: true,
|
||||
})
|
||||
|
||||
const formChainId = stateChainId.trim().toLowerCase()
|
||||
// Ensure chainId is a 0x-prefixed, lowercase hex string
|
||||
let chainId = formChainId
|
||||
if (!chainId.startsWith('0x')) {
|
||||
chainId = `0x${new BigNumber(chainId, 10).toString(16)}`
|
||||
}
|
||||
try {
|
||||
const {
|
||||
setRpcTarget,
|
||||
rpcUrl: propsRpcUrl,
|
||||
editRpc,
|
||||
rpcPrefs = {},
|
||||
onClear,
|
||||
networksTabIsInAddMode,
|
||||
} = this.props
|
||||
const {
|
||||
networkName,
|
||||
rpcUrl,
|
||||
chainId: stateChainId,
|
||||
ticker,
|
||||
blockExplorerUrl,
|
||||
} = this.state
|
||||
|
||||
if (!(await this.validateChainIdOnSubmit(formChainId, chainId, rpcUrl))) {
|
||||
return
|
||||
}
|
||||
const formChainId = stateChainId.trim().toLowerCase()
|
||||
// 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) {
|
||||
await editRpc(propsRpcUrl, rpcUrl, chainId, ticker, networkName, {
|
||||
blockExplorerUrl: blockExplorerUrl || rpcPrefs.blockExplorerUrl,
|
||||
...rpcPrefs,
|
||||
})
|
||||
} else {
|
||||
await setRpcTarget(rpcUrl, chainId, ticker, networkName, {
|
||||
blockExplorerUrl: blockExplorerUrl || rpcPrefs.blockExplorerUrl,
|
||||
...rpcPrefs,
|
||||
})
|
||||
}
|
||||
if (!(await this.validateChainIdOnSubmit(formChainId, chainId, rpcUrl))) {
|
||||
this.setState({
|
||||
isSubmitting: false,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (networksTabIsInAddMode) {
|
||||
onClear()
|
||||
} else {
|
||||
// After this point, isSubmitting will be reset in componentDidUpdate
|
||||
if (propsRpcUrl && rpcUrl !== propsRpcUrl) {
|
||||
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({
|
||||
chainId: this.getDisplayChainIdFromProps(),
|
||||
isSubmitting: false,
|
||||
})
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,6 +210,10 @@ export default class NetworkForm extends PureComponent {
|
||||
})
|
||||
}
|
||||
|
||||
isSubmitting() {
|
||||
return this.state.isSubmitting
|
||||
}
|
||||
|
||||
stateIsUnchanged() {
|
||||
const {
|
||||
rpcUrl,
|
||||
@ -220,7 +237,7 @@ export default class NetworkForm extends PureComponent {
|
||||
const chainIdIsUnchanged =
|
||||
typeof propsChainId === 'string' &&
|
||||
propsChainId.toLowerCase().startsWith('0x') &&
|
||||
stateChainId === this.getDisplayChainIdFromProps()
|
||||
stateChainId === this.getDisplayChainId(propsChainId)
|
||||
|
||||
return (
|
||||
stateRpcUrl === rpcUrl &&
|
||||
@ -424,6 +441,7 @@ export default class NetworkForm extends PureComponent {
|
||||
!networksTabIsInAddMode && !isCurrentRpcTarget && !viewOnly
|
||||
|
||||
const isSubmitDisabled =
|
||||
this.isSubmitting() ||
|
||||
this.stateIsUnchanged() ||
|
||||
!rpcUrl ||
|
||||
!chainId ||
|
||||
|
Loading…
Reference in New Issue
Block a user