Add "Retry" option for failed transactions (#7296)

* Begin mocking out retry ui

* Remove "Failed"

* I guess this works?

* Update corresponding test

* wip

* Ok, this appears to be working now

* cleanup

* Move this back to 3

* I don't think I need this

* Rename showRetry to showSpeedUp

* Address PR feedback

* Remove notes

* Rename shouldShowRetry -> shouldShowSpeedUp

* oops
feature/default_network_editable
ricky 5 years ago committed by Dan J Miller
parent c8878f46d4
commit af888d0ab2
  1. 3
      app/_locales/en/messages.json
  2. 3
      ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js
  3. 13
      ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js
  4. 1
      ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js
  5. 2
      ui/app/components/app/transaction-list-item-details/tests/transaction-list-item-details.component.test.js
  6. 15
      ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js
  7. 7
      ui/app/components/app/transaction-list-item/transaction-list-item.component.js
  8. 4
      ui/app/components/app/transaction-list/transaction-list.component.js
  9. 6
      ui/app/pages/routes/index.js
  10. 23
      ui/app/store/actions.js

@ -1442,6 +1442,9 @@
"viewOnEtherscan": {
"message": "View on Etherscan"
},
"retryTransaction": {
"message": "Retry Transaction"
},
"visitWebSite": {
"message": "Visit our web site"
},

@ -42,6 +42,7 @@ export default class GasModalPageContainer extends Component {
]),
customPriceIsSafe: PropTypes.bool,
isSpeedUp: PropTypes.bool,
isRetry: PropTypes.bool,
disableSave: PropTypes.bool,
isEthereumNetwork: PropTypes.bool,
}
@ -80,6 +81,7 @@ export default class GasModalPageContainer extends Component {
gasEstimatesLoading,
customPriceIsSafe,
isSpeedUp,
isRetry,
infoRowProps: {
transactionFee,
},
@ -99,6 +101,7 @@ export default class GasModalPageContainer extends Component {
gasEstimatesLoading={gasEstimatesLoading}
customPriceIsSafe={customPriceIsSafe}
isSpeedUp={isSpeedUp}
isRetry={isRetry}
isEthereumNetwork={isEthereumNetwork}
/>
)

@ -6,6 +6,7 @@ import {
setGasLimit,
setGasPrice,
createSpeedUpTransaction,
createRetryTransaction,
hideSidebar,
updateSendAmount,
setGasTotal,
@ -153,6 +154,7 @@ const mapStateToProps = (state, ownProps) => {
},
transaction: txData || transaction,
isSpeedUp: transaction.status === 'submitted',
isRetry: transaction.status === 'failed',
txId: transaction.id,
insufficientBalance,
gasEstimatesLoading,
@ -187,6 +189,9 @@ const mapDispatchToProps = dispatch => {
createSpeedUpTransaction: (txId, gasPrice) => {
return dispatch(createSpeedUpTransaction(txId, gasPrice))
},
createRetryTransaction: (txId, gasPrice) => {
return dispatch(createRetryTransaction(txId, gasPrice))
},
hideGasButtonGroup: () => dispatch(hideGasButtonGroup()),
setCustomTimeEstimate: (timeEstimateInSeconds) => dispatch(setCustomTimeEstimate(timeEstimateInSeconds)),
hideSidebar: () => dispatch(hideSidebar()),
@ -206,6 +211,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
isConfirm,
txId,
isSpeedUp,
isRetry,
insufficientBalance,
maxModeOn,
customGasPrice,
@ -221,6 +227,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
setGasData: dispatchSetGasData,
updateConfirmTxGasAndCalculate: dispatchUpdateConfirmTxGasAndCalculate,
createSpeedUpTransaction: dispatchCreateSpeedUpTransaction,
createRetryTransaction: dispatchCreateRetryTransaction,
hideSidebar: dispatchHideSidebar,
cancelAndClose: dispatchCancelAndClose,
hideModal: dispatchHideModal,
@ -248,6 +255,10 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
dispatchCreateSpeedUpTransaction(txId, gasPrice)
dispatchHideSidebar()
dispatchCancelAndClose()
} else if (isRetry) {
dispatchCreateRetryTransaction(txId, gasPrice)
dispatchHideSidebar()
dispatchCancelAndClose()
} else {
dispatchSetGasData(gasLimit, gasPrice)
dispatchHideGasButtonGroup()
@ -268,7 +279,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
},
cancelAndClose: () => {
dispatchCancelAndClose()
if (isSpeedUp) {
if (isSpeedUp || isRetry) {
dispatchHideSidebar()
}
},

@ -157,6 +157,7 @@ describe('gas-modal-page-container container', () => {
},
insufficientBalance: true,
isSpeedUp: false,
isRetry: false,
txId: 34,
isEthereumNetwork: true,
isMainnet: true,

@ -70,7 +70,7 @@ describe('TransactionListItemDetails Component', () => {
const wrapper = shallow(
<TransactionListItemDetails
transactionGroup={transactionGroup}
showRetry={true}
showSpeedUp={true}
/>,
{ context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } }
)

@ -21,6 +21,7 @@ export default class TransactionListItemDetails extends PureComponent {
onCancel: PropTypes.func,
onRetry: PropTypes.func,
showCancel: PropTypes.bool,
showSpeedUp: PropTypes.bool,
showRetry: PropTypes.bool,
isEarliestNonce: PropTypes.bool,
cancelDisabled: PropTypes.bool,
@ -123,6 +124,7 @@ export default class TransactionListItemDetails extends PureComponent {
const { justCopied } = this.state
const {
transactionGroup,
showSpeedUp,
showRetry,
onCancel,
onRetry,
@ -138,7 +140,7 @@ export default class TransactionListItemDetails extends PureComponent {
<div>{ t('details') }</div>
<div className="transaction-list-item-details__header-buttons">
{
showRetry && (
showSpeedUp && (
<Button
type="raised"
onClick={this.handleRetry}
@ -172,6 +174,17 @@ export default class TransactionListItemDetails extends PureComponent {
<img src="/images/arrow-popout.svg" />
</Button>
</Tooltip>
{
showRetry && <Tooltip title={blockExplorerUrl ? t('viewOnCustomBlockExplorer', [blockExplorerUrl]) : t('retryTransaction')}>
<Button
type="raised"
onClick={this.handleRetry}
className="transaction-list-item-details__header-button"
>
<i className="fa fa-refresh"></i>
</Button>
</Tooltip>
}
</div>
</div>
<div className="transaction-list-item-details__body">

@ -24,7 +24,7 @@ export default class TransactionListItem extends PureComponent {
showCancelModal: PropTypes.func,
showCancel: PropTypes.bool,
hasEnoughCancelGas: PropTypes.bool,
showRetry: PropTypes.bool,
showSpeedUp: PropTypes.bool,
isEarliestNonce: PropTypes.bool,
showFiat: PropTypes.bool,
token: PropTypes.object,
@ -177,7 +177,7 @@ export default class TransactionListItem extends PureComponent {
primaryTransaction,
showCancel,
hasEnoughCancelGas,
showRetry,
showSpeedUp,
tokenData,
transactionGroup,
rpcPrefs,
@ -233,7 +233,8 @@ export default class TransactionListItem extends PureComponent {
<TransactionListItemDetails
transactionGroup={transactionGroup}
onRetry={this.handleRetry}
showRetry={showRetry}
showSpeedUp={showSpeedUp}
showRetry={getStatusKey(primaryTransaction) === 'failed'}
isEarliestNonce={isEarliestNonce}
onCancel={this.handleCancel}
showCancel={showCancel}

@ -37,7 +37,7 @@ export default class TransactionList extends PureComponent {
}
}
shouldShowRetry = (transactionGroup, isEarliestNonce) => {
shouldShowSpeedUp = (transactionGroup, isEarliestNonce) => {
const { transactions = [], hasRetried } = transactionGroup
const [earliestTransaction = {}] = transactions
const { submittedTime } = earliestTransaction
@ -100,7 +100,7 @@ export default class TransactionList extends PureComponent {
<TransactionListItem
transactionGroup={transactionGroup}
key={`${transactionGroup.nonce}:${index}`}
showRetry={isPendingTx && this.shouldShowRetry(transactionGroup, index === 0)}
showSpeedUp={isPendingTx && this.shouldShowSpeedUp(transactionGroup, index === 0)}
showCancel={isPendingTx && this.shouldShowCancel(transactionGroup)}
isEarliestNonce={isPendingTx && index === 0}
token={selectedToken}

@ -206,6 +206,10 @@ class Routes extends Component {
}
: null
const sidebarShouldClose = sidebarTransaction &&
!sidebarTransaction.status === 'failed' &&
!submittedPendingTransactions.find(({ id }) => id === sidebarTransaction.id)
return (
<div
className={classnames('app', { 'mouse-user-styles': isMouseUser})}
@ -232,7 +236,7 @@ class Routes extends Component {
}
<Sidebar
sidebarOpen={sidebarIsOpen}
sidebarShouldClose={sidebarTransaction && !submittedPendingTransactions.find(({ id }) => id === sidebarTransaction.id)}
sidebarShouldClose={sidebarShouldClose}
hideSidebar={this.props.hideSidebar}
transitionName={sidebarTransitionName}
type={sidebarType}

@ -350,6 +350,7 @@ var actions = {
createCancelTransaction,
createSpeedUpTransaction,
createRetryTransaction,
approveProviderRequestByOrigin,
rejectProviderRequestByOrigin,
@ -1860,6 +1861,28 @@ function createSpeedUpTransaction (txId, customGasPrice) {
}
}
function createRetryTransaction (txId, customGasPrice) {
log.debug('background.createRetryTransaction')
let newTx
return dispatch => {
return new Promise((resolve, reject) => {
background.createSpeedUpTransaction(txId, customGasPrice, (err, newState) => {
if (err) {
dispatch(actions.displayWarning(err.message))
return reject(err)
}
const { selectedAddressTxList } = newState
newTx = selectedAddressTxList[selectedAddressTxList.length - 1]
resolve(newState)
})
})
.then(newState => dispatch(actions.updateMetamaskState(newState)))
.then(() => newTx)
}
}
//
// config
//

Loading…
Cancel
Save