merge master into sms-verification-modal
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "parity.js",
|
||||
"version": "0.2.46",
|
||||
"version": "0.2.48",
|
||||
"main": "release/index.js",
|
||||
"jsnext:main": "src/index.js",
|
||||
"author": "Parity Team <admin@parity.io>",
|
||||
|
||||
@@ -46,11 +46,22 @@ a.link, a.link:hover, a.link:visited {
|
||||
}
|
||||
|
||||
.address {
|
||||
max-width: 250px;
|
||||
text-align: left;
|
||||
|
||||
div {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
text-align: left;
|
||||
|
||||
div {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.center {
|
||||
|
||||
@@ -58,6 +58,7 @@ export default class Event extends Component {
|
||||
<td className={ styles.description }>
|
||||
<div>{ isPending ? '' : coin.tla }</div>
|
||||
<div>{ isPending ? '' : coin.name }</div>
|
||||
<div>{ this.renderAddress(event.params.coin) }</div>
|
||||
</td>
|
||||
<td className={ styles.address }>
|
||||
{ this.renderAddress(event.params.owner) }
|
||||
|
||||
@@ -46,3 +46,9 @@
|
||||
.icon {
|
||||
margin: 0 0 -4px 1em;
|
||||
}
|
||||
|
||||
.byline {
|
||||
opacity: 0.75;
|
||||
font-size: 0.75em;
|
||||
padding-top: 0.25em;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,9 @@ export default class Owner extends Component {
|
||||
<Token
|
||||
address={ token.address }
|
||||
tokenreg={ token.tokenreg } />
|
||||
<div className={ styles.byline }>
|
||||
{ token.address }
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
}
|
||||
|
||||
@@ -227,6 +227,7 @@ export default class AddContract extends Component {
|
||||
onEditAbi = (abiIn) => {
|
||||
const { api } = this.context;
|
||||
const { abi, abiError, abiParsed } = validateAbi(abiIn, api);
|
||||
|
||||
this.setState({ abi, abiError, abiParsed });
|
||||
}
|
||||
|
||||
|
||||
@@ -314,7 +314,7 @@ export default class Transfer extends Component {
|
||||
}
|
||||
|
||||
const token = balance.tokens.find((balance) => balance.token.tag === tag).token;
|
||||
const s = new BigNumber(num).mul(token.format || 1).toString();
|
||||
const s = new BigNumber(num).mul(token.format || 1).toFixed();
|
||||
|
||||
if (s.indexOf('.') !== -1) {
|
||||
return ERRORS.invalidDecimals;
|
||||
@@ -516,6 +516,13 @@ export default class Transfer extends Component {
|
||||
}
|
||||
|
||||
recalculateGas = () => {
|
||||
if (!this.isValid()) {
|
||||
this.setState({
|
||||
gas: '0'
|
||||
}, this.recalculate);
|
||||
return;
|
||||
}
|
||||
|
||||
(this.state.isEth
|
||||
? this._estimateGasEth()
|
||||
: this._estimateGasToken()
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
|
||||
import FileSaver from 'file-saver';
|
||||
import FileDownloadIcon from 'material-ui/svg-icons/file/file-download';
|
||||
|
||||
@@ -38,19 +39,18 @@ class ActionbarExport extends Component {
|
||||
className={ className }
|
||||
icon={ <FileDownloadIcon /> }
|
||||
label='export'
|
||||
onClick={ this.onDownloadBackup } />
|
||||
onClick={ this.handleExport }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
onDownloadBackup = () => {
|
||||
handleExport = () => {
|
||||
const { filename, content } = this.props;
|
||||
|
||||
const text = (typeof content === 'string')
|
||||
? content
|
||||
: JSON.stringify(content, null, 4);
|
||||
const text = JSON.stringify(content, null, 4);
|
||||
|
||||
const blob = new Blob([ text ], { type: 'text/plain;charset=utf-8' });
|
||||
FileSaver.saveAs(blob, filename);
|
||||
const blob = new Blob([ text ], { type: 'application/json' });
|
||||
FileSaver.saveAs(blob, `${filename}.json`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import IconMenu from 'material-ui/IconMenu';
|
||||
import MenuItem from 'material-ui/MenuItem';
|
||||
|
||||
@@ -22,11 +24,15 @@ import SortIcon from 'material-ui/svg-icons/content/sort';
|
||||
|
||||
import { Button } from '../../';
|
||||
|
||||
import SortStore from './sortStore';
|
||||
import styles from './sort.css';
|
||||
|
||||
@observer
|
||||
export default class ActionbarSort extends Component {
|
||||
static propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
|
||||
order: PropTypes.string,
|
||||
showDefault: PropTypes.bool,
|
||||
metas: PropTypes.array
|
||||
@@ -37,8 +43,10 @@ export default class ActionbarSort extends Component {
|
||||
showDefault: true
|
||||
}
|
||||
|
||||
state = {
|
||||
menuOpen: false
|
||||
store = new SortStore(this.props);
|
||||
|
||||
componentDidMount () {
|
||||
this.store.restoreSavedOrder();
|
||||
}
|
||||
|
||||
render () {
|
||||
@@ -51,12 +59,12 @@ export default class ActionbarSort extends Component {
|
||||
className={ styles.sortButton }
|
||||
label=''
|
||||
icon={ <SortIcon /> }
|
||||
onClick={ this.handleMenuOpen }
|
||||
onClick={ this.store.handleMenuOpen }
|
||||
/>
|
||||
}
|
||||
open={ this.state.menuOpen }
|
||||
onRequestChange={ this.handleMenuChange }
|
||||
onItemTouchTap={ this.handleSortChange }
|
||||
open={ this.store.menuOpen }
|
||||
onRequestChange={ this.store.handleMenuChange }
|
||||
onItemTouchTap={ this.store.handleSortChange }
|
||||
targetOrigin={ { horizontal: 'right', vertical: 'top' } }
|
||||
anchorOrigin={ { horizontal: 'right', vertical: 'top' } }
|
||||
touchTapCloseDelay={ 0 }
|
||||
@@ -109,16 +117,4 @@ export default class ActionbarSort extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
handleSortChange = (event, child) => {
|
||||
const order = child.props.value;
|
||||
this.props.onChange(order);
|
||||
}
|
||||
|
||||
handleMenuOpen = () => {
|
||||
this.setState({ menuOpen: true });
|
||||
}
|
||||
|
||||
handleMenuChange = (open) => {
|
||||
this.setState({ menuOpen: open });
|
||||
}
|
||||
}
|
||||
|
||||
71
js/src/ui/Actionbar/Sort/sortStore.js
Normal file
71
js/src/ui/Actionbar/Sort/sortStore.js
Normal file
@@ -0,0 +1,71 @@
|
||||
// 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 { action, observable } from 'mobx';
|
||||
import store from 'store';
|
||||
|
||||
const LS_STORE_KEY = '_parity::sortStore';
|
||||
|
||||
export default class SortStore {
|
||||
@observable menuOpen = false;
|
||||
|
||||
constructor (props) {
|
||||
const { id, onChange } = props;
|
||||
|
||||
this.onChange = onChange;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@action handleMenuOpen = () => {
|
||||
this.menuOpen = true;
|
||||
}
|
||||
|
||||
@action handleMenuChange = (open) => {
|
||||
this.menuOpen = open;
|
||||
}
|
||||
|
||||
@action handleSortChange = (event, child) => {
|
||||
const order = child.props.value;
|
||||
this.onChange(order);
|
||||
this.saveOrder(order);
|
||||
}
|
||||
|
||||
@action restoreSavedOrder = () => {
|
||||
const order = this.getSavedOrder();
|
||||
this.onChange(order);
|
||||
}
|
||||
|
||||
getSavedOrder = () => {
|
||||
return (this.getSavedOrders())[this.id];
|
||||
}
|
||||
|
||||
getSavedOrders = () => {
|
||||
return store.get(LS_STORE_KEY) || {};
|
||||
}
|
||||
|
||||
setSavedOrders = (orders) => {
|
||||
store.set(LS_STORE_KEY, orders);
|
||||
}
|
||||
|
||||
saveOrder = (order) => {
|
||||
const orders = {
|
||||
...this.getSavedOrders(),
|
||||
[ this.id ]: order
|
||||
};
|
||||
|
||||
this.setSavedOrders(orders);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { TextField } from 'material-ui';
|
||||
import { noop } from 'lodash';
|
||||
|
||||
import CopyToClipboard from '../../CopyToClipboard';
|
||||
|
||||
@@ -81,7 +82,7 @@ export default class Input extends Component {
|
||||
}
|
||||
|
||||
componentWillReceiveProps (newProps) {
|
||||
if (newProps.value !== this.props.value) {
|
||||
if ((newProps.value !== this.props.value) && (newProps.value !== this.state.value)) {
|
||||
this.setValue(newProps.value);
|
||||
}
|
||||
}
|
||||
@@ -131,6 +132,7 @@ export default class Input extends Component {
|
||||
onBlur={ this.onBlur }
|
||||
onChange={ this.onChange }
|
||||
onKeyDown={ this.onKeyDown }
|
||||
onPaste={ this.onPaste }
|
||||
inputStyle={ inputStyle }
|
||||
min={ min }
|
||||
max={ max }
|
||||
@@ -180,9 +182,9 @@ export default class Input extends Component {
|
||||
}
|
||||
|
||||
onChange = (event, value) => {
|
||||
this.setValue(value);
|
||||
|
||||
this.props.onChange && this.props.onChange(event, value);
|
||||
this.setValue(value, () => {
|
||||
this.props.onChange && this.props.onChange(event, value);
|
||||
});
|
||||
}
|
||||
|
||||
onBlur = (event) => {
|
||||
@@ -196,6 +198,14 @@ export default class Input extends Component {
|
||||
this.props.onBlur && this.props.onBlur(event);
|
||||
}
|
||||
|
||||
onPaste = (event) => {
|
||||
const value = event.clipboardData.getData('Text');
|
||||
|
||||
window.setTimeout(() => {
|
||||
this.onSubmit(value);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
onKeyDown = (event) => {
|
||||
const { value } = event.target;
|
||||
|
||||
@@ -209,12 +219,12 @@ export default class Input extends Component {
|
||||
}
|
||||
|
||||
onSubmit = (value) => {
|
||||
this.setValue(value);
|
||||
|
||||
this.props.onSubmit && this.props.onSubmit(value);
|
||||
this.setValue(value, () => {
|
||||
this.props.onSubmit && this.props.onSubmit(value);
|
||||
});
|
||||
}
|
||||
|
||||
setValue (value) {
|
||||
this.setState({ value });
|
||||
setValue (value, cb = noop) {
|
||||
this.setState({ value }, cb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
.iconDisabled {
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
|
||||
&.noLabel {
|
||||
top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
|
||||
@@ -69,14 +69,19 @@ class InputAddress extends Component {
|
||||
}
|
||||
|
||||
renderIcon () {
|
||||
const { value, disabled } = this.props;
|
||||
const { value, disabled, label } = this.props;
|
||||
|
||||
if (!value || !value.length || !util.isAddressValid(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const classes = [disabled ? styles.iconDisabled : styles.icon];
|
||||
if (!label) {
|
||||
classes.push(styles.noLabel);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ disabled ? styles.iconDisabled : styles.icon }>
|
||||
<div className={ classes.join(' ') }>
|
||||
<IdentityIcon
|
||||
inline center
|
||||
address={ value } />
|
||||
|
||||
@@ -44,7 +44,7 @@ export function validateAbi (abi, api) {
|
||||
|
||||
// Validate each elements of the Array
|
||||
const invalidIndex = abiParsed
|
||||
.map((o) => isValidAbiEvent(o, api) || isValidAbiFunction(o, api))
|
||||
.map((o) => isValidAbiEvent(o, api) || isValidAbiFunction(o, api) || isAbiFallback(o))
|
||||
.findIndex((valid) => !valid);
|
||||
|
||||
if (invalidIndex !== -1) {
|
||||
@@ -74,6 +74,14 @@ function isValidAbiFunction (object, api) {
|
||||
(object.inputs && api.util.isArray(object.inputs));
|
||||
}
|
||||
|
||||
function isAbiFallback (object) {
|
||||
if (!object) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return object.type === 'fallback';
|
||||
}
|
||||
|
||||
function isValidAbiEvent (object, api) {
|
||||
if (!object) {
|
||||
return false;
|
||||
|
||||
@@ -22,7 +22,7 @@ import { uniq } from 'lodash';
|
||||
|
||||
import List from './List';
|
||||
import { CreateAccount } from '../../modals';
|
||||
import { Actionbar, ActionbarSearch, ActionbarSort, Button, Page, Tooltip } from '../../ui';
|
||||
import { Actionbar, ActionbarExport, ActionbarSearch, ActionbarSort, Button, Page, Tooltip } from '../../ui';
|
||||
|
||||
import styles from './accounts.css';
|
||||
|
||||
@@ -90,12 +90,15 @@ class Accounts extends Component {
|
||||
return (
|
||||
<ActionbarSort
|
||||
key='sortAccounts'
|
||||
id='sortAccounts'
|
||||
order={ this.state.sortOrder }
|
||||
onChange={ onChange } />
|
||||
);
|
||||
}
|
||||
|
||||
renderActionbar () {
|
||||
const { accounts } = this.props;
|
||||
|
||||
const buttons = [
|
||||
<Button
|
||||
key='newAccount'
|
||||
@@ -103,6 +106,11 @@ class Accounts extends Component {
|
||||
label='new account'
|
||||
onClick={ this.onNewAccountClick } />,
|
||||
|
||||
<ActionbarExport
|
||||
key='exportAccounts'
|
||||
content={ accounts }
|
||||
filename='accounts' />,
|
||||
|
||||
this.renderSearchButton(),
|
||||
this.renderSortButton()
|
||||
];
|
||||
|
||||
@@ -75,6 +75,7 @@ class Addresses extends Component {
|
||||
return (
|
||||
<ActionbarSort
|
||||
key='sortAccounts'
|
||||
id='sortAddresses'
|
||||
order={ this.state.sortOrder }
|
||||
onChange={ onChange } />
|
||||
);
|
||||
@@ -106,7 +107,7 @@ class Addresses extends Component {
|
||||
<ActionbarExport
|
||||
key='exportAddressbook'
|
||||
content={ contacts }
|
||||
filename='addressbook.json' />,
|
||||
filename='addressbook' />,
|
||||
|
||||
<ActionbarImport
|
||||
key='importAddressbook'
|
||||
|
||||
@@ -19,7 +19,7 @@ import React, { Component, PropTypes } from 'react';
|
||||
import LinearProgress from 'material-ui/LinearProgress';
|
||||
import { Card, CardActions, CardTitle, CardText } from 'material-ui/Card';
|
||||
|
||||
import { Button, Input, InputAddressSelect } from '../../../ui';
|
||||
import { Button, Input, InputAddress, InputAddressSelect } from '../../../ui';
|
||||
|
||||
import styles from './queries.css';
|
||||
|
||||
@@ -96,32 +96,48 @@ export default class InputQuery extends Component {
|
||||
}
|
||||
|
||||
if (!results || results.length < 1) return null;
|
||||
|
||||
return outputs
|
||||
.map((out, index) => ({
|
||||
name: out.name,
|
||||
type: out.type,
|
||||
value: results[index],
|
||||
display: this.renderValue(results[index])
|
||||
}))
|
||||
.sort((outA, outB) => outA.display.length - outB.display.length)
|
||||
.map((out, index) => (
|
||||
<div key={ index }>
|
||||
<div className={ styles.queryResultName }>
|
||||
{ out.name }
|
||||
</div>
|
||||
.map((out, index) => {
|
||||
let input = null;
|
||||
if (out.type === 'address') {
|
||||
input = (
|
||||
<InputAddress
|
||||
className={ styles.queryValue }
|
||||
disabled
|
||||
value={ out.display }
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
input = (
|
||||
<Input
|
||||
className={ styles.queryValue }
|
||||
readOnly
|
||||
allowCopy
|
||||
value={ out.display }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
<Input
|
||||
className={ styles.queryValue }
|
||||
readOnly
|
||||
allowCopy
|
||||
value={ out.display }
|
||||
/>
|
||||
<br />
|
||||
</div>
|
||||
));
|
||||
return (
|
||||
<div key={ index }>
|
||||
<div className={ styles.queryResultName }>
|
||||
{ out.name }
|
||||
</div>
|
||||
{ input }
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
renderInput (input) {
|
||||
const { values } = this.state;
|
||||
const { name, type } = input;
|
||||
const label = `${name ? `${name}: ` : ''}${type}`;
|
||||
|
||||
@@ -143,6 +159,7 @@ export default class InputQuery extends Component {
|
||||
<InputAddressSelect
|
||||
hint={ type }
|
||||
label={ label }
|
||||
value={ values[name] }
|
||||
required
|
||||
onChange={ onChange }
|
||||
/>
|
||||
@@ -155,6 +172,7 @@ export default class InputQuery extends Component {
|
||||
<Input
|
||||
hint={ type }
|
||||
label={ label }
|
||||
value={ values[name] }
|
||||
required
|
||||
onChange={ onChange }
|
||||
/>
|
||||
|
||||
@@ -56,18 +56,10 @@
|
||||
}
|
||||
|
||||
.methodResults {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
max-width: 24rem;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.methodResults > div {
|
||||
padding: 0.25rem 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1 1 50%;
|
||||
box-sizing: border-box;
|
||||
|
||||
& > div {
|
||||
|
||||
@@ -19,7 +19,7 @@ import React, { Component, PropTypes } from 'react';
|
||||
import { Card, CardTitle, CardText } from 'material-ui/Card';
|
||||
|
||||
import InputQuery from './inputQuery';
|
||||
import { Container, ContainerTitle, Input } from '../../../ui';
|
||||
import { Container, ContainerTitle, Input, InputAddress } from '../../../ui';
|
||||
|
||||
import styles from './queries.css';
|
||||
|
||||
@@ -100,14 +100,14 @@ export default class Queries extends Component {
|
||||
<CardText
|
||||
className={ styles.methodContent }
|
||||
>
|
||||
{ this.renderValue(values[fn.name]) }
|
||||
{ this.renderValue(values[fn.name], fn.outputs[0].kind.type) }
|
||||
</CardText>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderValue (value) {
|
||||
renderValue (value, type) {
|
||||
if (typeof value === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
@@ -125,6 +125,16 @@ export default class Queries extends Component {
|
||||
valueToDisplay = value.toString();
|
||||
}
|
||||
|
||||
if (type === 'address') {
|
||||
return (
|
||||
<InputAddress
|
||||
className={ styles.queryValue }
|
||||
value={ valueToDisplay }
|
||||
disabled
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Input
|
||||
className={ styles.queryValue }
|
||||
|
||||
@@ -82,6 +82,7 @@ class Contracts extends Component {
|
||||
return (
|
||||
<ActionbarSort
|
||||
key='sortAccounts'
|
||||
id='sortContracts'
|
||||
order={ this.state.sortOrder }
|
||||
metas={ [
|
||||
{ key: 'timestamp', label: 'date' }
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
.acc {
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.acc > * {
|
||||
@@ -35,10 +38,13 @@
|
||||
}
|
||||
|
||||
.name {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
display: lock;
|
||||
display: block;
|
||||
vertical-align: middle;
|
||||
text-transform: uppercase;
|
||||
|
||||
span {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,9 @@
|
||||
}
|
||||
|
||||
.transactionDetails {
|
||||
margin-right: 321px;
|
||||
padding-right: 321px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.isConfirmed {
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
}
|
||||
|
||||
.transactionDetails {
|
||||
margin-right: 321px;
|
||||
padding-right: 321px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.mainContainer {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
.signer {
|
||||
width: 916px;
|
||||
}
|
||||
|
||||
.pending {
|
||||
|
||||
Reference in New Issue
Block a user