-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Cancel tx JS #4958
Cancel tx JS #4958
Changes from 43 commits
49ed3d8
a9ae42c
eb8fe28
3d31031
eb3e79c
45d1641
f871389
aa47572
35d959e
2235923
65c6390
14dd162
9766508
b57aecd
03c19fd
42dd28a
a9662fa
b7c8c16
89b4343
1aeec64
eb8e56d
131b837
c56ce69
c2ce35c
06c9951
8e17b08
b8a7d62
4d9ca26
684ab6c
c6195d6
85929ea
35aad6c
acf79fe
3c4199b
2c04f54
2d03df7
c9535bf
8d01b28
666f59f
10eda45
ca73bc8
bd05a8c
0f4f40d
3bf3972
fb72ab4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,9 @@ | |
# mac stuff | ||
.DS_Store | ||
|
||
# npm stuff | ||
npm-debug.log | ||
|
||
# gdb files | ||
.gdb_history | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1833,7 +1833,14 @@ export default { | |
example: { | ||
from: '0xb60e8dd61c5d32be8058bb8eb970870f07233155', | ||
to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567', | ||
value: fromDecimal(2441406250) | ||
gas: fromDecimal(30400), | ||
gasPrice: fromDecimal(10000000000000), | ||
value: fromDecimal(2441406250), | ||
data: '0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675', | ||
condition: { | ||
block: 354221, | ||
time: new Date() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same with these. |
||
} | ||
} | ||
} | ||
], | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,8 @@ | |
// along with Parity. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
import moment from 'moment'; | ||
import dateDifference from 'date-difference'; | ||
import { FormattedMessage } from 'react-intl'; | ||
import React, { Component, PropTypes } from 'react'; | ||
import { connect } from 'react-redux'; | ||
import { Link } from 'react-router'; | ||
|
@@ -35,19 +37,29 @@ class TxRow extends Component { | |
static propTypes = { | ||
accountAddresses: PropTypes.array.isRequired, | ||
address: PropTypes.string.isRequired, | ||
blockNumber: PropTypes.object, | ||
contractAddresses: PropTypes.array.isRequired, | ||
netVersion: PropTypes.string.isRequired, | ||
tx: PropTypes.object.isRequired, | ||
|
||
block: PropTypes.object, | ||
className: PropTypes.string, | ||
cancelTransaction: PropTypes.func, | ||
editTransaction: PropTypes.func, | ||
historic: PropTypes.bool | ||
}; | ||
|
||
static defaultProps = { | ||
historic: true | ||
}; | ||
|
||
state = { | ||
isCancelOpen: false, | ||
isEditOpen: false, | ||
canceled: false, | ||
editing: false | ||
}; | ||
|
||
render () { | ||
const { address, className, historic, netVersion, tx } = this.props; | ||
|
||
|
@@ -137,11 +149,116 @@ class TxRow extends Component { | |
return ( | ||
<td className={ styles.timestamp }> | ||
<div>{ blockNumber && block ? moment(block.timestamp).fromNow() : null }</div> | ||
<div>{ blockNumber ? _blockNumber.toFormat() : 'Pending' }</div> | ||
<div>{ blockNumber ? _blockNumber.toFormat() : this.renderCancelToggle() }</div> | ||
</td> | ||
); | ||
} | ||
|
||
renderCancelToggle () { | ||
const { canceled, editing, isCancelOpen, isEditOpen } = this.state; | ||
|
||
if (canceled) { | ||
return ( | ||
<div className={ styles.pending }> | ||
<FormattedMessage | ||
lassName={ styles.uppercase } | ||
id='ui.txList.txRow.canceled' | ||
defaultMessage='Canceled' | ||
/> | ||
</div> | ||
); | ||
} | ||
|
||
if (editing) { | ||
return ( | ||
<div className={ styles.pending }> | ||
<div className={ styles.uppercase }> | ||
<FormattedMessage | ||
id='ui.txList.txRow.editing' | ||
defaultMessage='Editing' | ||
/> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
if (!isCancelOpen && !isEditOpen) { | ||
const pendingStatus = this.getCondition(); | ||
|
||
if (pendingStatus === 'submitting') { | ||
return ( | ||
<div className={ styles.pending }> | ||
<div /> | ||
<div className={ styles.uppercase }> | ||
<FormattedMessage | ||
id='ui.txList.txRow.submitting' | ||
defaultMessage='Submitting' | ||
/> | ||
</div> | ||
</div> | ||
); | ||
} | ||
return ( | ||
<div className={ styles.pending }> | ||
<span> | ||
<FormattedMessage | ||
id='ui.txList.txRow.time' | ||
defaultMessage='{ which }' | ||
values={ { which: pendingStatus } } | ||
/> | ||
</span> | ||
<div className={ styles.uppercase }> | ||
<FormattedMessage | ||
id='ui.txList.txRow.scheduled' | ||
defaultMessage='Scheduled' | ||
/> | ||
</div> | ||
<a onClick={ this.setEdit } className={ styles.uppercase }> | ||
<FormattedMessage | ||
id='ui.txList.txRow.edit' | ||
defaultMessage='Edit' | ||
/> | ||
</a> | ||
<span>{' | '}</span> | ||
<a onClick={ this.setCancel } className={ styles.uppercase }> | ||
<FormattedMessage | ||
id='ui.txList.txRow.cancel' | ||
defaultMessage='Cancel' | ||
/> | ||
</a> | ||
</div> | ||
); | ||
} | ||
|
||
return ( | ||
<div className={ styles.pending }> | ||
<div /> | ||
<div className={ styles.uppercase }> | ||
<FormattedMessage | ||
id='ui.txList.txRow.verify' | ||
defaultMessage='Are you sure?' | ||
/> | ||
</div> | ||
<a onClick={ (isCancelOpen) ? this.cancelTx : this.editTx }> | ||
<FormattedMessage | ||
id='ui.txList.txRow.verify.cancelEdit' | ||
defaultMessage='{ which }' | ||
values={ { | ||
which: `${(isCancelOpen) ? 'Cancel' : 'Edit'}` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should get a big red/yellow warning for transaction cancellation since it's not reliable as mentioned in RPC docs. There are two separate cases:
When editing transaction we should also differentiate those two cases. (1) is safe to edit, but (2) should always increase the gas price when edited (it increases the chance of actually replacing the transaction that was already propagated). PM me for more details :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (2) should also zero-out the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These should be FormattedMessage as well (Should also be translatable) |
||
} } | ||
/> | ||
</a> | ||
<span>{' | '}</span> | ||
<a onClick={ this.revertEditCancel }> | ||
<FormattedMessage | ||
id='ui.txList.txRow.verify.nevermind' | ||
defaultMessage='Nevermind' | ||
/> | ||
</a> | ||
</div> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FormattedMessage & inline closures. |
||
); | ||
} | ||
|
||
getIsKnownContract (address) { | ||
const { contractAddresses } = this.props; | ||
|
||
|
@@ -165,6 +282,48 @@ class TxRow extends Component { | |
|
||
return `/addresses/${address}`; | ||
} | ||
|
||
getCondition = () => { | ||
const { blockNumber, tx } = this.props; | ||
let { time, block } = tx.condition; | ||
|
||
if (time) { | ||
if ((time.getTime() - Date.now()) >= 0) { | ||
return `${dateDifference(new Date(), time, { compact: true })} left`; | ||
} else { | ||
return 'submitting'; | ||
} | ||
} else if (blockNumber) { | ||
block = blockNumber.minus(block); | ||
return (block.toNumber() < 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FormattedMessage here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All string returns pulled from |
||
? block.abs().toFormat(0) + ' blocks left' | ||
: 'submitting'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just make the strings here translatable. (Also line 247 is still, as part of the value for |
||
} | ||
} | ||
|
||
cancelTx = () => { | ||
const { cancelTransaction, tx } = this.props; | ||
|
||
cancelTransaction(this, tx); | ||
} | ||
|
||
editTx = () => { | ||
const { editTransaction, tx } = this.props; | ||
|
||
editTransaction(this, tx); | ||
} | ||
|
||
setCancel = () => { | ||
this.setState({ isCancelOpen: true }); | ||
} | ||
|
||
setEdit = () => { | ||
this.setState({ isEditOpen: true }); | ||
} | ||
|
||
revertEditCancel = () => { | ||
this.setState({ isCancelOpen: false, isEditOpen: false }); | ||
} | ||
} | ||
|
||
function mapStateToProps (initState) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would just remove the
fromDecimal
wrappers here, i.e. the response should rather be what we receive via the actual RPC, raw.