simplify tx confirmations display (#3559)

* Hash component

* DRY code by using Hash component

* TxHash component: show hash inline

* TxHash component: less verbose confirmations display

* TxHash component: rename ui/Hash to ui/ShortenedHash

* signer: center message in TransactionFinished

* style fixes
This commit is contained in:
Jannis Redmann 2016-11-28 17:39:32 +01:00 committed by Jaco Greeff
parent eec99ebad8
commit 2b178d8233
9 changed files with 126 additions and 56 deletions

View File

@ -18,6 +18,8 @@ import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import ShortenedHash from '../ShortenedHash';
const defaultName = 'UNNAMED'; const defaultName = 'UNNAMED';
class IdentityName extends Component { class IdentityName extends Component {
@ -41,7 +43,7 @@ class IdentityName extends Component {
return null; return null;
} }
const addressFallback = shorten ? this.formatHash(address) : address; const addressFallback = shorten ? (<ShortenedHash data={ address } />) : address;
const fallback = unknown ? defaultName : addressFallback; const fallback = unknown ? defaultName : addressFallback;
const isUuid = hasAccount && account.name === account.uuid; const isUuid = hasAccount && account.name === account.uuid;
const displayName = (name && name.toUpperCase().trim()) || const displayName = (name && name.toUpperCase().trim()) ||
@ -55,14 +57,6 @@ class IdentityName extends Component {
</span> </span>
); );
} }
formatHash (hash) {
if (!hash || hash.length <= 16) {
return hash;
}
return `${hash.substr(2, 6)}...${hash.slice(-6)}`;
}
} }
function mapStateToProps (state) { function mapStateToProps (state) {

View 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 './shortenedHash';

View 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/>.
*/
.hash {
display: inline-block;
word-break: break-all;
}

View File

@ -0,0 +1,41 @@
// 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 styles from './shortenedHash.css';
export default class ShortenedHash extends Component {
static propTypes = {
data: PropTypes.string.isRequired
}
render () {
const { data } = this.props;
let shortened = data.toLowerCase();
if (shortened.slice(0, 2) === '0x') {
shortened = shortened.slice(2);
}
if (shortened.length > (6 + 6)) {
shortened = shortened.slice(0, 6) + '…' + shortened.slice(-6);
}
return (
<abbr className={ styles.hash } title={ shortened }>{ shortened }</abbr>
);
}
}

View File

@ -15,19 +15,12 @@
/* along with Parity. If not, see <http://www.gnu.org/licenses/>. /* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/ */
.details {
}
.header {
}
.hash { .hash {
padding-top: 1em; padding-top: 1em;
word-break: break-all; word-break: break-all;
} }
.confirm { .confirm {
padding-top: 1em;
opacity: 0.5; opacity: 0.5;
} }

View File

@ -19,7 +19,9 @@ import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { LinearProgress } from 'material-ui'; import { LinearProgress } from 'material-ui';
import { txLink } from '../../3rdparty/etherscan/links'; import { txLink } from '../../3rdparty/etherscan/links';
import ShortenedHash from '../ShortenedHash';
import styles from './txHash.css'; import styles from './txHash.css';
@ -62,22 +64,23 @@ class TxHash extends Component {
render () { render () {
const { hash, isTest, summary } = this.props; const { hash, isTest, summary } = this.props;
let header = null;
if (!summary) { const link = (
header = ( <a href={ txLink(hash, isTest) } target='_blank'>
<div className={ styles.header }> <ShortenedHash data={ hash } />
The transaction has been posted to the network with a transaction hash of </a>
</div> );
);
let header = (
<p>The transaction has been posted to the network, with a hash of { link }.</p>
);
if (summary) {
header = (<p>{ link }</p>);
} }
return ( return (
<div className={ styles.details }> <div>
{ header } { header }
<div className={ styles.hash }>
<a href={ txLink(hash, isTest) } target='_blank'>{ hash }</a>
</div>
{ this.renderConfirmations() } { this.renderConfirmations() }
</div> </div>
); );
@ -87,17 +90,29 @@ class TxHash extends Component {
const { maxConfirmations } = this.props; const { maxConfirmations } = this.props;
const { blockNumber, transaction } = this.state; const { blockNumber, transaction } = this.state;
let txBlock = 'Pending'; if (!(transaction && transaction.blockNumber && transaction.blockNumber.gt(0))) {
let confirmations = 'No'; return (
let value = 0; <div className={ styles.confirm }>
<LinearProgress
if (transaction && transaction.blockNumber && transaction.blockNumber.gt(0)) { className={ styles.progressbar }
const num = blockNumber.minus(transaction.blockNumber).plus(1); color='white'
txBlock = `#${transaction.blockNumber.toFormat(0)}`; mode='indeterminate'
confirmations = num.toFormat(0); />
value = num.gt(maxConfirmations) ? maxConfirmations : num.toNumber(); <div className={ styles.progressinfo }>waiting for confirmations</div>
</div>
);
} }
const confirmations = blockNumber.minus(transaction.blockNumber).plus(1);
const value = Math.min(confirmations.toNumber(), maxConfirmations);
let count;
if (confirmations.gt(maxConfirmations)) {
count = confirmations.toFormat(0);
} else {
count = confirmations.toFormat(0) + `/${maxConfirmations}`;
}
const unit = value === 1 ? 'confirmation' : 'confirmations';
return ( return (
<div className={ styles.confirm }> <div className={ styles.confirm }>
<LinearProgress <LinearProgress
@ -106,9 +121,10 @@ class TxHash extends Component {
max={ maxConfirmations } max={ maxConfirmations }
value={ value } value={ value }
color='white' color='white'
mode='determinate' /> mode='determinate'
/>
<div className={ styles.progressinfo }> <div className={ styles.progressinfo }>
{ txBlock } / { confirmations } confirmations <abbr title={ `block #${blockNumber.toFormat(0)}` }>{ count } { unit }</abbr>
</div> </div>
</div> </div>
); );

View File

@ -37,6 +37,7 @@ import Modal, { Busy as BusyStep, Completed as CompletedStep } from './Modal';
import muiTheme from './Theme'; import muiTheme from './Theme';
import Page from './Page'; import Page from './Page';
import ParityBackground from './ParityBackground'; import ParityBackground from './ParityBackground';
import ShortenedHash from './ShortenedHash';
import SignerIcon from './SignerIcon'; import SignerIcon from './SignerIcon';
import Tags from './Tags'; import Tags from './Tags';
import Tooltips, { Tooltip } from './Tooltips'; import Tooltips, { Tooltip } from './Tooltips';
@ -79,6 +80,7 @@ export {
Page, Page,
ParityBackground, ParityBackground,
RadioButtons, RadioButtons,
ShortenedHash,
SignerIcon, SignerIcon,
Tags, Tags,
Tooltip, Tooltip,

View File

@ -19,6 +19,7 @@ import React, { Component, PropTypes } from 'react';
import moment from 'moment'; import moment from 'moment';
import { IdentityIcon, IdentityName, MethodDecoding } from '../../../../ui'; import { IdentityIcon, IdentityName, MethodDecoding } from '../../../../ui';
import ShortenedHash from '../../../../ui/ShortenedHash';
import { txLink, addressLink } from '../../../../3rdparty/etherscan/links'; import { txLink, addressLink } from '../../../../3rdparty/etherscan/links';
import styles from '../transactions.css'; import styles from '../transactions.css';
@ -95,7 +96,7 @@ export default class Transaction extends Component {
href={ txLink(transaction.hash, isTest) } href={ txLink(transaction.hash, isTest) }
target='_blank' target='_blank'
> >
{ this.formatHash(transaction.hash) } <ShortenedHash data={ transaction.hash } />
</a> </a>
</div> </div>
</td> </td>
@ -150,14 +151,6 @@ export default class Transaction extends Component {
); );
} }
formatHash (hash) {
if (!hash || hash.length <= 16) {
return hash;
}
return `${hash.substr(2, 6)}...${hash.slice(-6)}`;
}
formatNumber (number) { formatNumber (number) {
return new BigNumber(number).toFormat(); return new BigNumber(number).toFormat();
} }

View File

@ -19,6 +19,7 @@ import moment from 'moment';
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { IdentityIcon, IdentityName, Input, InputAddress } from '../../../../ui'; import { IdentityIcon, IdentityName, Input, InputAddress } from '../../../../ui';
import ShortenedHash from '../../../../ui/ShortenedHash';
import { txLink } from '../../../../3rdparty/etherscan/links'; import { txLink } from '../../../../3rdparty/etherscan/links';
import styles from '../../contract.css'; import styles from '../../contract.css';
@ -71,7 +72,7 @@ export default class Event extends Component {
<div className={ styles.eventType }> <div className={ styles.eventType }>
{ event.type }({ keys }) { event.type }({ keys })
</div> </div>
<a href={ url } target='_blank'>{ this.formatHash(event.transactionHash) }</a> <a href={ url } target='_blank'><ShortenedHash data={ event.transactionHash } /></a>
</td> </td>
<td className={ styles.eventDetails }> <td className={ styles.eventDetails }>
<div className={ styles.eventParams }> <div className={ styles.eventParams }>
@ -82,14 +83,6 @@ export default class Event extends Component {
); );
} }
formatHash (hash) {
if (!hash || hash.length <= 16) {
return hash;
}
return `${hash.substr(2, 6)}...${hash.slice(-6)}`;
}
renderAddressName (address, withName = true) { renderAddressName (address, withName = true) {
return ( return (
<span className={ styles.eventAddress }> <span className={ styles.eventAddress }>