Display local/completed transactions (#3630)

* Initial fetch of local transactions

* Container allows for title specification

* Introduce TxList component

* Display local transactions in signer list

* Simplify

* Pass only hashes from calling components

* Simplify no pending display

* Render pending blocks at the top

* Get rid of time for 0 blocks

* Indeed sort Pending to the top

* Allow retrieval of pending transactions

* setTimeout with clearTimeout
This commit is contained in:
Jaco Greeff
2016-11-29 13:50:09 +01:00
committed by GitHub
parent a578e10c49
commit 5e8f6f271d
12 changed files with 499 additions and 361 deletions

View File

@@ -18,15 +18,17 @@ import BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { observer } from 'mobx-react';
import Store from '../../store';
import * as RequestsActions from '../../../../redux/providers/signerActions';
import { Container, ContainerTitle } from '../../../../ui';
import { Container, Page, TxList } from '../../../../ui';
import { RequestPending, RequestFinished } from '../../components';
import styles from './RequestsPage.css';
@observer
class RequestsPage extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
@@ -44,20 +46,19 @@ class RequestsPage extends Component {
isTest: PropTypes.bool.isRequired
};
store = new Store(this.context.api);
store = new Store(this.context.api, true);
componentWillUnmount () {
this.store.unsubscribe();
}
render () {
const { pending, finished } = this.props.signer;
if (!pending.length && !finished.length) {
return this.renderNoRequestsMsg();
}
return (
<div>
{ this.renderPendingRequests() }
{ this.renderFinishedRequests() }
</div>
<Page>
<div>{ this.renderPendingRequests() }</div>
<div>{ this.renderLocalQueue() }</div>
<div>{ this.renderFinishedRequests() }</div>
</Page>
);
}
@@ -65,18 +66,39 @@ class RequestsPage extends Component {
return new BigNumber(b.id).cmp(a.id);
}
renderLocalQueue () {
const { localHashes } = this.store;
if (!localHashes.length) {
return null;
}
return (
<Container title='Local Transactions'>
<TxList
address=''
hashes={ localHashes } />
</Container>
);
}
renderPendingRequests () {
const { pending } = this.props.signer;
if (!pending.length) {
return;
return (
<Container>
<div className={ styles.noRequestsMsg }>
There are no requests requiring your confirmation.
</div>
</Container>
);
}
const items = pending.sort(this._sortRequests).map(this.renderPending);
return (
<Container>
<ContainerTitle title='Pending Requests' />
<Container title='Pending Requests'>
<div className={ styles.items }>
{ items }
</div>
@@ -94,8 +116,7 @@ class RequestsPage extends Component {
const items = finished.sort(this._sortRequests).map(this.renderFinished);
return (
<Container>
<ContainerTitle title='Finished Requests' />
<Container title='Finished Requests'>
<div className={ styles.items }>
{ items }
</div>
@@ -143,16 +164,6 @@ class RequestsPage extends Component {
/>
);
}
renderNoRequestsMsg () {
return (
<Container>
<div className={ styles.noRequestsMsg }>
There are no requests requiring your confirmation.
</div>
</Container>
);
}
}
function mapStateToProps (state) {

View File

@@ -16,7 +16,7 @@
import React, { Component } from 'react';
import { Actionbar, Page } from '../../ui';
import { Actionbar } from '../../ui';
import RequestsPage from './containers/RequestsPage';
import styles from './signer.css';
@@ -27,9 +27,7 @@ export default class Signer extends Component {
<div className={ styles.signer }>
<Actionbar
title='Trusted Signer' />
<Page>
<RequestsPage />
</Page>
<RequestsPage />
</div>
);
}

View File

@@ -14,13 +14,26 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { isEqual } from 'lodash';
import { action, observable } from 'mobx';
export default class Store {
@observable balances = {};
@observable localHashes = [];
constructor (api) {
constructor (api, withLocalTransactions = false) {
this._api = api;
this._timeoutId = 0;
if (withLocalTransactions) {
this.fetchLocalTransactions();
}
}
@action unsubscribe () {
if (this._timeoutId) {
clearTimeout(this._timeoutId);
}
}
@action setBalance = (address, balance) => {
@@ -31,6 +44,12 @@ export default class Store {
this.balances = Object.assign({}, this.balances, balances);
}
@action setLocalHashes = (localHashes) => {
if (!isEqual(localHashes, this.localHashes)) {
this.localHashes = localHashes;
}
}
fetchBalance (address) {
this._api.eth
.getBalance(address)
@@ -63,4 +82,18 @@ export default class Store {
console.warn('Store:fetchBalances', error);
});
}
fetchLocalTransactions = () => {
const nextTimeout = () => {
this._timeoutId = setTimeout(this.fetchLocalTransactions, 1500);
};
this._api.parity
.localTransactions()
.then((localTransactions) => {
this.setLocalHashes(Object.keys(localTransactions));
})
.then(nextTimeout)
.catch(nextTimeout);
}
}