Simple GUI for local transactions
This commit is contained in:
parent
cd686b5d68
commit
ff27bbcb4f
@ -15,7 +15,7 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { inAddress, inData, inHex, inNumber16, inOptions } from '../../format/input';
|
||||
import { outAccountInfo, outAddress, outHistogram, outNumber, outPeers } from '../../format/output';
|
||||
import { outAccountInfo, outAddress, outHistogram, outNumber, outPeers, outTransaction } from '../../format/output';
|
||||
|
||||
export default class Parity {
|
||||
constructor (transport) {
|
||||
@ -117,16 +117,27 @@ export default class Parity {
|
||||
.execute('parity_hashContent', url);
|
||||
}
|
||||
|
||||
importGethAccounts (accounts) {
|
||||
return this._transport
|
||||
.execute('parity_importGethAccounts', (accounts || []).map(inAddress))
|
||||
.then((accounts) => (accounts || []).map(outAddress));
|
||||
}
|
||||
|
||||
listGethAccounts () {
|
||||
return this._transport
|
||||
.execute('parity_listGethAccounts')
|
||||
.then((accounts) => (accounts || []).map(outAddress));
|
||||
}
|
||||
|
||||
importGethAccounts (accounts) {
|
||||
localTransactions () {
|
||||
return this._transport
|
||||
.execute('parity_importGethAccounts', (accounts || []).map(inAddress))
|
||||
.then((accounts) => (accounts || []).map(outAddress));
|
||||
.execute('parity_localTransactions')
|
||||
.then(transactions => {
|
||||
Object.values(transactions)
|
||||
.filter(tx => tx.transaction)
|
||||
.map(tx => tx.transaction = outTransaction(tx.transaction));
|
||||
return transactions;
|
||||
});
|
||||
}
|
||||
|
||||
minGasPrice () {
|
||||
@ -192,6 +203,17 @@ export default class Parity {
|
||||
.execute('parity_nodeName');
|
||||
}
|
||||
|
||||
pendingTransactions () {
|
||||
return this._transport
|
||||
.execute('parity_pendingTransactions')
|
||||
.then(data => data.map(outTransaction));
|
||||
}
|
||||
|
||||
pendingTransactionsStats () {
|
||||
return this._transport
|
||||
.execute('parity_pendingTransactionsStats');
|
||||
}
|
||||
|
||||
phraseToAddress (phrase) {
|
||||
return this._transport
|
||||
.execute('parity_phraseToAddress', phrase)
|
||||
|
17
js/src/dapps/localtx.html
Normal file
17
js/src/dapps/localtx.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
|
||||
<title>Local transactions Viewer</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script src="vendor.js"></script>
|
||||
<script src="commons.js"></script>
|
||||
<script src="/parity-utils/parity.js"></script>
|
||||
<script src="localtx.js"></script>
|
||||
</body>
|
||||
</html>
|
33
js/src/dapps/localtx.js
Normal file
33
js/src/dapps/localtx.js
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ReactDOM from 'react-dom';
|
||||
import React from 'react';
|
||||
|
||||
import injectTapEventPlugin from 'react-tap-event-plugin';
|
||||
injectTapEventPlugin();
|
||||
|
||||
import Application from './localtx/Application';
|
||||
|
||||
import '../../assets/fonts/Roboto/font.css';
|
||||
import '../../assets/fonts/RobotoMono/font.css';
|
||||
import './style.css';
|
||||
import './localtx.html';
|
||||
|
||||
ReactDOM.render(
|
||||
<Application />,
|
||||
document.querySelector('#container')
|
||||
);
|
197
js/src/dapps/localtx/Application/application.js
Normal file
197
js/src/dapps/localtx/Application/application.js
Normal file
@ -0,0 +1,197 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import BigNumber from 'bignumber.js';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { api } from '../parity';
|
||||
|
||||
import { Transaction, LocalTransaction } from '../Transaction';
|
||||
|
||||
export default class Application extends Component {
|
||||
state = {
|
||||
loading: true,
|
||||
transactions: [],
|
||||
localTransactions: {}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const poll = () => this.fetchTransactionData().then(poll);
|
||||
this._timeout = setTimeout(poll, 2000);
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
clearTimeout(this._timeout);
|
||||
}
|
||||
|
||||
fetchTransactionData () {
|
||||
return Promise.all([
|
||||
api.parity.pendingTransactions(),
|
||||
api.parity.pendingTransactionsStats(),
|
||||
api.parity.localTransactions(),
|
||||
]).then(([pending, stats, local]) => {
|
||||
// Combine results together
|
||||
const transactions = pending.map(tx => {
|
||||
return {
|
||||
transaction: tx,
|
||||
stats: stats[tx.hash],
|
||||
isLocal: !!local[tx.hash]
|
||||
};
|
||||
});
|
||||
|
||||
// Add transaction data to locals
|
||||
transactions
|
||||
.filter(tx => tx.isLocal)
|
||||
.map(data => {
|
||||
const tx = data.transaction;
|
||||
local[tx.hash].transaction = tx;
|
||||
local[tx.hash].stats = data.stats;
|
||||
});
|
||||
|
||||
// Convert local transactions to array
|
||||
const localTransactions = Object.keys(local).map(hash => {
|
||||
const data = local[hash];
|
||||
data.txHash = hash;
|
||||
return data;
|
||||
});
|
||||
|
||||
// Sort local transactions by nonce (move future to the end)
|
||||
localTransactions.sort((a, b) => {
|
||||
a = a.transaction || {};
|
||||
b = b.transaction || {};
|
||||
|
||||
if (a.from && b.from && a.from !== b.from) {
|
||||
return a.from < b.from;
|
||||
}
|
||||
|
||||
if (!a.nonce || !b.nonce) {
|
||||
return !a.nonce ? 1 : -1;
|
||||
}
|
||||
|
||||
return new BigNumber(a.nonce).comparedTo(new BigNumber(b.nonce));
|
||||
});
|
||||
|
||||
this.setState({
|
||||
loading: false,
|
||||
transactions,
|
||||
localTransactions
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render () {
|
||||
const { loading } = this.state;
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div>Loading...</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={ { padding: '1rem 2rem'}}>
|
||||
<h1>Your past local transactions</h1>
|
||||
{ this.renderLocals() }
|
||||
<h1>Transactions in the queue</h1>
|
||||
{ this.renderQueueSummary() }
|
||||
{ this.renderQueue() }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderQueueSummary () {
|
||||
const { transactions } = this.state;
|
||||
if (!transactions.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const count = transactions.length;
|
||||
const locals = transactions.filter(tx => tx.isLocal).length;
|
||||
const fee = transactions
|
||||
.map(tx => tx.transaction)
|
||||
.map(tx => tx.gasPrice.mul(tx.gas))
|
||||
.reduce((sum, fee) => sum.add(fee), new BigNumber(0));
|
||||
|
||||
return (
|
||||
<h3>
|
||||
Count: <strong>{ locals ? `${count} (${locals})` : count }</strong>
|
||||
|
||||
Total Fee: <strong>{ api.util.fromWei(fee).toFixed(3) } ETH</strong>
|
||||
</h3>
|
||||
);
|
||||
}
|
||||
|
||||
renderQueue () {
|
||||
const { transactions } = this.state;
|
||||
if (!transactions.length) {
|
||||
return (
|
||||
<h3>The queue seems is empty.</h3>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<table cellSpacing='0'>
|
||||
<thead>
|
||||
{ Transaction.renderHeader() }
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
transactions.map((tx, idx) => (
|
||||
<Transaction
|
||||
key={ tx.transaction.hash }
|
||||
idx={ idx + 1}
|
||||
isLocal={ tx.isLocal }
|
||||
transaction={ tx.transaction }
|
||||
stats={ tx.stats }
|
||||
/>
|
||||
))
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
renderLocals () {
|
||||
const { localTransactions } = this.state;
|
||||
if (!localTransactions.length) {
|
||||
return (
|
||||
<h3>You haven't sent any transactions yet.</h3>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<table cellSpacing='0'>
|
||||
<thead>
|
||||
{ LocalTransaction.renderHeader() }
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
localTransactions.map(tx => (
|
||||
<LocalTransaction
|
||||
key={ tx.txHash }
|
||||
hash={ tx.txHash }
|
||||
transaction={ tx.transaction }
|
||||
status={ tx.status }
|
||||
stats={ tx.stats }
|
||||
details={ tx }
|
||||
/>
|
||||
))
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
32
js/src/dapps/localtx/Application/application.spec.js
Normal file
32
js/src/dapps/localtx/Application/application.spec.js
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import '../../../environment/tests';
|
||||
|
||||
import Application from './application';
|
||||
|
||||
describe('localtx/Application', () => {
|
||||
describe('rendering', () => {
|
||||
it('renders without crashing', () => {
|
||||
const rendered = shallow(<Application />);
|
||||
|
||||
expect(rendered).to.be.defined;
|
||||
});
|
||||
});
|
||||
});
|
17
js/src/dapps/localtx/Application/index.js
Normal file
17
js/src/dapps/localtx/Application/index.js
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './application';
|
17
js/src/dapps/localtx/Transaction/index.js
Normal file
17
js/src/dapps/localtx/Transaction/index.js
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export { Transaction, LocalTransaction } from './transaction';
|
31
js/src/dapps/localtx/Transaction/transaction.css
Normal file
31
js/src/dapps/localtx/Transaction/transaction.css
Normal file
@ -0,0 +1,31 @@
|
||||
.from {
|
||||
white-space: nowrap;
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.transaction {
|
||||
td {
|
||||
padding: 7px 15px;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
padding: 7px 0;
|
||||
}
|
||||
|
||||
&.local {
|
||||
background: #8bc34a;
|
||||
}
|
||||
}
|
||||
|
||||
.nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.edit {
|
||||
label, input {
|
||||
display: block;
|
||||
}
|
||||
}
|
359
js/src/dapps/localtx/Transaction/transaction.js
Normal file
359
js/src/dapps/localtx/Transaction/transaction.js
Normal file
@ -0,0 +1,359 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { api } from '../parity';
|
||||
|
||||
import styles from './transaction.css';
|
||||
|
||||
import IdentityIcon from '../../githubhint/IdentityIcon';
|
||||
|
||||
class BaseTransaction extends Component {
|
||||
|
||||
shortHash (hash) {
|
||||
return `${hash.substr(0, 6)}..${hash.substr(hash.length - 4)}`;
|
||||
}
|
||||
|
||||
renderHash (hash) {
|
||||
return (
|
||||
<code title={ hash }>
|
||||
{ this.shortHash(hash) }
|
||||
</code>
|
||||
);
|
||||
}
|
||||
|
||||
renderFrom (transaction) {
|
||||
if (!transaction) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
return (
|
||||
<div title={ transaction.from } className={ styles.from }>
|
||||
<IdentityIcon
|
||||
address={ transaction.from }
|
||||
/>
|
||||
0x{ transaction.nonce.toString(16) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderGasPrice (transaction) {
|
||||
if (!transaction) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
return (
|
||||
<span title={ `${transaction.gasPrice.toFormat(0) } wei`}>
|
||||
{ api.util.fromWei(transaction.gasPrice, 'shannon').toFormat(2) } shannon
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
renderGas (transaction) {
|
||||
if (!transaction) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
return (
|
||||
<span title={ `${transaction.gas.toFormat(0)} Gas` }>
|
||||
{ transaction.gas.div(10**6).toFormat(3) } MGas
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
renderPropagation (stats) {
|
||||
const noOfPeers = Object.keys(stats.propagatedTo).length;
|
||||
const noOfPropagations = Object.values(stats.propagatedTo).reduce((sum, val) => sum + val, 0);
|
||||
|
||||
return (
|
||||
<span className={ styles.nowrap }>
|
||||
{ noOfPropagations } ({ noOfPeers } peers)
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Transaction extends BaseTransaction {
|
||||
|
||||
static propTypes = {
|
||||
idx: PropTypes.number.isRequired,
|
||||
transaction: PropTypes.object.isRequired,
|
||||
isLocal: PropTypes.bool,
|
||||
stats: PropTypes.object
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
isLocal: false,
|
||||
stats: {
|
||||
firstSeen: 0,
|
||||
propagatedTo: {}
|
||||
}
|
||||
};
|
||||
|
||||
static renderHeader () {
|
||||
return (
|
||||
<tr className={ styles.header }>
|
||||
<th></th>
|
||||
<th>
|
||||
Transaction
|
||||
</th>
|
||||
<th>
|
||||
From
|
||||
</th>
|
||||
<th>
|
||||
Gas Price
|
||||
</th>
|
||||
<th>
|
||||
Gas
|
||||
</th>
|
||||
<th>
|
||||
First seen
|
||||
</th>
|
||||
<th>
|
||||
# Propagated
|
||||
</th>
|
||||
<th>
|
||||
</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { isLocal, stats, transaction, idx } = this.props;
|
||||
|
||||
const clazz = classnames(styles.transaction, {
|
||||
[styles.local]: isLocal
|
||||
});
|
||||
const noOfPeers = Object.keys(stats.propagatedTo).length;
|
||||
const noOfPropagations = Object.values(stats.propagatedTo).reduce((sum, val) => sum + val, 0);
|
||||
|
||||
return (
|
||||
<tr className={ clazz }>
|
||||
<td>
|
||||
{ idx }.
|
||||
</td>
|
||||
<td>
|
||||
{ this.renderHash(transaction.hash) }
|
||||
</td>
|
||||
<td>
|
||||
{ this.renderFrom(transaction) }
|
||||
</td>
|
||||
<td>
|
||||
{ this.renderGasPrice(transaction) }
|
||||
</td>
|
||||
<td>
|
||||
{ this.renderGas(transaction) }
|
||||
</td>
|
||||
<td>
|
||||
{ stats.firstSeen }
|
||||
</td>
|
||||
<td>
|
||||
{ this.renderPropagation(stats) }
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class LocalTransaction extends BaseTransaction {
|
||||
|
||||
static propTypes = {
|
||||
hash: PropTypes.string.isRequired,
|
||||
status: PropTypes.string.isRequired,
|
||||
transaction: PropTypes.object,
|
||||
isLocal: PropTypes.bool,
|
||||
stats: PropTypes.object,
|
||||
details: PropTypes.object
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
stats: {
|
||||
propagatedTo: {}
|
||||
}
|
||||
};
|
||||
|
||||
static renderHeader () {
|
||||
return (
|
||||
<tr className={ styles.header }>
|
||||
<th></th>
|
||||
<th>
|
||||
Transaction
|
||||
</th>
|
||||
<th>
|
||||
From
|
||||
</th>
|
||||
<th>
|
||||
Gas Price / Gas
|
||||
</th>
|
||||
<th>
|
||||
Propagated
|
||||
</th>
|
||||
<th>
|
||||
Status
|
||||
</th>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
state = {
|
||||
isSending: false,
|
||||
isResubmitting: false,
|
||||
gasPrice: null,
|
||||
gas: null
|
||||
};
|
||||
|
||||
toggleResubmit = () => {
|
||||
const { transaction } = this.props;
|
||||
const { isResubmitting, gasPrice } = this.state;
|
||||
|
||||
this.setState({
|
||||
isResubmitting: !isResubmitting,
|
||||
});
|
||||
|
||||
if (gasPrice === null) {
|
||||
this.setState({
|
||||
gasPrice: `0x${ transaction.gasPrice.toString(16) }`,
|
||||
gas: `0x${ transaction.gas.toString(16) }`
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
sendTransaction = () => {
|
||||
const { transaction } = this.props;
|
||||
const { gasPrice, gas } = this.state;
|
||||
|
||||
const newTransaction = {
|
||||
from: transaction.from,
|
||||
to: transaction.to,
|
||||
nonce: transaction.nonce,
|
||||
value: transaction.value,
|
||||
data: transaction.data,
|
||||
gasPrice, gas
|
||||
};
|
||||
|
||||
this.setState({
|
||||
isResubmitting: false,
|
||||
isSending: true
|
||||
});
|
||||
|
||||
const closeSending = () => this.setState({
|
||||
isSending: false
|
||||
});
|
||||
|
||||
api.eth.sendTransaction(newTransaction)
|
||||
.then(closeSending)
|
||||
.catch(closeSending);
|
||||
};
|
||||
|
||||
render () {
|
||||
if (this.state.isResubmitting) {
|
||||
return this.renderResubmit();
|
||||
}
|
||||
|
||||
const { stats, transaction, hash, status } = this.props;
|
||||
const { isSending } = this.state;
|
||||
|
||||
const resubmit = isSending ? (
|
||||
'sending...'
|
||||
) : (
|
||||
<a href='javascript:void' onClick={ this.toggleResubmit }>
|
||||
resubmit
|
||||
</a>
|
||||
);
|
||||
|
||||
return (
|
||||
<tr className={ styles.transaction }>
|
||||
<td>
|
||||
{ !transaction ? null : resubmit }
|
||||
</td>
|
||||
<td>
|
||||
{ this.renderHash(hash) }
|
||||
</td>
|
||||
<td>
|
||||
{ this.renderFrom(transaction) }
|
||||
</td>
|
||||
<td>
|
||||
{ this.renderGasPrice(transaction) }
|
||||
<br />
|
||||
{ this.renderGas(transaction) }
|
||||
</td>
|
||||
<td>
|
||||
{ status === 'pending' ? this.renderPropagation(stats) : '-' }
|
||||
</td>
|
||||
<td>
|
||||
{ this.renderStatus() }
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
renderStatus () {
|
||||
const { details } = this.props;
|
||||
|
||||
let state = {
|
||||
'pending': () => `In queue: Pending`,
|
||||
'future': () => `In queue: Future`,
|
||||
'mined': () => `Mined`,
|
||||
'dropped': () => `Dropped because of queue limit`,
|
||||
'invalid': () => `Transaction is invalid`,
|
||||
'rejected': () => `Rejected: ${ details.error }`,
|
||||
'replaced': () => `Replaced by ${ this.shortHash(details.hash) }`,
|
||||
}[this.props.status];
|
||||
|
||||
return state ? state() : 'unknown';
|
||||
}
|
||||
|
||||
renderResubmit () {
|
||||
const { transaction } = this.props;
|
||||
const { gasPrice, gas } = this.state;
|
||||
|
||||
return (
|
||||
<tr className={ styles.transaction }>
|
||||
<td>
|
||||
<a href='javascript:void' onClick={ this.toggleResubmit }>
|
||||
cancel
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{ this.renderHash(transaction.hash) }
|
||||
</td>
|
||||
<td>
|
||||
{ this.renderFrom(transaction) }
|
||||
</td>
|
||||
<td className={ styles.edit }>
|
||||
<input
|
||||
type='text'
|
||||
value={ gasPrice }
|
||||
onChange={ el => this.setState({ gasPrice: el.target.value }) }
|
||||
/>
|
||||
<input
|
||||
type='text'
|
||||
value={ gas }
|
||||
onChange={ el => this.setState({ gas: el.target.value }) }
|
||||
/>
|
||||
</td>
|
||||
<td colSpan='2'>
|
||||
<a href='javascript:void' onClick={ this.sendTransaction }>
|
||||
Send
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
37
js/src/dapps/localtx/Transaction/transaction.spec.js
Normal file
37
js/src/dapps/localtx/Transaction/transaction.spec.js
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import '../../../environment/tests';
|
||||
|
||||
import Transaction from './transaction';
|
||||
|
||||
describe('localtx/Transaction', () => {
|
||||
describe('rendering', () => {
|
||||
it('renders without crashing', () => {
|
||||
const rendered = shallow(
|
||||
<Transaction
|
||||
isLocal={ false }
|
||||
transaction={ {} }
|
||||
/>
|
||||
);
|
||||
|
||||
expect(rendered).to.be.defined;
|
||||
});
|
||||
});
|
||||
});
|
21
js/src/dapps/localtx/parity.js
Normal file
21
js/src/dapps/localtx/parity.js
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
const api = window.parent.secureApi;
|
||||
|
||||
export {
|
||||
api
|
||||
};
|
@ -224,15 +224,6 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
listGethAccounts: {
|
||||
desc: 'Returns a list of the accounts available from Geth',
|
||||
params: [],
|
||||
returns: {
|
||||
type: Array,
|
||||
desc: '20 Bytes addresses owned by the client.'
|
||||
}
|
||||
},
|
||||
|
||||
importGethAccounts: {
|
||||
desc: 'Imports a list of accounts from geth',
|
||||
params: [
|
||||
@ -247,6 +238,24 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
listGethAccounts: {
|
||||
desc: 'Returns a list of the accounts available from Geth',
|
||||
params: [],
|
||||
returns: {
|
||||
type: Array,
|
||||
desc: '20 Bytes addresses owned by the client.'
|
||||
}
|
||||
},
|
||||
|
||||
localTransactions: {
|
||||
desc: 'Returns an object of current and past local transactions.',
|
||||
params: [],
|
||||
returns: {
|
||||
type: Object,
|
||||
desc: 'Mapping of `tx hash` into status object.'
|
||||
}
|
||||
},
|
||||
|
||||
minGasPrice: {
|
||||
desc: 'Returns currently set minimal gas price',
|
||||
params: [],
|
||||
@ -379,6 +388,24 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
pendingTransactions: {
|
||||
desc: 'Returns a list of transactions currently in the queue.',
|
||||
params: [],
|
||||
returns: {
|
||||
type: Array,
|
||||
desc: 'Transactions ordered by priority'
|
||||
}
|
||||
},
|
||||
|
||||
pendingTransactionsStats: {
|
||||
desc: 'Returns propagation stats for transactions in the queue',
|
||||
params: [],
|
||||
returns: {
|
||||
type: Object,
|
||||
desc: 'mapping of `tx hash` into `stats`'
|
||||
}
|
||||
},
|
||||
|
||||
phraseToAddress: {
|
||||
desc: 'Converts a secret phrase into the corresponting address',
|
||||
params: [
|
||||
|
@ -39,5 +39,15 @@
|
||||
"author": "Parity Team <admin@ethcore.io>",
|
||||
"version": "1.0.0",
|
||||
"secure": true
|
||||
},
|
||||
{
|
||||
"id": "0xae74ad174b95cdbd01c88ac5b73a296d33e9088fc2a200e76bcedf3a94a7815d",
|
||||
"url": "localtx",
|
||||
"name": "TxQueue Viewer",
|
||||
"description": "Have a peak on internals of transaction queue of your node.",
|
||||
"author": "Parity Team <admin@ethcore.io>",
|
||||
"version": "1.0.0",
|
||||
"secure": true
|
||||
}
|
||||
|
||||
]
|
||||
|
@ -40,6 +40,7 @@ module.exports = {
|
||||
'githubhint': ['./dapps/githubhint.js'],
|
||||
'registry': ['./dapps/registry.js'],
|
||||
'signaturereg': ['./dapps/signaturereg.js'],
|
||||
'localtx': ['./dapps/localtx.js'],
|
||||
'tokenreg': ['./dapps/tokenreg.js'],
|
||||
// app
|
||||
'index': ['./index.js']
|
||||
|
Loading…
Reference in New Issue
Block a user