Display contract block creation (#4069)
* Add contract block creation to metadata * Display mined block for contract on Contracts view * Better use of Summary for Accounts * Add sorted by mined block for contracts * Proper Block Number sort // display in contract page * PR Grumble * Linting issues
This commit is contained in:
parent
71e6e24a1f
commit
cf0a20f08b
@ -75,6 +75,10 @@ export default class Contract {
|
||||
return this._functions;
|
||||
}
|
||||
|
||||
get receipt () {
|
||||
return this._receipt;
|
||||
}
|
||||
|
||||
get instance () {
|
||||
this._instance.address = this._address;
|
||||
return this._instance;
|
||||
@ -139,6 +143,7 @@ export default class Contract {
|
||||
}
|
||||
|
||||
setState({ state: 'hasReceipt', receipt });
|
||||
this._receipt = receipt;
|
||||
this._address = receipt.contractAddress;
|
||||
return this._address;
|
||||
});
|
||||
|
@ -455,10 +455,15 @@ class DeployContract extends Component {
|
||||
|
||||
this.setState({ step: 'DEPLOYMENT' });
|
||||
|
||||
api
|
||||
.newContract(abiParsed)
|
||||
const contract = api.newContract(abiParsed);
|
||||
|
||||
contract
|
||||
.deploy(options, params, this.onDeploymentState)
|
||||
.then((address) => {
|
||||
const blockNumber = contract._receipt
|
||||
? contract.receipt.blockNumber.toNumber()
|
||||
: null;
|
||||
|
||||
return Promise.all([
|
||||
api.parity.setAccountName(address, name),
|
||||
api.parity.setAccountMeta(address, {
|
||||
@ -466,8 +471,9 @@ class DeployContract extends Component {
|
||||
contract: true,
|
||||
timestamp: Date.now(),
|
||||
deleted: false,
|
||||
source,
|
||||
description
|
||||
blockNumber,
|
||||
description,
|
||||
source
|
||||
})
|
||||
])
|
||||
.then(() => {
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
.empty {
|
||||
line-height: 24px;
|
||||
margin: 0.75em 0.5em 0 0;
|
||||
margin: 0 0.5em 0 0;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
.byline {
|
||||
.byline, .description {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
line-height: 1.2em;
|
||||
@ -31,6 +31,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 0.75em;
|
||||
margin: 0.5em 0 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
|
@ -22,13 +22,14 @@ import styles from './title.css';
|
||||
|
||||
export default class Title extends Component {
|
||||
static propTypes = {
|
||||
byline: nodeOrStringProptype(),
|
||||
className: PropTypes.string,
|
||||
title: nodeOrStringProptype(),
|
||||
byline: nodeOrStringProptype()
|
||||
description: nodeOrStringProptype(),
|
||||
title: nodeOrStringProptype()
|
||||
}
|
||||
|
||||
render () {
|
||||
const { className, title, byline } = this.props;
|
||||
const { byline, className, title } = this.props;
|
||||
|
||||
const byLine = typeof byline === 'string'
|
||||
? (
|
||||
@ -46,6 +47,29 @@ export default class Title extends Component {
|
||||
<div className={ styles.byline }>
|
||||
{ byLine }
|
||||
</div>
|
||||
{ this.renderDescription() }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderDescription () {
|
||||
const { description } = this.props;
|
||||
|
||||
if (!description) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const desc = typeof description === 'string'
|
||||
? (
|
||||
<span title={ description }>
|
||||
{ description }
|
||||
</span>
|
||||
)
|
||||
: description;
|
||||
|
||||
return (
|
||||
<div className={ styles.description }>
|
||||
{ desc }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ class List extends Component {
|
||||
}
|
||||
|
||||
renderAccounts () {
|
||||
const { accounts, balances, empty, link, handleAddSearchToken } = this.props;
|
||||
const { accounts, balances, empty } = this.props;
|
||||
|
||||
if (empty) {
|
||||
return (
|
||||
@ -80,20 +80,29 @@ class List extends Component {
|
||||
return (
|
||||
<div
|
||||
className={ styles.item }
|
||||
key={ address }>
|
||||
<Summary
|
||||
link={ link }
|
||||
account={ account }
|
||||
balance={ balance }
|
||||
owners={ owners }
|
||||
handleAddSearchToken={ handleAddSearchToken }
|
||||
showCertifications
|
||||
/>
|
||||
key={ address }
|
||||
>
|
||||
{ this.renderSummary(account, balance, owners) }
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
renderSummary (account, balance, owners) {
|
||||
const { handleAddSearchToken, link } = this.props;
|
||||
|
||||
return (
|
||||
<Summary
|
||||
account={ account }
|
||||
balance={ balance }
|
||||
handleAddSearchToken={ handleAddSearchToken }
|
||||
link={ link }
|
||||
owners={ owners }
|
||||
showCertifications
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
getAddresses () {
|
||||
const filteredAddresses = this.getFilteredAddresses();
|
||||
return this.sortAddresses(filteredAddresses);
|
||||
@ -122,7 +131,15 @@ class List extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
compareAccounts (accountA, accountB, key) {
|
||||
compareAccounts (accountA, accountB, key, _reverse = null) {
|
||||
if (key && key.split(':')[1] === '-1') {
|
||||
return this.compareAccounts(accountA, accountB, key.split(':')[0], true);
|
||||
}
|
||||
|
||||
if (key === 'timestamp' && _reverse === null) {
|
||||
return this.compareAccounts(accountA, accountB, key, true);
|
||||
}
|
||||
|
||||
if (key === 'name') {
|
||||
return accountA.name.localeCompare(accountB.name);
|
||||
}
|
||||
@ -177,7 +194,9 @@ class List extends Component {
|
||||
return tagsA.localeCompare(tagsB);
|
||||
}
|
||||
|
||||
const reverse = key === 'timestamp' ? -1 : 1;
|
||||
const reverse = _reverse
|
||||
? -1
|
||||
: 1;
|
||||
|
||||
const metaA = accountA.meta[key];
|
||||
const metaB = accountB.meta[key];
|
||||
|
@ -19,6 +19,7 @@ import React, { Component, PropTypes } from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { isEqual } from 'lodash';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Balance, Container, ContainerTitle, IdentityIcon, IdentityName, Tags, Input } from '~/ui';
|
||||
import Certifications from '~/ui/Certifications';
|
||||
@ -107,14 +108,22 @@ export default class Summary extends Component {
|
||||
/>
|
||||
);
|
||||
|
||||
const description = this.getDescription(account.meta);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Tags tags={ tags } handleAddSearchToken={ handleAddSearchToken } />
|
||||
<IdentityIcon
|
||||
address={ address } />
|
||||
<ContainerTitle
|
||||
title={ this.renderLink() }
|
||||
byline={ addressComponent } />
|
||||
<div className={ styles.heading }>
|
||||
<IdentityIcon
|
||||
address={ address }
|
||||
/>
|
||||
<ContainerTitle
|
||||
byline={ addressComponent }
|
||||
className={ styles.main }
|
||||
description={ description }
|
||||
title={ this.renderLink() }
|
||||
/>
|
||||
</div>
|
||||
|
||||
{ this.renderOwners() }
|
||||
{ this.renderBalance() }
|
||||
@ -123,6 +132,26 @@ export default class Summary extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
getDescription (meta = {}) {
|
||||
const { blockNumber } = meta;
|
||||
|
||||
if (!blockNumber) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const formattedBlockNumber = (new BigNumber(blockNumber)).toFormat();
|
||||
|
||||
return (
|
||||
<FormattedMessage
|
||||
id='accounts.summary.minedBlock'
|
||||
defaultMessage='Mined at block #{blockNumber}'
|
||||
values={ {
|
||||
blockNumber: formattedBlockNumber
|
||||
} }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderOwners () {
|
||||
const { owners } = this.props;
|
||||
const ownersValid = (owners || []).filter((owner) => owner.address && new BigNumber(owner.address).gt(0));
|
||||
|
@ -56,3 +56,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.blockNumber {
|
||||
color: rgba(255, 255, 255, 0.25);
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
.origin {
|
||||
text-align: left;
|
||||
padding-left: 32px;
|
||||
|
@ -17,6 +17,9 @@
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
import ActionDelete from 'material-ui/svg-icons/action/delete';
|
||||
import AvPlayArrow from 'material-ui/svg-icons/av/play-arrow';
|
||||
import ContentCreate from 'material-ui/svg-icons/content/create';
|
||||
@ -136,7 +139,9 @@ class Contract extends Component {
|
||||
account={ account }
|
||||
balance={ balance }
|
||||
isContract
|
||||
/>
|
||||
>
|
||||
{ this.renderBlockNumber(account.meta) }
|
||||
</Header>
|
||||
|
||||
<Queries
|
||||
accountsInfo={ accountsInfo }
|
||||
@ -156,6 +161,28 @@ class Contract extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
renderBlockNumber (meta = {}) {
|
||||
const { blockNumber } = meta;
|
||||
|
||||
if (!blockNumber) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const formattedBlockNumber = (new BigNumber(blockNumber)).toFormat();
|
||||
|
||||
return (
|
||||
<div className={ styles.blockNumber }>
|
||||
<FormattedMessage
|
||||
id='contract.minedBlock'
|
||||
defaultMessage='Mined at block #{blockNumber}'
|
||||
values={ {
|
||||
blockNumber: formattedBlockNumber
|
||||
} }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderDetails (contract) {
|
||||
const { showDetailsDialog } = this.state;
|
||||
|
||||
|
@ -1,17 +0,0 @@
|
||||
// Copyright 2015, 2016 Parity Technologies (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 './summary';
|
@ -1,52 +0,0 @@
|
||||
// Copyright 2015, 2016 Parity Technologies (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 { Link } from 'react-router';
|
||||
|
||||
import { Container, ContainerTitle, IdentityIcon, IdentityName } from '~/ui';
|
||||
|
||||
export default class Summary extends Component {
|
||||
static contextTypes = {
|
||||
api: React.PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
contract: PropTypes.object.isRequired,
|
||||
children: PropTypes.node
|
||||
}
|
||||
|
||||
render () {
|
||||
const contract = this.props.contract;
|
||||
|
||||
if (!contract) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const viewLink = `/app/${contract.address}`;
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<IdentityIcon
|
||||
address={ contract.address } />
|
||||
<ContainerTitle
|
||||
title={ <Link to={ viewLink }>{ <IdentityName address={ contract.address } unknown /> }</Link> }
|
||||
byline={ contract.address } />
|
||||
{ this.props.children }
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ class Contracts extends Component {
|
||||
state = {
|
||||
addContract: false,
|
||||
deployContract: false,
|
||||
sortOrder: 'timestamp',
|
||||
sortOrder: 'blockNumber',
|
||||
searchValues: [],
|
||||
searchTokens: []
|
||||
}
|
||||
@ -92,7 +92,8 @@ class Contracts extends Component {
|
||||
empty={ !hasContracts }
|
||||
order={ sortOrder }
|
||||
orderFallback='name'
|
||||
handleAddSearchToken={ this.onAddSearchToken } />
|
||||
handleAddSearchToken={ this.onAddSearchToken }
|
||||
/>
|
||||
</Page>
|
||||
</div>
|
||||
);
|
||||
@ -109,7 +110,8 @@ class Contracts extends Component {
|
||||
id='sortContracts'
|
||||
order={ this.state.sortOrder }
|
||||
metas={ [
|
||||
{ key: 'timestamp', label: 'date' }
|
||||
{ key: 'timestamp', label: 'date' },
|
||||
{ key: 'blockNumber:-1', label: 'mined block' }
|
||||
] }
|
||||
showDefault={ false }
|
||||
onChange={ onChange } />
|
||||
|
Loading…
Reference in New Issue
Block a user