Merge branch 'master' into jg-signer-decoding

# Conflicts:
#	js/src/views/Signer/components/RequestFinished/requestFinished.js
This commit is contained in:
Jaco Greeff
2016-12-02 11:21:17 +01:00
116 changed files with 2375 additions and 1507 deletions

View File

@@ -144,7 +144,8 @@ export function outSignerRequest (request) {
break;
case 'payload':
request[key].transaction = outTransaction(request[key].transaction);
request[key].signTransaction = outTransaction(request[key].signTransaction);
request[key].sendTransaction = outTransaction(request[key].sendTransaction);
break;
}
});

View File

@@ -0,0 +1 @@
[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_addr","type":"address"},{"name":"_name","type":"bytes32"}],"name":"register","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"fromName","outputs":[{"name":"id","type":"uint256"},{"name":"addr","type":"address"},{"name":"owner","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"badgeCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_fee","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_id","type":"uint256"},{"name":"_key","type":"bytes32"}],"name":"meta","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_id","type":"uint256"}],"name":"unregister","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_addr","type":"address"}],"name":"fromAddress","outputs":[{"name":"id","type":"uint256"},{"name":"name","type":"bytes32"},{"name":"owner","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_id","type":"uint256"}],"name":"badge","outputs":[{"name":"addr","type":"address"},{"name":"name","type":"bytes32"},{"name":"owner","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_id","type":"uint256"},{"name":"_key","type":"bytes32"},{"name":"_value","type":"bytes32"}],"name":"setMeta","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_addr","type":"address"},{"name":"_name","type":"bytes32"},{"name":"_owner","type":"address"}],"name":"registerAs","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"id","type":"uint256"},{"indexed":false,"name":"addr","type":"address"}],"name":"Registered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"id","type":"uint256"}],"name":"Unregistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"id","type":"uint256"},{"indexed":true,"name":"key","type":"bytes32"},{"indexed":false,"name":"value","type":"bytes32"}],"name":"MetaChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}]

View File

@@ -0,0 +1 @@
[{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"}]

View File

@@ -14,6 +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/>.
import badgereg from './badgereg.json';
import basiccoin from './basiccoin.json';
import basiccoinmanager from './basiccoinmanager.json';
import dappreg from './dappreg.json';
@@ -28,6 +29,7 @@ import tokenreg from './tokenreg.json';
import wallet from './wallet.json';
export {
badgereg,
basiccoin,
basiccoinmanager,
dappreg,

View File

@@ -0,0 +1,66 @@
// 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 { bytesToHex, hex2Ascii } from '../api/util/format';
import ABI from './abi/certifier.json';
const ZERO = '0x0000000000000000000000000000000000000000000000000000000000000000';
export default class BadgeReg {
constructor (api, registry) {
this._api = api;
this._registry = registry;
registry.getContract('badgereg');
this.certifiers = {}; // by name
this.contracts = {}; // by name
}
fetchCertifier (name) {
if (this.certifiers[name]) {
return Promise.resolve(this.certifiers[name]);
}
return this._registry.getContract('badgereg')
.then((badgeReg) => {
return badgeReg.instance.fromName.call({}, [name])
.then(([ id, address ]) => {
return Promise.all([
badgeReg.instance.meta.call({}, [id, 'TITLE']),
badgeReg.instance.meta.call({}, [id, 'IMG'])
])
.then(([ title, img ]) => {
title = bytesToHex(title);
title = title === ZERO ? null : hex2Ascii(title);
if (bytesToHex(img) === ZERO) img = null;
const data = { address, name, title, icon: img };
this.certifiers[name] = data;
return data;
});
});
});
}
checkIfCertified (certifier, address) {
if (!this.contracts[certifier]) {
this.contracts[certifier] = this._api.newContract(ABI, certifier);
}
const contract = this.contracts[certifier];
return contract.instance.certified.call({}, [address]);
}
}

View File

@@ -20,6 +20,7 @@ import SignatureReg from './signaturereg';
import TokenReg from './tokenreg';
import GithubHint from './githubhint';
import * as smsVerification from './sms-verification';
import BadgeReg from './badgereg';
let instance = null;
@@ -33,6 +34,7 @@ export default class Contracts {
this._signaturereg = new SignatureReg(api, this._registry);
this._tokenreg = new TokenReg(api, this._registry);
this._githubhint = new GithubHint(api, this._registry);
this.badgeReg = new BadgeReg(api, this._registry);
}
get registry () {

View File

@@ -17,10 +17,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
import injectTapEventPlugin from 'react-tap-event-plugin';
import { useStrict } from 'mobx';
injectTapEventPlugin();
useStrict(true);
import Application from './dappreg/Application';

View File

@@ -11,28 +11,23 @@
height: 100%;
margin: 0;
padding: 0;
}
.loading-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-family: Roboto;
background-color: rgba(0, 0, 0, 0.8);
color: #ddd;
background: white;
font-family: 'Roboto', sans-serif;
font-size: 16px;
font-weight: 300;
}
.loading {
font-size: 4em;
text-align: center;
padding-top: 5em;
font-size: 2em;
color: #999;
}
</style>
</head>
<body>
<div id="container">
<div class="loading-container">
<span class="loading">Loading...</span>
</div>
<div class="loading">Loading</div>
</div>
<script src="vendor.js"></script>
<% if (!htmlWebpackPlugin.options.secure) { %>

View File

@@ -11,28 +11,23 @@
height: 100%;
margin: 0;
padding: 0;
}
.loading-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-family: Roboto;
background-color: rgba(0, 0, 0, 0.8);
color: #ddd;
background: white;
font-family: 'Roboto', sans-serif;
font-size: 16px;
font-weight: 300;
}
.loading {
font-size: 4em;
text-align: center;
padding-top: 5em;
font-size: 2em;
color: #999;
}
</style>
</head>
<body>
<div id="container">
<div class="loading-container">
<span class="loading">Loading...</span>
</div>
<div class="loading">Loading</span>
</div>
<script src="vendor.js"></script>
</body>

View File

@@ -20,6 +20,7 @@ import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
import ContentClear from 'material-ui/svg-icons/content/clear';
import NavigationArrowBack from 'material-ui/svg-icons/navigation/arrow-back';
import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward';
import PrintIcon from 'material-ui/svg-icons/action/print';
import { Button, Modal } from '../../ui';
@@ -32,6 +33,11 @@ import NewImport from './NewImport';
import RawKey from './RawKey';
import RecoveryPhrase from './RecoveryPhrase';
import { createIdentityImg } from '../../api/util/identity';
import print from './print';
import recoveryPage from './recovery-page.ejs';
import ParityLogo from '../../../assets/images/parity-logo-black-no-text.svg';
const TITLES = {
type: 'creation type',
create: 'create account',
@@ -179,12 +185,18 @@ export default class CreateAccount extends Component {
];
case 2:
return (
return [
createType === 'fromNew' || createType === 'fromPhrase' ? (
<Button
icon={ <PrintIcon /> }
label='Print Phrase'
onClick={ this.printPhrase } />
) : null,
<Button
icon={ <ActionDoneAll /> }
label='Close'
onClick={ this.onClose } />
);
];
}
}
@@ -377,4 +389,11 @@ export default class CreateAccount extends Component {
store.dispatch({ type: 'newError', error });
}
printPhrase = () => {
const { address, phrase, name } = this.state;
const identity = createIdentityImg(address);
print(recoveryPage({ phrase, name, identity, address, logo: ParityLogo }));
}
}

View File

@@ -0,0 +1,63 @@
// 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 const onPrint = (window, cb) => {
let called = false; let query, queryFn;
const onPrint = () => {
if (queryFn) {
query.removeListener(queryFn);
}
window.removeEventListener('afterprint', onPrint, false);
if (!called) {
called = true;
cb();
}
};
if (window.matchMedia) {
queryFn = (query) => {
if (!query.matches) {
onPrint();
}
};
query = window.matchMedia('print');
query.addListener(queryFn);
}
window.addEventListener('afterprint', onPrint, false);
};
export default (html) => {
const iframe = document.createElement('iframe');
iframe.setAttribute('sandbox', 'allow-modals allow-same-origin allow-scripts');
iframe.setAttribute('src', '/');
iframe.setAttribute('style', 'display: none');
document.body.appendChild(iframe);
const teardown = () => {
// Safari crashes without a timeout.
setTimeout(() => document.body.removeChild(iframe), 0);
};
setTimeout(() => {
iframe.contentDocument.write(html);
setTimeout(() => {
onPrint(iframe.contentWindow, teardown);
iframe.contentWindow.focus();
iframe.contentWindow.print();
}, 20);
}, 0);
};

View File

@@ -0,0 +1,49 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Recovery phrase for <%= name %></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<style>
body {
margin: 2em auto;
max-width: 30em;
padding: 1em;
text-align: center;
font-size: 110%;
font-family: sans-serif;
font-weight: 300;
}
#logo {
max-width: 4rem;
margin-bottom: 3rem;
}
p {
margin-bottom: 1rem;
}
figure {
margin-bottom: 1rem;
}
figure.address img {
border-radius: 100%;
}
pre code {
display: inline-block;
text-align: center;
white-space: normal;
line-height: 1.3;
}
</style>
</head>
<body>
<img id="logo" src="<%= logo %>" alt="Parity Logo" />
<p>This is your account <em><%= name %></em>:</p>
<figure class="address">
<img src="<%= identity %>" alt="symbol for the address of the account" />
<figcaption><code><%= address %></code></figcaption>
</figure>
<p>This is the recovery phrase:</p>
<pre><code><%= phrase %></code></pre>
</body>
</html>

View File

@@ -18,6 +18,7 @@ import React, { Component, PropTypes } from 'react';
import ActionDone from 'material-ui/svg-icons/action/done';
import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward';
import PrintIcon from 'material-ui/svg-icons/action/print';
import { Button, Modal } from '../../ui';
@@ -27,6 +28,11 @@ import Completed from './Completed';
import TnC from './TnC';
import Welcome from './Welcome';
import { createIdentityImg } from '../../api/util/identity';
import print from '../CreateAccount/print';
import recoveryPage from '../CreateAccount/recovery-page.ejs';
import ParityLogo from '../../../assets/images/parity-logo-black-no-text.svg';
const STAGE_NAMES = ['welcome', 'terms', 'new account', 'recovery', 'completed'];
export default class FirstRun extends Component {
@@ -107,7 +113,6 @@ export default class FirstRun extends Component {
switch (stage) {
case 0:
case 3:
return (
<Button
icon={ <NavigationArrowForward /> }
@@ -133,6 +138,20 @@ export default class FirstRun extends Component {
onClick={ this.onCreate } />
);
case 3:
return [
<Button
icon={ <PrintIcon /> }
label='Print Phrase'
onClick={ this.printPhrase }
/>,
<Button
icon={ <NavigationArrowForward /> }
label='Next'
onClick={ this.onNext }
/>
];
case 4:
return (
<Button
@@ -205,4 +224,11 @@ export default class FirstRun extends Component {
store.dispatch({ type: 'newError', error });
}
printPhrase = () => {
const { address, phrase, name } = this.state;
const identity = createIdentityImg(address);
print(recoveryPage({ phrase, name, identity, address, logo: ParityLogo }));
}
}

View File

@@ -20,17 +20,20 @@ import SettingsMiddleware from '../views/Settings/middleware';
import SignerMiddleware from './providers/signerMiddleware';
import statusMiddleware from '../views/Status/middleware';
import CertificationsMiddleware from './providers/certifications/middleware';
export default function (api) {
const errors = new ErrorsMiddleware();
const signer = new SignerMiddleware(api);
const settings = new SettingsMiddleware();
const status = statusMiddleware();
const certifications = new CertificationsMiddleware();
const middleware = [
settings.toMiddleware(),
signer.toMiddleware(),
errors.toMiddleware()
errors.toMiddleware(),
certifications.toMiddleware()
];
return middleware.concat(status, thunk);

View File

@@ -0,0 +1,23 @@
// 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 const fetchCertifications = (address) => ({
type: 'fetchCertifications', address
});
export const addCertification = (address, name, title, icon) => ({
type: 'addCertification', address, name, title, icon
});

View File

@@ -0,0 +1,51 @@
// 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 Contracts from '../../../contracts';
import { addCertification } from './actions';
const knownCertifiers = [ 'smsverification' ];
export default class CertificationsMiddleware {
toMiddleware () {
return (store) => (next) => (action) => {
if (action.type !== 'fetchCertifications') {
return next(action);
}
const { address } = action;
const badgeReg = Contracts.get().badgeReg;
knownCertifiers.forEach((name) => {
badgeReg.fetchCertifier(name)
.then((cert) => {
return badgeReg.checkIfCertified(cert.address, address)
.then((isCertified) => {
if (isCertified) {
const { name, title, icon } = cert;
store.dispatch(addCertification(address, name, title, icon));
}
});
})
.catch((err) => {
if (err) {
console.error(`Failed to check if ${address} certified by ${name}:`, err);
}
});
});
};
}
}

View 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/>.
const initialState = {};
export default (state = initialState, action) => {
if (action.type !== 'addCertification') {
return state;
}
const { address, name, icon, title } = action;
const certifications = state[address] || [];
if (certifications.some((c) => c.name === name)) {
return state;
}
const newCertifications = certifications.concat({ name, icon, title });
return { ...state, [address]: newCertifications };
};

View File

@@ -72,9 +72,8 @@ export default class SignerMiddleware {
};
// Sign request in-browser
if (wallet && payload.transaction) {
const { transaction } = payload;
const transaction = payload.sendTransaction || payload.signTransaction;
if (wallet && transaction) {
(transaction.nonce.isZero()
? this._api.parity.nextNonce(transaction.from)
: Promise.resolve(transaction.nonce)

View File

@@ -18,6 +18,7 @@ import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import { apiReducer, balancesReducer, blockchainReducer, compilerReducer, imagesReducer, personalReducer, signerReducer, statusReducer as nodeStatusReducer, snackbarReducer } from './providers';
import certificationsReducer from './providers/certifications/reducer';
import errorReducer from '../ui/Errors/reducers';
import settingsReducer from '../views/Settings/reducers';
@@ -32,6 +33,7 @@ export default function () {
settings: settingsReducer,
balances: balancesReducer,
certifications: certificationsReducer,
blockchain: blockchainReducer,
compiler: compilerReducer,
images: imagesReducer,

View File

@@ -0,0 +1,46 @@
/* 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/>.
*/
.certifications {
margin-top: 1em;
}
.certification {
display: inline-block;
position: relative;
margin-right: .5em;
padding: .3em .6em .2em 2.6em;
border-radius: 1em;
line-height: 1em;
text-transform: uppercase;
background-color: rgba(255, 255, 255, 0.07);
}
.certification:last-child {
margin-right: 0;
}
.icon {
position: absolute;
top: -.25em;
left: 0;
width: 2em;
height: 2em;
margin: 0;
padding: 0;
border-radius: 1em;
}

View File

@@ -0,0 +1,87 @@
// 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 { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { hashToImageUrl } from '../../redux/providers/imagesReducer';
import { fetchCertifications } from '../../redux/providers/certifications/actions';
import defaultIcon from '../../../assets/images/certifications/unknown.svg';
import styles from './certifications.css';
class Certifications extends Component {
static propTypes = {
account: PropTypes.string.isRequired,
certifications: PropTypes.array.isRequired,
dappsUrl: PropTypes.string.isRequired,
fetchCertifications: PropTypes.func.isRequired
}
componentWillMount () {
const { account, fetchCertifications } = this.props;
fetchCertifications(account);
}
render () {
const { certifications } = this.props;
if (certifications.length === 0) {
return null;
}
return (
<div className={ styles.certifications }>
{ certifications.map(this.renderCertification) }
</div>
);
}
renderCertification = (certification) => {
const { name, title, icon } = certification;
const { dappsUrl } = this.props;
const classNames = `${styles.certification} ${!icon ? styles.noIcon : ''}`;
const img = icon ? dappsUrl + hashToImageUrl(icon) : defaultIcon;
return (
<div className={ classNames } key={ name }>
<img className={ styles.icon } src={ img } />
<div className={ styles.text }>{ title || name }</div>
</div>
);
}
}
function mapStateToProps (_, initProps) {
const { account } = initProps;
return (state) => {
const certifications = state.certifications[account] || [];
return { certifications };
};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({ fetchCertifications }, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Certifications);

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

View File

@@ -92,7 +92,9 @@ export default class Store {
Promise
.all(txhashes.map((txhash) => this._api.eth.getTransactionByHash(txhash)))
.then((transactions) => {
.then((_transactions) => {
const transactions = _transactions.filter((tx) => tx);
this.addTransactions(
transactions.reduce((transactions, tx, index) => {
transactions[txhashes[index]] = tx;

View File

@@ -23,6 +23,7 @@ import Badge from './Badge';
import Balance from './Balance';
import BlockStatus from './BlockStatus';
import Button from './Button';
import Certifications from './Certifications';
import ConfirmDialog from './ConfirmDialog';
import Container, { Title as ContainerTitle } from './Container';
import ContextProvider from './ContextProvider';
@@ -55,6 +56,7 @@ export {
Balance,
BlockStatus,
Button,
Certifications,
ConfirmDialog,
Container,
ContainerTitle,

View File

@@ -18,6 +18,7 @@ import React, { Component, PropTypes } from 'react';
import { Balance, Container, ContainerTitle, IdentityIcon, IdentityName, Tags } from '../../../ui';
import CopyToClipboard from '../../../ui/CopyToClipboard';
import Certifications from '../../../ui/Certifications';
import styles from './header.css';
@@ -32,6 +33,7 @@ export default class Header extends Component {
}
render () {
const { api } = this.context;
const { account, balance } = this.props;
const { address, meta, uuid } = account;
@@ -67,6 +69,10 @@ export default class Header extends Component {
<Balance
account={ account }
balance={ balance } />
<Certifications
account={ account.address }
dappsUrl={ api.dappsUrl }
/>
</div>
</Container>
</div>

View File

@@ -64,12 +64,6 @@ class Account extends Component {
}
componentDidMount () {
const { api } = this.context;
const { address } = this.props.params;
const { isTestnet } = this.props;
const verificationStore = new VerificationStore(api, address, isTestnet);
this.setState({ verificationStore });
this.setVisibleAccounts();
}
@@ -80,6 +74,15 @@ class Account extends Component {
if (prevAddress !== nextAddress) {
this.setVisibleAccounts(nextProps);
}
const { isTestnet } = nextProps;
if (typeof isTestnet === 'boolean' && !this.state.verificationStore) {
const { api } = this.context;
const { address } = nextProps.params;
this.setState({
verificationStore: new VerificationStore(api, address, isTestnet)
});
}
}
componentWillUnmount () {
@@ -115,7 +118,8 @@ class Account extends Component {
<Page>
<Header
account={ account }
balance={ balance } />
balance={ balance }
/>
<Transactions
accounts={ accounts }
address={ address } />

View File

@@ -19,10 +19,17 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Snackbar as SnackbarMUI } from 'material-ui';
import { darkBlack } from 'material-ui/styles/colors';
import { darkBlack, grey800 } from 'material-ui/styles/colors';
import { closeSnackbar } from '../../../redux/providers/snackbarActions';
const bodyStyle = {
backgroundColor: darkBlack,
borderStyle: 'solid',
borderColor: grey800,
borderWidth: '1px 1px 0 1px'
};
class Snackbar extends Component {
static propTypes = {
closeSnackbar: PropTypes.func.isRequired,
@@ -40,7 +47,7 @@ class Snackbar extends Component {
open={ open }
message={ message }
autoHideDuration={ cooldown }
bodyStyle={ { backgroundColor: darkBlack } }
bodyStyle={ bodyStyle }
onRequestClose={ this.handleClose }
/>
);

View File

@@ -15,45 +15,46 @@
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.status {
padding: 0.5em;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
display: flex;
align-items: center;
padding: .4em .5em;
font-size: x-small;
color: #ccc;
background-color: rgba(0, 0, 0, 0.2)
}
.title {
margin: 0 0.5em 0 2em;
background-color: rgba(0, 0, 0, 0.8);
}
.enode {
word-wrap: break-word;
float: right;
}
.enode > * {
display: inline-block;
margin: 0.25em 0.5em;
vertical-align: top;
margin: 0 .25em;
vertical-align: middle;
}
.block {
.enode > :last-child {
margin-right: 0;
}
.netinfo {
display: flex;
flex-grow: 1;
align-items: center;
color: #ddd;
color: #ddd;
}
.netinfo > * {
display: inline-block;
margin-left: 1em;
}
.network {
padding: 0.25em 0.5em;
display: inline-block;
border-radius: 4px;
border-radius: .4em;
line-height: 1.2;
text-transform: uppercase;
}
@@ -65,14 +66,3 @@
.networktest {
background: rgb(136, 0, 0);
}
.peers {
}
.version {
padding: 0.25em 0.5em;
float: left;
}
.syncing {
}

View File

@@ -46,7 +46,6 @@ class Status extends Component {
<div className={ styles.version }>
{ clientVersion }
</div>
{ this.renderEnode() }
<div className={ styles.netinfo }>
<BlockStatus />
<div className={ netStyle }>
@@ -56,6 +55,7 @@ class Status extends Component {
{ netPeers.active.toFormat() }/{ netPeers.connected.toFormat() }/{ netPeers.max.toFormat() } peers
</div>
</div>
{ this.renderEnode() }
</div>
);
}
@@ -73,7 +73,7 @@ class Status extends Component {
return (
<div className={ styles.enode }>
<CopyToClipboard data={ enode } />
<CopyToClipboard data={ enode } size={ 12 } />
<div>{ abbreviated }</div>
</div>
);

View File

@@ -59,7 +59,7 @@ class Tab extends Component {
selected={ active }
icon={ view.icon }
label={ label }
onClick={ this.handleClick }
onTouchTap={ this.handleClick }
>
{ children }
</MUITab>

View File

@@ -21,3 +21,7 @@
display: flex;
flex-direction: column;
}
.container {
padding-bottom: 1.6em;
}

View File

@@ -16,7 +16,7 @@
import React, { Component, PropTypes } from 'react';
import { Container, ContainerTitle } from '../../../ui';
import { Container } from '../../../ui';
import Event from './Event';
import styles from '../contract.css';
@@ -48,8 +48,7 @@ export default class Events extends Component {
});
return (
<Container>
<ContainerTitle title='events' />
<Container title='events'>
<table className={ styles.events }>
<tbody>{ list }</tbody>
</table>

View File

@@ -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, InputAddress } from '../../../ui';
import { Container, Input, InputAddress } from '../../../ui';
import styles from './queries.css';
@@ -55,8 +55,7 @@ export default class Queries extends Component {
.map((fn) => this.renderInputQuery(fn));
return (
<Container>
<ContainerTitle title='queries' />
<Container title='queries'>
<div className={ styles.methods }>
<div className={ styles.vMethods }>
{ noInputQueries }

View File

@@ -132,7 +132,8 @@ class Contract extends Component {
<Page>
<Header
account={ account }
balance={ balance } />
balance={ balance }
/>
<Queries
contract={ contract }
values={ queryValues } />
@@ -447,7 +448,10 @@ function mapStateToProps (state) {
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({ newError, setVisibleAccounts }, dispatch);
return bindActionCreators({
newError,
setVisibleAccounts
}, dispatch);
}
export default connect(

View File

@@ -42,25 +42,26 @@
}
.expanded {
right: 16px;
max-height: 300px;
right: 1em;
border-radius: 4px 4px 0 0;
overflow-y: auto;
display: flex;
flex-direction: column;
max-height: 19em;
}
.expanded .content {
flex: 1;
overflow: auto;
overflow-y: auto;
overflow-x: hidden;
display: flex;
background: rgba(0, 0, 0, 0.8);
min-height: 16em;
}
.corner {
position: absolute;
bottom: 0;
right: 16px;
right: 1em;
border-radius: 4px 4px 0 0;
}
@@ -118,7 +119,7 @@
}
.header {
height: 36px;
height: 2em;
padding: 0.5em 1em;
background: rgba(0, 0, 0, 0.25);
margin-bottom: 0;
@@ -148,6 +149,7 @@
.actions {
float: right;
margin-top: -2px;
}
.actions div {

View File

@@ -19,7 +19,7 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import NavigationRefresh from 'material-ui/svg-icons/navigation/refresh';
import { Button, Container, ContainerTitle, ParityBackground } from '../../../ui';
import { Button, Container, ParityBackground } from '../../../ui';
import { updateBackground } from '../actions';
@@ -55,8 +55,7 @@ class Background extends Component {
render () {
return (
<Container>
<ContainerTitle title='Background Pattern' />
<Container title='Background Pattern'>
<div className={ layout.layout }>
<div className={ layout.overview }>
<div>The background pattern you can see right now is unique to your Parity installation. It will change every time you create a new Signer token. This is so that decentralized applications cannot pretend to be trustworthy.</div>

View File

@@ -17,7 +17,7 @@
import React, { Component, PropTypes } from 'react';
import { MenuItem } from 'material-ui';
import { Select, Container, ContainerTitle } from '../../../ui';
import { Select, Container } from '../../../ui';
import layout from '../layout.css';
@@ -43,8 +43,7 @@ export default class Parity extends Component {
render () {
return (
<Container>
<ContainerTitle title='Parity' />
<Container title='Parity'>
<div className={ layout.layout }>
<div className={ layout.overview }>
<div>Control the Parity node settings and mode of operation via this interface.</div>

View File

@@ -16,7 +16,7 @@
import React, { Component, PropTypes } from 'react';
import { Container, ContainerTitle } from '../../../ui';
import { Container } from '../../../ui';
import layout from '../layout.css';
import styles from './proxy.css';
@@ -31,8 +31,7 @@ export default class Proxy extends Component {
const proxyurl = `${dappsUrl}/proxy/proxy.pac`;
return (
<Container>
<ContainerTitle title='Proxy' />
<Container title='Proxy'>
<div className={ layout.layout }>
<div className={ layout.overview }>
<div>The proxy setup allows you to access Parity and all associated decentralized applications via memorable addresses.</div>

View File

@@ -19,7 +19,7 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Checkbox } from 'material-ui';
import { Container, ContainerTitle } from '../../../ui';
import { Container } from '../../../ui';
import { toggleView } from '../actions';
@@ -34,8 +34,7 @@ class Views extends Component {
render () {
return (
<Container>
<ContainerTitle title='Views' />
<Container title='Views'>
<div className={ layout.layout }>
<div className={ layout.overview }>
<div>Manage the available application views, using only the parts of the application that is applicable to you.</div>

View File

@@ -27,7 +27,8 @@ export default class RequestPending extends Component {
isSending: PropTypes.bool.isRequired,
date: PropTypes.instanceOf(Date).isRequired,
payload: PropTypes.oneOfType([
PropTypes.shape({ transaction: PropTypes.object.isRequired }),
PropTypes.shape({ signTransaction: PropTypes.object.isRequired }),
PropTypes.shape({ sendTransaction: PropTypes.object.isRequired }),
PropTypes.shape({ sign: PropTypes.object.isRequired })
]).isRequired,
className: PropTypes.string,
@@ -64,9 +65,8 @@ export default class RequestPending extends Component {
);
}
if (payload.transaction) {
const { transaction } = payload;
const transaction = payload.sendTransaction || payload.signTransaction;
if (transaction) {
return (
<TransactionPending
className={ className }

View File

@@ -20,7 +20,7 @@ import AvPlay from 'material-ui/svg-icons/av/play-arrow';
import AvReplay from 'material-ui/svg-icons/av/replay';
import ReorderIcon from 'material-ui/svg-icons/action/reorder';
import { Container, ContainerTitle } from '../../../../ui';
import { Container } from '../../../../ui';
import styles from './Debug.css';
@@ -42,9 +42,7 @@ export default class Debug extends Component {
const { devLogsLevels } = nodeStatus;
return (
<Container>
<ContainerTitle
title='Node Logs' />
<Container title='Node Logs'>
{ this.renderActions() }
<h2 className={ styles.subheader }>
{ devLogsLevels || '-' }