Initial new UI source code import (#2607)

* address -> name mappings

* expanding, loading all coin details

* send use only actual BasicCoin tokens registered (any reg)

* sending token & accounts

* form styling updates

* send form layout in place

* coin send working as expected

* api subscriptions on multiple addresses

* bring in events

* simplify

* basic events display in-place, functionally complete

* basic functionality in-place

* fix horrible event address issue

* rwork display of events slightly

* test TLA availability

* table for owner -> tokens

* fix signature lookup address

* fix signature lookup address

* basic overview styling

* txhash links

* page layout adjustments

* background import

* adjust colors

* no global registration, simplify color selection

* updated styling

* connection dialog for "busy connecting"

* initial token connection - WIP

* init token updates take place

* basic test for manual token

* rework connection display

* allow updates of the secure token

* first stab at making the build build

* update runner tags

* fix linting issues

* skip tests requiring network (should be e2e, TODO)

* re-enable javascript tag/runner

* release push does the trick

* push to any branch, CI name

* javscript-test runner as well

* swap dependencies build requires test

* revert stages swap

* retrieve images associated with tokens

* remove js build deps order

* null image when hash = 0x0

* 6x64 images (hashes for registries)

* don't pass tokens as prop to IdentityIcon

* check images against content hash pictures

* cleanup signer after connection changes

* fix naming typo

* display unknownImages for balances (not available as content hash)

* unknownImage for transfer dialog

* basic githubhint layout

* single input for commit/filename

* ethcore_hashContent call

* lookup hash

* registration in place

* fixes

* events is using a proper table

* pass value through as-is

* stop wrongly using main app IdentityIcon

* NEVER export class instance functions

* alignment back to normal

* typo  in definition

* set & get images working (mostly)

* show content retrieval info

* set exitcode via ||

* use javascript:latest images

* disable npm progress bar

* rename phase I

* rename phase II

* only send build output to GitHub on major branches

* also run the build step as part of the test (until comprehensive)

* ci-specific build (no webpack progress)

* allow for account creation via recovery phrase

* display account uuid (where available), closes #2546

* connection dialog now shows up in dapps as well, closes #2538

* token images show up as expected

* IdentityName component added and deployed

* fix padding tests

* adjust tests to map to stricter 0x-prefixed hex

* render names via common component for the address -> name

* split lint into seperate script (early exit)

* test phases changed to lint, test & pack

* pack part of test phase

* remove files marked for deletion (cleanup)

* Signer cleanups, start moving in the direction of the rest

* add personal signer methods

* basic signer request subscription

* don't poll blockNumber when not connected

* missing return, creating massive ws queue backlogs

* ΞTH -> ETH

* fix failing tests

* registry uses setAddress to actually set addresses now

* bytes mapping operates on lowerCase hex strings

* sha3 ids for each application

* add dappreg to list of contracts

* adjust alignment of queries

* show gas estimation log

* abi with payable for register function

* add key as required

* image retrieval from dappreg

* use proper Image urls

* embed and link apps from Parity, retrieved via /api/apps

* filter apps that has been replaced

* proxy entry for parity-utils

* add basiccoin abi

* add support for fallback abi type

* capture constructor paramaters

* merge master into js

* move images to assets/images/

* add font assets

* import fonts as part of build

* don't inline woff files

* Revert "merge master into js"

This reverts commit cfcfa81bd26f1b3cbc748d3afa1eb5c670b363fe.

* remove unused npm packages

* information on gas estimates (like almost everywhere else)

* don't pass gas & gasPrice to estimation

* display account passwordhint when available

* signer subscriptions based on polling & function trapping

* pending requests retrieved via jsapi

* update signer middleware

* remove all web3 instances

* remove web3 package

* last web3 dependencies removed

* no need to toChecksumAddress - api takes care of it

* expand description for personal_confirmRequest

* Signer conversion from web3 -> parity.js completed

* explicit in no return

* green circle background

* remove generated background

* convert /api/* paths to localhost:8080/api/* paths (hard-coded, temporary)

* change dapps to load from localhost:8080/ui/*

* remove dangling web3 files

* update manager test for signer

* /api/ping -> /

* additional token images

* additional token images

* add missing styles.css for 8180 error pages

* cater for txhash returning null/empty object

* adjust output directories

* Release merge with origin with ours strategy

* additional token images

* cater for development server

* s/localhost/127.0.0.1/ (cater for origin)

* Fix address selection for contract deployment

* Adjust z-index for error overlay

* better text on unique background pattern

* fix signer rejections

* Don't allow gavcoin transfer with no balance

* fix txhash rendering in signer

* remove unnecessary ParityBackground

* script to update js-precompiled

* Redirect from :8080 to :8180

* Remove extra return

* Dapp logo images
This commit is contained in:
Jaco Greeff
2016-10-18 11:52:56 +02:00
committed by Gav Wood
parent 6c7af57529
commit 1e6a2cb378
969 changed files with 57315 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
/* 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/>.
*/
.balances {
clear: both;
}
.editicon {
margin-left: 0.5em;
}
.floatleft {
float: left;
margin-bottom: 0.5em;
}
.addressline,
.infoline,
.uuidline {
line-height: 1.618em;
}
.infoline,
.uuidline {
opacity: 0.25;
}
.uuidline {
display: inline-block;
}

View File

@@ -0,0 +1,121 @@
// 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 { Balance, Container, ContainerTitle, IdentityIcon, IdentityName } from '../../../ui';
import styles from './header.css';
export default class Header extends Component {
static contextTypes = {
api: PropTypes.object
}
static propTypes = {
account: PropTypes.object,
balance: PropTypes.object,
isTest: PropTypes.bool
}
state = {
name: null
}
componentWillMount () {
this.setName();
}
componentWillReceiveProps () {
this.setName();
}
render () {
const { account, balance } = this.props;
const { address, meta, uuid } = account;
if (!account) {
return null;
}
const uuidText = !uuid
? null
: <div className={ styles.uuidline }>uuid: { uuid }</div>;
return (
<Container>
<IdentityIcon
address={ address } />
<div className={ styles.floatleft }>
<ContainerTitle title={ <IdentityName address={ address } unknown /> } />
<div className={ styles.addressline }>
{ address }
</div>
{ uuidText }
<div className={ styles.infoline }>
{ meta.description }
</div>
{ this.renderTxCount() }
</div>
<div className={ styles.balances }>
<Balance
account={ account }
balance={ balance } />
</div>
</Container>
);
}
renderTxCount () {
const { isTest, balance } = this.props;
if (!balance) {
return null;
}
const txCount = balance.txCount.sub(isTest ? 0x100000 : 0);
return (
<div className={ styles.infoline }>
{ txCount.toFormat() } outgoing transactions
</div>
);
}
onSubmitName = (name) => {
const { api } = this.context;
const { account } = this.props;
this.setState({ name }, () => {
api.personal
.setAccountName(account.address, name)
.catch((error) => {
console.error(error);
});
});
}
setName () {
const { account } = this.props;
if (account && account.name !== this.propName) {
this.propName = account.name;
this.setState({
name: account.name
});
}
}
}

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

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

View File

@@ -0,0 +1,193 @@
// 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 BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react';
import moment from 'moment';
import { IdentityIcon, IdentityName, MethodDecoding } from '../../../../ui';
import styles from '../transactions.css';
export default class Transaction extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
}
static propTypes = {
transaction: PropTypes.object.isRequired,
address: PropTypes.string.isRequired,
isTest: PropTypes.bool.isRequired
}
state = {
info: null,
isContract: false,
isReceived: false
}
componentDidMount () {
const { address, transaction } = this.props;
this.lookup(address, transaction);
}
render () {
const { transaction, isTest } = this.props;
const { block } = this.state;
const prefix = `https://${isTest ? 'testnet.' : ''}etherscan.io/`;
return (
<tr>
<td className={ styles.timestamp }>
<div>{ this.formatBlockTimestamp(block) }</div>
<div>{ this.formatNumber(transaction.blockNumber) }</div>
</td>
{ this.renderAddress(prefix, transaction.from) }
{ this.renderTransaction() }
{ this.renderAddress(prefix, transaction.to) }
<td className={ styles.method }>
{ this.renderMethod() }
</td>
</tr>
);
}
renderMethod () {
const { address } = this.props;
const { info } = this.state;
if (!info) {
return null;
}
return (
<MethodDecoding
historic
address={ address }
transaction={ info } />
);
}
renderTransaction () {
const { transaction, isTest } = this.props;
const prefix = `https://${isTest ? 'testnet.' : ''}etherscan.io/`;
const hashLink = `${prefix}tx/${transaction.hash}`;
return (
<td className={ styles.transaction }>
{ this.renderEtherValue() }
<div></div>
<div>
<a href={ hashLink } target='_blank' className={ styles.link }>
{ this.formatHash(transaction.hash) }
</a>
</div>
</td>
);
}
renderAddress (prefix, address) {
const eslink = address ? (
<a
href={ `${prefix}address/${address}` }
target='_blank'
className={ styles.link }>
<IdentityName address={ address } shorten />
</a>
) : 'DEPLOY';
return (
<td className={ styles.address }>
<div className={ styles.center }>
<IdentityIcon
center
className={ styles.icon }
address={ address } />
</div>
<div className={ styles.center }>
{ eslink }
</div>
</td>
);
}
renderEtherValue () {
const { api } = this.context;
const { info } = this.state;
if (!info) {
return null;
}
const value = api.util.fromWei(info.value);
if (value.eq(0)) {
return <div className={ styles.value }>{ ' ' }</div>;
}
return (
<div className={ styles.value }>
{ value.toFormat(5) }<small>ETH</small>
</div>
);
}
formatHash (hash) {
if (!hash || hash.length <= 16) {
return hash;
}
return `${hash.substr(2, 6)}...${hash.slice(-6)}`;
}
formatNumber (number) {
return new BigNumber(number).toFormat();
}
formatBlockTimestamp (block) {
if (!block) {
return null;
}
return moment(block.timestamp).fromNow();
}
lookup (address, transaction) {
const { api } = this.context;
const { info } = this.state;
if (info) {
return;
}
this.setState({ isReceived: address === transaction.to });
Promise
.all([
api.eth.getBlockByNumber(transaction.blockNumber),
api.eth.getTransactionByHash(transaction.hash)
])
.then(([block, info]) => {
this.setState({ block, info });
})
.catch((error) => {
console.error('lookup', error);
});
}
}

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

View File

@@ -0,0 +1,101 @@
/* 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/>.
*/
.right {
text-align: right;
}
.center {
text-align: center;
}
.left {
text-align: left;
}
.transactions {
}
.transactions table {
width: 100%;
border-collapse: collapse;
}
.transactions tr {
line-height: 32px;
vertical-align: top;
}
.transactions tr:nth-child(even) {
background: rgba(255, 255, 255, 0.04);
}
.transactions th {
color: #aaa;
text-align: center;
}
.transactions td {
vertical-align: top;
padding: 0.75em 0.75em;
}
.transactions .link {
vertical-align: top;
}
.infonone {
opacity: 0.25;
}
.etherscan {
text-align: right;
padding-top: 1em;
font-size: 0.75em;
color: #aaa;
}
.address {
text-align: center;
}
.transaction {
text-align: center;
}
.transactions td.transaction {
padding-top: 1.5em;
}
.transaction div {
line-height: 1.25em;
min-height: 1.25em;
}
.icon {
margin: 0;
}
.method {
width: 40%;
}
.transactions td.timestamp {
padding-top: 1.5em;
text-align: right;
line-height: 1.5em;
opacity: 0.5;
}

View File

@@ -0,0 +1,148 @@
// 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 LinearProgress from 'material-ui/LinearProgress';
import etherscan from '../../../3rdparty/etherscan';
import { Container, ContainerTitle } from '../../../ui';
import Transaction from './Transaction';
import styles from './transactions.css';
class Transactions extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
}
static propTypes = {
address: PropTypes.string.isRequired,
accounts: PropTypes.object,
contacts: PropTypes.object,
contracts: PropTypes.object,
tokens: PropTypes.object,
isTest: PropTypes.bool
}
state = {
transactions: [],
loading: true,
callInfo: {}
}
componentDidMount () {
this.getTransactions();
}
render () {
return (
<Container>
<ContainerTitle title='transactions' />
{ this.renderTransactions() }
</Container>
);
}
renderTransactions () {
const { loading, transactions } = this.state;
if (loading) {
return (
<LinearProgress mode='indeterminate' />
);
} else if (!transactions.length) {
return (
<div className={ styles.infonone }>
No transactions were found for this account
</div>
);
}
return (
<div className={ styles.transactions }>
<table>
<tbody>
{ this.renderRows() }
</tbody>
</table>
<div className={ styles.etherscan }>
Transaction list powered by <a href='https://etherscan.io/' target='_blank'>etherscan.io</a>
</div>
</div>
);
}
renderRows () {
const { address, accounts, contacts, contracts, tokens, isTest } = this.props;
const { transactions } = this.state;
return (transactions || []).map((transaction, index) => {
return (
<Transaction
key={ index }
transaction={ transaction }
address={ address }
accounts={ accounts }
contacts={ contacts }
contracts={ contracts }
tokens={ tokens }
isTest={ isTest } />
);
});
}
getTransactions = () => {
const { isTest, address } = this.props;
return etherscan.account
.transactions(address, 0, isTest)
.then((transactions) => {
this.setState({
transactions,
loading: false
});
})
.catch((error) => {
console.error('getTransactions', error);
});
}
}
function mapStateToProps (state) {
const { isTest } = state.nodeStatus;
const { accounts, contacts, contracts } = state.personal;
const { tokens } = state.balances;
return {
isTest,
accounts,
contacts,
contracts,
tokens
};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({}, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Transactions);

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/>.
*/
.account {
}
.btnicon {
width: 24px;
height: 24px;
}

View File

@@ -0,0 +1,207 @@
// 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 ContentCreate from 'material-ui/svg-icons/content/create';
import ContentSend from 'material-ui/svg-icons/content/send';
import { EditMeta, Shapeshift, Transfer } from '../../modals';
import { Actionbar, Button, Page } from '../../ui';
import shapeshiftBtn from '../../../assets/images/shapeshift-btn.png';
import Header from './Header';
import Transactions from './Transactions';
import styles from './account.css';
class Account extends Component {
static propTypes = {
params: PropTypes.object,
accounts: PropTypes.object,
balances: PropTypes.object,
images: PropTypes.object.isRequired,
isTest: PropTypes.bool
}
propName = null
state = {
showEditDialog: false,
showFundDialog: false,
showTransferDialog: false
}
render () {
const { accounts, balances, isTest } = this.props;
const { address } = this.props.params;
const account = (accounts || {})[address];
const balance = (balances || {})[address];
if (!account) {
return null;
}
return (
<div className={ styles.account }>
{ this.renderEditDialog(account) }
{ this.renderFundDialog() }
{ this.renderTransferDialog() }
{ this.renderActionbar() }
<Page>
<Header
isTest={ isTest }
account={ account }
balance={ balance } />
<Transactions
accounts={ accounts }
address={ address } />
</Page>
</div>
);
}
renderActionbar () {
const buttons = [
<Button
key='transferFunds'
icon={ <ContentSend /> }
label='transfer'
onClick={ this.onTransferClick } />,
<Button
key='shapeshift'
icon={ <img src={ shapeshiftBtn } className={ styles.btnicon } /> }
label='shapeshift'
onClick={ this.onShapeshiftAccountClick } />,
<Button
key='editmeta'
icon={ <ContentCreate /> }
label='edit'
onClick={ this.onEditClick } />
];
return (
<Actionbar
title='Account Management'
buttons={ buttons } />
);
}
renderEditDialog (account) {
const { showEditDialog } = this.state;
if (!showEditDialog) {
return null;
}
return (
<EditMeta
account={ account }
keys={ ['description', 'passwordHint'] }
onClose={ this.onEditClick } />
);
}
renderFundDialog () {
const { showFundDialog } = this.state;
if (!showFundDialog) {
return null;
}
const { address } = this.props.params;
return (
<Shapeshift
address={ address }
onClose={ this.onShapeshiftAccountClose } />
);
}
renderTransferDialog () {
const { showTransferDialog } = this.state;
if (!showTransferDialog) {
return null;
}
const { address } = this.props.params;
const { accounts, balances, images } = this.props;
const account = accounts[address];
const balance = balances[address];
return (
<Transfer
account={ account }
balance={ balance }
balances={ balances }
images={ images }
onClose={ this.onTransferClose } />
);
}
onEditClick = () => {
this.setState({
showEditDialog: !this.state.showEditDialog
});
}
onShapeshiftAccountClick = () => {
this.setState({
showFundDialog: !this.state.showFundDialog
});
}
onShapeshiftAccountClose = () => {
this.onShapeshiftAccountClick();
}
onTransferClick = () => {
this.setState({
showTransferDialog: !this.state.showTransferDialog
});
}
onTransferClose = () => {
this.onTransferClick();
}
}
function mapStateToProps (state) {
const { accounts } = state.personal;
const { balances } = state.balances;
const { images } = state;
const { isTest } = state.nodeStatus;
return {
isTest,
accounts,
balances,
images
};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({}, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Account);

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

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

View File

@@ -0,0 +1,45 @@
/* 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/>.
*/
.list {
display: flex;
flex-wrap: wrap;
}
.item {
flex: 0 1 50%;
width: 50%;
position: relative;
padding-bottom: 0.25em;
box-sizing: border-box;
}
.item:nth-child(odd) {
padding-right: 0.125em;
}
.item:nth-child(even) {
padding-left: 0.125em;
}
.empty {
width: 100%;
display: block;
}
.empty div {
color: #aaa;
}

View File

@@ -0,0 +1,69 @@
// 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 { Container } from '../../../ui';
import Summary from '../Summary';
import styles from './list.css';
export default class List extends Component {
static propTypes = {
accounts: PropTypes.object,
balances: PropTypes.object,
link: PropTypes.string,
empty: PropTypes.bool
};
render () {
return (
<div className={ styles.list }>
{ this.renderAccounts() }
</div>
);
}
renderAccounts () {
const { accounts, balances, link, empty } = this.props;
if (empty) {
return (
<Container className={ styles.empty }>
<div>
There are currently no accounts or addresses to display.
</div>
</Container>
);
}
return Object.keys(accounts).map((address, idx) => {
const account = accounts[address] || {};
const balance = balances[address] || {};
return (
<div
className={ styles.item }
key={ address }>
<Summary
link={ link }
account={ account }
balance={ balance } />
</div>
);
});
}
}

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

View File

@@ -0,0 +1,60 @@
// 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 { Link } from 'react-router';
import { Balance, Container, ContainerTitle, IdentityIcon, IdentityName } from '../../../ui';
export default class Summary extends Component {
static contextTypes = {
api: React.PropTypes.object
}
static propTypes = {
account: PropTypes.object.isRequired,
balance: PropTypes.object.isRequired,
link: PropTypes.string,
children: PropTypes.node
}
state = {
name: 'Unnamed'
}
render () {
const { account, balance, children, link } = this.props;
if (!account) {
return null;
}
const viewLink = `/${link || 'account'}/${account.address}`;
return (
<Container>
<IdentityIcon
address={ account.address } />
<ContainerTitle
title={ <Link to={ viewLink }>{ <IdentityName address={ account.address } unknown /> }</Link> }
byline={ account.address } />
<Balance
balance={ balance } />
{ children }
</Container>
);
}
}

View File

@@ -0,0 +1,32 @@
/* 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/>.
*/
.accounts {
}
.accountTooltip {
top: 13.3em;
left: 7em;
}
.toolbar {
position: relative;
}
.toolbarTooltip {
right: 1em;
top: 4em;
}

View File

@@ -0,0 +1,134 @@
// 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 ContentAdd from 'material-ui/svg-icons/content/add';
import List from './List';
import { CreateAccount } from '../../modals';
import { Actionbar, Button, Page, Tooltip } from '../../ui';
import styles from './accounts.css';
class Accounts extends Component {
static contextTypes = {
api: PropTypes.object
}
static propTypes = {
accounts: PropTypes.object,
hasAccounts: PropTypes.bool,
balances: PropTypes.object
}
state = {
addressBook: false,
newDialog: false
}
render () {
const { accounts, hasAccounts, balances } = this.props;
return (
<div className={ styles.accounts }>
{ this.renderNewDialog() }
{ this.renderActionbar() }
<Page>
<List
accounts={ accounts }
balances={ balances }
empty={ !hasAccounts } />
<Tooltip
className={ styles.accountTooltip }
text='your accounts are visible for easy access, allowing you to edit the meta information, make transfers, view transactions and fund the account' />
</Page>
</div>
);
}
renderActionbar () {
const buttons = [
<Button
key='newAccount'
icon={ <ContentAdd /> }
label='new account'
onClick={ this.onNewAccountClick } />
];
return (
<Actionbar
className={ styles.toolbar }
title='Accounts Overview'
buttons={ buttons }>
<Tooltip
className={ styles.toolbarTooltip }
right
text='actions relating to the current view are available on the toolbar for quick access, be it for performing actions or creating a new item' />
</Actionbar>
);
}
renderNewDialog () {
const { accounts } = this.props;
const { newDialog } = this.state;
if (!newDialog) {
return null;
}
return (
<CreateAccount
accounts={ accounts }
onClose={ this.onNewAccountClose }
onUpdate={ this.onNewAccountUpdate } />
);
}
onNewAccountClick = () => {
this.setState({
newDialog: !this.state.newDialog
});
}
onNewAccountClose = () => {
this.onNewAccountClick();
}
onNewAccountUpdate = () => {
}
}
function mapStateToProps (state) {
const { accounts, hasAccounts } = state.personal;
const { balances } = state.balances;
return {
accounts,
hasAccounts,
balances
};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({}, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Accounts);

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

View File

@@ -0,0 +1,113 @@
// 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 { ConfirmDialog, IdentityIcon, IdentityName } from '../../../ui';
import { newError } from '../../../redux/actions';
import styles from '../address.css';
class Delete extends Component {
static contextTypes = {
api: PropTypes.object.isRequired,
router: PropTypes.object
}
static propTypes = {
address: PropTypes.string,
account: PropTypes.object,
route: PropTypes.string.isRequired,
visible: PropTypes.bool,
onClose: PropTypes.func,
newError: PropTypes.func
}
render () {
const { account, visible } = this.props;
if (!visible) {
return null;
}
return (
<ConfirmDialog
className={ styles.delete }
title='confirm removal'
visible
onDeny={ this.closeDeleteDialog }
onConfirm={ this.onDeleteConfirmed }>
<div className={ styles.hero }>
Are you sure you want to remove the following address from your addressbook?
</div>
<div className={ styles.info }>
<IdentityIcon
className={ styles.icon }
address={ account.address } />
<div className={ styles.nameinfo }>
<div className={ styles.header }>
<IdentityName address={ account.address } unknown />
</div>
<div className={ styles.address }>
{ account.address }
</div>
</div>
</div>
<div className={ styles.description }>
{ account.meta.description }
</div>
</ConfirmDialog>
);
}
onDeleteConfirmed = () => {
const { api, router } = this.context;
const { account, route, newError } = this.props;
account.meta.deleted = true;
api.personal
.setAccountMeta(account.address, account.meta)
.then(() => {
router.push(route);
this.closeDeleteDialog();
})
.catch((error) => {
console.error('onDeleteConfirmed', error);
newError(new Error(`Deletion failed: ${error.message}`));
this.closeDeleteDialog();
});
}
closeDeleteDialog = () => {
this.props.onClose();
}
}
function mapStateToProps (state) {
return {};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({ newError }, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Delete);

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

View File

@@ -0,0 +1,50 @@
/* 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/>.
*/
.address {
}
.delete .hero {
padding-bottom: 1em;
}
.delete .info {
display: inline-block;
}
.delete .icon {
display: inline-block;
}
.delete .nameinfo {
display: inline-block;
text-align: left;
}
.delete .header {
text-transform: uppercase;
font-size: 1.25em;
padding-bottom: 0.25em;
}
.delete .address {
}
.delete .description {
padding-top: 1em;
font-size: 0.75em;
color: #aaa;
}

View File

@@ -0,0 +1,153 @@
// 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 ActionDelete from 'material-ui/svg-icons/action/delete';
import ContentCreate from 'material-ui/svg-icons/content/create';
import { EditMeta } from '../../modals';
import { Actionbar, Button, Page } from '../../ui';
import Header from '../Account/Header';
import Transactions from '../Account/Transactions';
import Delete from './Delete';
import styles from './address.css';
class Address extends Component {
static contextTypes = {
api: PropTypes.object.isRequired,
router: PropTypes.object.isRequired
}
static propTypes = {
contacts: PropTypes.object,
balances: PropTypes.object,
isTest: PropTypes.bool,
params: PropTypes.object
}
state = {
showDeleteDialog: false,
showEditDialog: false
}
render () {
const { contacts, balances, isTest } = this.props;
const { address } = this.props.params;
const { showDeleteDialog } = this.state;
const contact = (contacts || {})[address];
const balance = (balances || {})[address];
if (!contact) {
return null;
}
return (
<div className={ styles.address }>
{ this.renderEditDialog(contact) }
{ this.renderActionbar(contact) }
<Delete
account={ contact }
visible={ showDeleteDialog }
route='/addresses'
onClose={ this.closeDeleteDialog } />
<Page>
<Header
isTest={ isTest }
account={ contact }
balance={ balance } />
<Transactions
address={ address } />
</Page>
</div>
);
}
renderActionbar (contact) {
const buttons = [
<Button
key='editmeta'
icon={ <ContentCreate /> }
label='edit'
onClick={ this.onEditClick } />,
<Button
key='delete'
icon={ <ActionDelete /> }
label='delete address'
onClick={ this.showDeleteDialog } />
];
return (
<Actionbar
title='Address Information'
buttons={ !contact || contact.meta.deleted ? [] : buttons } />
);
}
renderEditDialog (contact) {
const { showEditDialog } = this.state;
if (!showEditDialog) {
return null;
}
return (
<EditMeta
account={ contact }
keys={ ['description'] }
onClose={ this.onEditClick } />
);
}
onEditClick = () => {
this.setState({
showEditDialog: !this.state.showEditDialog
});
}
closeDeleteDialog = () => {
this.setState({ showDeleteDialog: false });
}
showDeleteDialog = () => {
this.setState({ showDeleteDialog: true });
}
}
function mapStateToProps (state) {
const { contacts } = state.personal;
const { balances } = state.balances;
const { isTest } = state.nodeStatus;
return {
isTest,
contacts,
balances
};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({}, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Address);

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

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/>.
*/
.addresses {
}
.list {
display: flex;
flex-wrap: wrap;
}
.address {
flex: 0 1 50%;
width: 50%;
position: relative;
}
.address:nth-child(odd)>div {
padding-right: 0.5em !important;
}
.address:nth-child(even)>div {
padding-left: 0.5em !important;
}
.empty {
width: 100%;
display: block;
}
.empty div {
color: #aaa;
}

View File

@@ -0,0 +1,122 @@
// 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 ContentAdd from 'material-ui/svg-icons/content/add';
import List from '../Accounts/List';
import { AddAddress } from '../../modals';
import { Actionbar, Button, Page } from '../../ui';
import styles from './addresses.css';
class Addresses extends Component {
static contextTypes = {
api: PropTypes.object
}
static propTypes = {
balances: PropTypes.object,
contacts: PropTypes.object,
hasContacts: PropTypes.bool
}
state = {
showAdd: false
}
render () {
const { balances, contacts, hasContacts } = this.props;
return (
<div className={ styles.addresses }>
{ this.renderActionbar() }
{ this.renderAddAddress() }
<Page>
<List
link='address'
accounts={ contacts }
balances={ balances }
empty={ !hasContacts } />
</Page>
</div>
);
}
renderActionbar () {
const buttons = [
<Button
key='newAddress'
icon={ <ContentAdd /> }
label='new address'
onClick={ this.onOpenAdd } />
];
return (
<Actionbar
className={ styles.toolbar }
title='Saved Addresses'
buttons={ buttons } />
);
}
renderAddAddress () {
const { contacts } = this.props;
const { showAdd } = this.state;
if (!showAdd) {
return null;
}
return (
<AddAddress
contacts={ contacts }
onClose={ this.onCloseAdd } />
);
}
onOpenAdd = () => {
this.setState({
showAdd: true
});
}
onCloseAdd = () => {
this.setState({ showAdd: false });
}
}
function mapStateToProps (state) {
const { balances } = state.balances;
const { contacts, hasContacts } = state.personal;
return {
balances,
contacts,
hasContacts
};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({}, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Addresses);

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

View File

@@ -0,0 +1,45 @@
// 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 { FirstRun } from '../../../modals';
import { Errors, ParityBackground, Tooltips } from '../../../ui';
import styles from '../application.css';
export default class Container extends Component {
static propTypes = {
children: PropTypes.node.isRequired,
showFirstRun: PropTypes.bool,
onCloseFirstRun: PropTypes.func
};
render () {
const { children, showFirstRun, onCloseFirstRun } = this.props;
return (
<ParityBackground className={ styles.container }>
<FirstRun
visible={ showFirstRun }
onClose={ onCloseFirstRun } />
<Tooltips />
<Errors />
{ children }
</ParityBackground>
);
}
}

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

View File

@@ -0,0 +1,35 @@
// 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 '../application.css';
export default class DappContainer extends Component {
static propTypes = {
children: PropTypes.node.isRequired
};
render () {
const { children } = this.props;
return (
<div className={ styles.container }>
{ children }
</div>
);
}
}

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

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/>.
*/
.error {
padding: 2em;
background: red;
color: white;
}

View File

@@ -0,0 +1,29 @@
// 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 } from 'react';
import styles from './frameError.css';
export default class FrameError extends Component {
render () {
return (
<div className={ styles.error }>
ERROR: This application cannot and should not be loaded in an embedded iFrame
</div>
);
}
}

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

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

View File

@@ -0,0 +1,65 @@
/* 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/>.
*/
.status {
clear: both;
padding: 1.5em;
text-align: right;
color: #ddd;
}
.title {
margin: 0 0.5em 0 2em;
}
.block {
}
.netinfo {
display: flex;
flex-direction: row;
justify-content: flex-end;
margin-top: 0.25em;
}
.netinfo>div {
display: inline-block;
margin-left: 1em;
}
.network {
padding: 0.25em 0.5em;
display: inline-block;
border-radius: 4px;
text-transform: uppercase;
height: 1.25em;
margin-top: 0.25em;
box-sizing: content-box;
}
.networklive {
background: rgb(75, 255, 75);
}
.networktest {
background: rgb(255, 75, 75);
}
.peers {
}
.version {
}

View File

@@ -0,0 +1,82 @@
// 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 styles from './status.css';
class Status extends Component {
static propTypes = {
blockNumber: PropTypes.object,
clientVersion: PropTypes.string,
netPeers: PropTypes.object,
netChain: PropTypes.string,
isTest: PropTypes.bool
}
render () {
const { clientVersion, blockNumber, netChain, netPeers, isTest } = this.props;
const netStyle = `${styles.network} ${styles[isTest ? 'networktest' : 'networklive']}`;
if (!blockNumber) {
return null;
}
return (
<div className={ styles.status }>
<div className={ styles.version }>
{ clientVersion }
</div>
<div className={ styles.netinfo }>
<div>
<div className={ styles.block }>
{ blockNumber.toFormat() } blocks
</div>
<div className={ styles.peers }>
{ netPeers.active.toFormat() }/{ netPeers.connected.toFormat() }/{ netPeers.max.toFormat() } peers
</div>
</div>
<div className={ netStyle }>
{ isTest ? 'test' : netChain }
</div>
</div>
</div>
);
}
}
function mapStateToProps (state) {
const { blockNumber, clientVersion, netPeers, netChain, isTest } = state.nodeStatus;
return {
blockNumber,
clientVersion,
netPeers,
netChain,
isTest
};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({}, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Status);

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

View File

@@ -0,0 +1,84 @@
/* 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/>.
*/
.toolbar {
background: none !important;
height: 72px !important;
position: relative;
}
.tabs {
width: 100%;
position: relative;
}
.tabs button,
.settings,
.logo,
.last {
background: rgba(0, 0, 0, 0.5) !important; /* rgba(0, 0, 0, 0.25) !important; */
}
.tabs button:hover {
background: rgba(0, 0, 0, 0.4) !important;
}
button.tabactive,
button.tabactive:hover {
background: rgba(0, 0, 0, 0.25) !important;
border-radius: 4px 4px 0 0;
}
.tabbarTooltip {
left: 3.3em;
top: 0.5em;
}
.label {
position: relative;
}
.labelBubble {
position: absolute;
top: -12px;
right: -12px;
}
.logo {
margin: 0 0 0 -24px;
padding: 22px 24px 0 24px;
white-space: nowrap;
}
.logo img {
height: 28px;
width: 28px;
margin-right: 0.5em;
}
.logo div {
display: inline-block;
text-transform: uppercase;
line-height: 32px;
vertical-align: top;
letter-spacing: 0.2em;
}
.last {
margin: 0 -24px 0 0;
padding: 22px 12px 0 12px;
white-space: nowrap;
}

View File

@@ -0,0 +1,187 @@
// 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 { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
import { Tabs, Tab } from 'material-ui/Tabs';
import { Badge, Tooltip } from '../../../ui';
import styles from './tabBar.css';
import imagesEthcoreBlock from '../../../../assets/images/ethcore-block.png';
const TABMAP = {
accounts: 'account',
addresses: 'address',
apps: 'app',
contracts: 'contract'
};
class TabBar extends Component {
static contextTypes = {
router: PropTypes.object.isRequired
}
static propTypes = {
pending: PropTypes.array,
isTest: PropTypes.bool,
netChain: PropTypes.string,
settings: PropTypes.object.isRequired
}
state = {
activeRoute: '/accounts'
}
render () {
return (
<Toolbar
className={ styles.toolbar }>
{ this.renderLogo() }
{ this.renderTabs() }
{ this.renderLast() }
</Toolbar>
);
}
renderLogo () {
return (
<ToolbarGroup>
<div className={ styles.logo }>
<img src={ imagesEthcoreBlock } />
<div>Parity</div>
</div>
</ToolbarGroup>
);
}
renderLast () {
return (
<ToolbarGroup>
<div className={ styles.last }>
<div></div>
</div>
</ToolbarGroup>
);
}
renderTabs () {
const { settings } = this.props;
const windowHash = (window.location.hash || '').split('?')[0].split('/')[1];
const hash = TABMAP[windowHash] || windowHash;
const items = Object.keys(settings.views)
.filter((id) => settings.views[id].fixed || settings.views[id].active)
.map((id) => {
const view = settings.views[id];
let label = this.renderLabel(view.label);
let body = null;
if (id === 'accounts') {
body = (
<Tooltip className={ styles.tabbarTooltip } text='navigate between the different parts and views of the application, switching between an account view, token view and distributed application view' />
);
} else if (id === 'signer') {
label = this.renderSignerLabel(label);
} else if (id === 'status') {
label = this.renderStatusLabel(label);
}
return (
<Tab
className={ hash === view.value ? styles.tabactive : '' }
value={ view.value }
icon={ view.icon }
key={ id }
label={ label }
onActive={ this.onActivate(view.route) }>
{ body }
</Tab>
);
});
return (
<Tabs
className={ styles.tabs }
value={ hash }>
{ items }
</Tabs>
);
}
renderLabel = (name, bubble) => {
return (
<div className={ styles.label }>
{ name }
{ bubble }
</div>
);
}
renderSignerLabel = (label) => {
const { pending } = this.props;
let bubble = null;
if (pending && pending.length) {
bubble = (
<Badge
color='red'
className={ styles.labelBubble }
value={ pending.length } />
);
}
return this.renderLabel(label, bubble);
}
renderStatusLabel = (label) => {
const { isTest, netChain } = this.props;
const bubble = (
<Badge
color={ isTest ? 'red' : 'default' }
className={ styles.labelBubble }
value={ isTest ? 'TEST' : netChain } />
);
return this.renderLabel(label, bubble);
}
onActivate = (activeRoute) => {
const { router } = this.context;
return (event) => {
router.push(activeRoute);
this.setState({ activeRoute });
};
}
}
function mapStateToProps (state) {
const { settings } = state;
return { settings };
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({}, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(TabBar);

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/>.
*/
.outer,
.container {
min-height: 100vh;
}

View File

@@ -0,0 +1,146 @@
// 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 Connection from '../Connection';
import ParityBar from '../ParityBar';
import Container from './Container';
import DappContainer from './DappContainer';
import FrameError from './FrameError';
import Status from './Status';
import TabBar from './TabBar';
import styles from './application.css';
const inFrame = window.parent !== window && window.parent.frames.length !== 0;
const showFirstRun = window.localStorage.getItem('showFirstRun') === '1';
class Application extends Component {
static contextTypes = {
api: PropTypes.object.isRequired,
background: PropTypes.string
}
static propTypes = {
children: PropTypes.node,
netChain: PropTypes.string,
isTest: PropTypes.bool,
pending: PropTypes.array
}
state = {
showFirstRun: false
}
componentWillMount () {
this.checkAccounts();
}
render () {
const [root] = (window.location.hash || '').replace('#/', '').split('/');
const isDapp = root === 'app';
if (inFrame) {
return (
<FrameError />
);
}
return (
<div className={ styles.outer }>
{ isDapp ? this.renderDapp() : this.renderApp() }
<Connection />
<ParityBar dapp={ isDapp } />
</div>
);
}
renderApp () {
const { children, pending, netChain, isTest } = this.props;
const { showFirstRun } = this.state;
return (
<Container
showFirstRun={ showFirstRun }
onCloseFirstRun={ this.onCloseFirstRun }>
<TabBar
netChain={ netChain }
isTest={ isTest }
pending={ pending } />
{ children }
<Status />
</Container>
);
}
renderDapp () {
const { children } = this.props;
return (
<DappContainer>
{ children }
</DappContainer>
);
}
checkAccounts () {
const { api } = this.context;
api.personal
.listAccounts()
.then((accounts) => {
this.setState({
showFirstRun: showFirstRun || accounts.length === 0
});
})
.catch((error) => {
console.error('checkAccounts', error);
});
}
onCloseFirstRun = () => {
window.localStorage.setItem('showFirstRun', '0');
this.setState({
showFirstRun: false
});
}
}
function mapStateToProps (state) {
const { netChain, isTest } = state.nodeStatus;
const { hasAccounts } = state.personal;
const { pending } = state.signer;
return {
hasAccounts,
netChain,
isTest,
pending
};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({}, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Application);

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

View File

@@ -0,0 +1,113 @@
/* 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/>.
*/
.overlay {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(255, 255, 255, 0.75);
z-index: 20000
}
.modal {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 20001
}
.body {
margin: 0 auto;
padding: 2em 4em;
text-align: center;
max-width: 40em;
background: rgba(25, 25, 25, 0.75);
color: rgb(208, 208, 208);
box-shadow: rgba(0, 0, 0, 0.25) 0px 14px 45px, rgba(0, 0, 0, 0.22) 0px 10px 18px
}
.header {
fontSize: 1.25em
}
.info {
margin-top: 2em;
line-height: 1.618em
}
.form {
margin-top: 0.75em;
padding: 0 4em;
text-align: left;
}
.btnrow {
text-align: right;
padding: 0 4em;
}
.icons {
}
.icon,
.iconSmall {
display: inline-block;
padding: 1em;
vertical-align: middle;
}
.iconName {
}
.icon .svg {
width: 6em !important;
height: 6em !important;
}
.iconSmall .svg {
width: 3em !important;
height: 3em !important;
}
.console {
font-family: 'Roboto Mono';
background: rgba(0, 0, 0, 0.25);
padding: 0 0.25em;
}
@keyframes pulse {
0% {
fill: rgb(0, 200, 0);
}
50% {
fill: rgb(150, 200, 150);
}
100% {
fill: rgb(0, 200, 0);
}
}
.pulse {
fill: red;
animation-name: pulse;
animation-duration: 1.5s;
animation-iteration-count: infinite;
}

View File

@@ -0,0 +1,150 @@
// 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 ActionCompareArrows from 'material-ui/svg-icons/action/compare-arrows';
import ActionDashboard from 'material-ui/svg-icons/action/dashboard';
// import CommunicationVpnKey from 'material-ui/svg-icons/communication/vpn-key';
import HardwareDesktopMac from 'material-ui/svg-icons/hardware/desktop-mac';
import NotificationVpnLock from 'material-ui/svg-icons/notification/vpn-lock';
import { Input } from '../../ui';
import styles from './connection.css';
class Connection extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
}
static propTypes = {
isConnected: PropTypes.bool,
isConnecting: PropTypes.bool,
isPingable: PropTypes.bool,
needsToken: PropTypes.bool
}
state = {
token: '',
validToken: false
}
render () {
const { isConnected, isConnecting, isPingable } = this.props;
const isOk = !isConnecting && isConnected && isPingable;
if (isOk) {
return null;
}
const typeIcon = isPingable
? <NotificationVpnLock className={ styles.svg } />
: <ActionDashboard className={ styles.svg } />;
const description = isPingable
? this.renderSigner()
: this.renderPing();
return (
<div>
<div className={ styles.overlay } />
<div className={ styles.modal }>
<div className={ styles.body }>
<div className={ styles.icons }>
<div className={ styles.icon }>
<HardwareDesktopMac className={ styles.svg } />
</div>
<div className={ styles.iconSmall }>
<ActionCompareArrows className={ styles.svg + ' ' + styles.pulse } />
</div>
<div className={ styles.icon }>
{ typeIcon }
</div>
</div>
{ description }
</div>
</div>
</div>
);
}
renderSigner () {
const { api } = this.context;
const { token, validToken } = this.state;
const { needsToken, isConnecting } = api;
if (needsToken && !isConnecting) {
return (
<div className={ styles.info }>
<div>Unable to make a connection to the Parity Secure API. To update your secure token or to generate a new one, run <span className={ styles.console }>parity signer new-token</span> and supply the token below</div>
<div className={ styles.form }>
<Input
label='secure token'
hint='a generated token from Parity'
error={ validToken || (!token || !token.length) ? null : 'invalid signer token' }
value={ token }
onChange={ this.onChangeToken } />
</div>
</div>
);
}
return (
<div className={ styles.info }>
Connecting to the Parity Secure API.
</div>
);
}
renderPing () {
return (
<div className={ styles.info }>
Connecting to the Parity Node. If this informational message persists, please ensure that your Parity node is running and reachable on the network.
</div>
);
}
onChangeToken = (event, token) => {
const validToken = /[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}/.test(token);
this.setState({ token, validToken }, () => {
validToken && this.setToken();
});
}
setToken = () => {
const { api } = this.context;
const { token } = this.state;
api.updateToken(token);
this.setState({ token: '', validToken: false });
}
}
function mapStateToProps (state) {
const { isConnected, isConnecting, isPingable, needsToken } = state.nodeStatus;
return { isConnected, isConnecting, isPingable, needsToken };
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({}, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Connection);

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

View File

@@ -0,0 +1,132 @@
// 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 BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react';
import { Container, ContainerTitle } from '../../../ui';
import styles from '../contract.css';
export default class Events extends Component {
static contextTypes = {
api: PropTypes.object
}
static propTypes = {
events: PropTypes.array,
isTest: PropTypes.bool
}
state = {
transactions: {}
}
componentDidMount () {
this.componentWillReceiveProps(this.props);
}
componentWillReceiveProps (newProps) {
this.retrieveTransactions(newProps.events);
}
render () {
const { events, isTest } = this.props;
const { transactions } = this.state;
if (!events || !events.length) {
return null;
}
const rows = events.map((event) => {
const transaction = transactions[event.transactionHash] || {};
const classes = `${styles.event} ${styles[event.state]}`;
const url = `https://${isTest ? 'testnet.' : ''}etherscan.io/tx/${event.transactionHash}`;
const keys = Object.keys(event.params).map((key, index) => {
return <div className={ styles.key } key={ `${event.key}_key_${index}` }>{ key }</div>;
});
const values = Object.values(event.params).map((value, index) => {
return (
<div className={ styles.value } key={ `${event.key}_val_${index}` }>
{ this.renderValue(value) }
</div>
);
});
return (
<tr className={ classes } key={ event.key }>
<td>{ event.state === 'pending' ? 'pending' : event.blockNumber.toFormat(0) }</td>
<td className={ styles.txhash }>
<div>{ transaction.from }</div>
<a href={ url } target='_blank'>{ event.transactionHash }</a>
</td>
<td>
<div>{ event.type } =></div>
{ keys }
</td>
<td>
<div>&nbsp;</div>
{ values }
</td>
</tr>
);
});
return (
<Container>
<ContainerTitle title='events' />
<table className={ styles.events }>
<tbody>{ rows }</tbody>
</table>
</Container>
);
}
renderValue (value) {
const { api } = this.context;
if (api.util.isInstanceOf(value, BigNumber)) {
return value.toFormat(0);
} else if (api.util.isArray(value)) {
return api.util.bytesToHex(value);
}
return value.toString();
}
retrieveTransactions (events) {
const { api } = this.context;
const { transactions } = this.state;
const hashes = {};
events.forEach((event) => {
if (!hashes[event.transactionHash] && !transactions[event.transactionHash]) {
hashes[event.transactionHash] = true;
}
});
Promise
.all(Object.keys(hashes).map((hash) => api.eth.getTransactionByHash(hash)))
.then((newTransactions) => {
this.setState({
transactions: newTransactions.reduce((store, transaction) => {
transactions[transaction.hash] = transaction;
return transactions;
}, transactions)
});
});
}
}

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

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

View File

@@ -0,0 +1,186 @@
// 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 BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react';
import Chip from 'material-ui/Chip';
import LinearProgress from 'material-ui/LinearProgress';
import { Card, CardActions, CardTitle, CardText } from 'material-ui/Card';
import { Button, Input } from '../../../ui';
import styles from './queries.css';
export default class InputQuery extends Component {
static contextTypes = {
api: PropTypes.object
}
static propTypes = {
contract: PropTypes.object.isRequired,
inputs: PropTypes.array.isRequired,
outputs: PropTypes.array.isRequired,
name: PropTypes.string.isRequired,
className: PropTypes.string
}
state = {
isValid: true,
results: [],
values: {}
}
render () {
const { name, className } = this.props;
return (
<Card
className={ className }
>
<CardTitle
className={ styles.methodTitle }
title={ name }
/>
{ this.renderContent() }
</Card>
);
}
renderContent () {
const { inputs } = this.props;
const { isValid } = this.state;
const inputsFields = inputs
.map(input => this.renderInput(input));
return (
<div>
<CardText
className={ styles.methodContent }
>
<div className={ styles.methodResults }>
{ this.renderResults() }
</div>
{ inputsFields }
</CardText>
<CardActions>
<Button
label='Execute'
disabled={ !isValid }
onClick={ this.onClick } />
</CardActions>
</div>
);
}
renderResults () {
const { results, isLoading } = this.state;
const { outputs } = this.props;
if (isLoading) {
return (<LinearProgress mode='indeterminate' />);
}
if (!results || results.length < 1) return null;
return outputs
.map((out, index) => ({
name: out.name,
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>
<Chip className={ styles.queryValue }>
{ out.display }
</Chip>
<br />
</div>));
}
renderInput (input) {
const { name, type } = input;
const label = `${name}: ${type}`;
const onChange = (event) => {
const value = event.target.value;
const { values } = this.state;
this.setState({
values: {
...values,
[ name ]: value
}
});
};
return (
<div key={ name }>
<Input
hint={ type }
label={ label }
required
onChange={ onChange }
/>
</div>
);
}
renderValue (value) {
if (!value) return 'no data';
const { api } = this.context;
if (api.util.isInstanceOf(value, BigNumber)) {
return value.toFormat(0);
} else if (api.util.isArray(value)) {
return api.util.bytesToHex(value);
}
return value.toString();
}
onClick = () => {
const { values } = this.state;
const { inputs, contract, name, outputs } = this.props;
this.setState({
isLoading: true,
results: []
});
const inputValues = inputs.map(input => values[input.name]);
contract
.instance[name]
.call({}, inputValues)
.then(results => {
if (outputs.length === 1) {
results = [ results ];
}
this.setState({
isLoading: false,
results
});
})
.catch(e => {
console.error(`sending ${name} with params`, inputValues, e);
});
};
}

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/>.
*/
.vMethods, .hMethods, .methods {
display: flex;
flex-wrap: wrap;
}
.container {
align-items: flex-start;
display: border-box;
}
.container .method {
background-color: rgba(255, 255, 255, 0.05) !important;
margin: 0.5em;
}
.vMethods {
flex-direction: column;
width: 33.3333%;
}
.hMethods {
flex: 1;
flex-direction: row;
width: 66.6666%;
}
.hMethods .container {
width: 50%;
}
.methodTitle {
padding-bottom: 8px !important;
padding-top: 8px !important;
}
.methodContent {
padding-top: 0 !important;
padding-bottom: 8px !important;
}
.methodResults {
display: flex;
flex-wrap: wrap;
max-width: 24rem;
justify-content: space-around;
}
.methodResults > div {
margin: 0.5rem;
display: flex;
flex-direction: column;
align-items: center;
max-width: 100%;
}
.queryValue, .queryValue * {
user-select: text !important;
max-width: 100%;
box-sizing: border-box;
white-space: normal !important;
overflow-wrap: break-word !important;
}
.queryValue:hover {
cursor: text !important;
}
.queryResultName {
margin-bottom: 0.25rem;
}

View File

@@ -0,0 +1,132 @@
// 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 BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react';
import Chip from 'material-ui/Chip';
import { Card, CardTitle, CardText } from 'material-ui/Card';
import InputQuery from './inputQuery';
import { Container, ContainerTitle } from '../../../ui';
import styles from './queries.css';
export default class Queries extends Component {
static contextTypes = {
api: PropTypes.object
}
static propTypes = {
contract: PropTypes.object,
values: PropTypes.object
}
render () {
const { contract } = this.props;
if (!contract) {
return null;
}
const queries = contract.functions
.filter((fn) => fn.constant)
.sort(this._sortEntries);
const noInputQueries = queries
.slice()
.filter((fn) => fn.inputs.length === 0)
.map((fn) => this.renderQuery(fn));
const withInputQueries = queries
.slice()
.filter((fn) => fn.inputs.length > 0)
.map((fn) => this.renderInputQuery(fn));
return (
<Container>
<ContainerTitle title='queries' />
<div className={ styles.methods }>
<div className={ styles.vMethods }>
{ noInputQueries }
</div>
<div className={ styles.hMethods }>
{ withInputQueries }
</div>
</div>
</Container>
);
}
renderInputQuery (fn) {
const { abi, name } = fn;
const { contract } = this.props;
return (
<div className={ styles.container } key={ fn.signature }>
<InputQuery
className={ styles.method }
inputs={ abi.inputs }
outputs={ abi.outputs }
name={ name }
contract={ contract }
/>
</div>
);
}
renderQuery (fn) {
const { values } = this.props;
return (
<div className={ styles.container } key={ fn.signature }>
<Card className={ styles.method }>
<CardTitle
className={ styles.methodTitle }
title={ fn.name }
/>
<CardText
className={ styles.methodContent }
>
{ this.renderValue(values[fn.name]) }
</CardText>
</Card>
</div>
);
}
renderValue (value) {
if (!value) return null;
const { api } = this.context;
let valueToDisplay = value.toString();
if (api.util.isInstanceOf(value, BigNumber)) {
valueToDisplay = value.toFormat(0);
} else if (api.util.isArray(value)) {
valueToDisplay = api.util.bytesToHex(value);
}
return (
<Chip className={ styles.queryValue }>
{ valueToDisplay }
</Chip>
);
}
_sortEntries (a, b) {
return a.name.localeCompare(b.name);
}
}

View File

@@ -0,0 +1,58 @@
/* 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/>.
*/
.contract {
}
.events {
width: 100%;
border: none;
border-spacing: 0;
}
.event {
vertical-align: top;
line-height: 26px;
}
.event td {
vertical-align: top;
padding: 1em 0.5em;
}
.txhash {
text-overflow: ellipsis;
}
.key {
text-align: right;
color: #aaa;
}
.value {
}
.event td div {
white-space: nowrap;
}
.mined {
}
.pending {
opacity: 0.5;
}

View File

@@ -0,0 +1,365 @@
// 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 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';
import { newError } from '../../redux/actions';
import { EditMeta, ExecuteContract } from '../../modals';
import { Actionbar, Button, Page } from '../../ui';
import Header from '../Account/Header';
import Delete from '../Address/Delete';
import Events from './Events';
import Queries from './Queries';
import styles from './contract.css';
class Contract extends Component {
static contextTypes = {
api: React.PropTypes.object.isRequired
}
static propTypes = {
accounts: PropTypes.object,
balances: PropTypes.object,
contracts: PropTypes.object,
isTest: PropTypes.bool,
params: PropTypes.object
}
state = {
contract: null,
fromAddress: '',
showDeleteDialog: false,
showEditDialog: false,
showExecuteDialog: false,
subscriptionId: -1,
blockSubscriptionId: -1,
allEvents: [],
minedEvents: [],
pendingEvents: [],
queryValues: {}
}
componentDidMount () {
const { api } = this.context;
this.attachContract(this.props);
this.setBaseAccount(this.props);
api
.subscribe('eth_blockNumber', this.queryContract)
.then(blockSubscriptionId => this.setState({ blockSubscriptionId }));
}
componentWillReceiveProps (newProps) {
const { accounts, contracts } = newProps;
if (Object.keys(contracts).length !== Object.keys(this.props.contracts).length) {
this.attachContract(newProps);
}
if (Object.keys(accounts).length !== Object.keys(this.props.accounts).length) {
this.setBaseAccount(newProps);
}
}
componentWillUnmount () {
const { api } = this.context;
const { subscriptionId, blockSubscriptionId, contract } = this.state;
api.unsubscribe('eth_blockNumber', blockSubscriptionId);
contract.unsubscribe(subscriptionId);
}
render () {
const { balances, contracts, params, isTest } = this.props;
const { allEvents, contract, queryValues } = this.state;
const account = contracts[params.address];
const balance = balances[params.address];
if (!account) {
return null;
}
return (
<div className={ styles.contract }>
{ this.renderActionbar(account) }
{ this.renderDeleteDialog(account) }
{ this.renderEditDialog(account) }
{ this.renderExecuteDialog() }
<Page>
<Header
isTest={ isTest }
account={ account }
balance={ balance } />
<Queries
contract={ contract }
values={ queryValues } />
<Events
isTest={ isTest }
events={ allEvents } />
</Page>
</div>
);
}
renderActionbar (account) {
const buttons = [
<Button
key='execute'
icon={ <AvPlayArrow /> }
label='execute'
onClick={ this.showExecuteDialog } />,
<Button
key='editmeta'
icon={ <ContentCreate /> }
label='edit'
onClick={ this.onEditClick } />,
<Button
key='delete'
icon={ <ActionDelete /> }
label='delete contract'
onClick={ this.showDeleteDialog } />
];
return (
<Actionbar
title='Contract Information'
buttons={ !account || account.meta.deleted ? [] : buttons } />
);
}
renderDeleteDialog (account) {
const { showDeleteDialog } = this.state;
return (
<Delete
account={ account }
visible={ showDeleteDialog }
route='/contracts'
onClose={ this.closeDeleteDialog } />
);
}
renderEditDialog (account) {
const { showEditDialog } = this.state;
if (!showEditDialog) {
return null;
}
return (
<EditMeta
account={ account }
keys={ ['description'] }
onClose={ this.onEditClick } />
);
}
renderExecuteDialog () {
const { contract, fromAddress, showExecuteDialog } = this.state;
const { accounts } = this.props;
if (!showExecuteDialog) {
return null;
}
return (
<ExecuteContract
accounts={ accounts }
contract={ contract }
fromAddress={ fromAddress }
onClose={ this.closeExecuteDialog }
onFromAddressChange={ this.onFromAddressChange } />
);
}
queryContract = () => {
const { contract } = this.state;
if (!contract) {
return;
}
const queries = contract.functions
.filter((fn) => fn.constant)
.filter((fn) => !fn.inputs.length);
Promise
.all(queries.map((query) => query.call()))
.then(results => {
const values = queries.reduce((object, fn, idx) => {
const key = fn.name;
object[key] = results[idx];
return object;
}, {});
this.setState({ queryValues: values });
})
.catch((error) => {
console.error('queryContract', error);
});
}
onEditClick = () => {
this.setState({
showEditDialog: !this.state.showEditDialog
});
}
closeDeleteDialog = () => {
this.setState({ showDeleteDialog: false });
}
showDeleteDialog = () => {
this.setState({ showDeleteDialog: true });
}
closeExecuteDialog = () => {
this.setState({ showExecuteDialog: false });
}
showExecuteDialog = () => {
this.setState({ showExecuteDialog: true });
}
_sortEvents = (a, b) => {
return b.blockNumber.cmp(a.blockNumber) || b.logIndex.cmp(a.logIndex);
}
_logToEvent = (log) => {
const { api } = this.context;
const key = api.util.sha3(JSON.stringify(log));
const { address, blockNumber, logIndex, transactionHash, transactionIndex, params, type } = log;
return {
type: log.event,
state: type,
address,
blockNumber,
logIndex,
transactionHash,
transactionIndex,
params,
key
};
}
_receiveEvents = (error, logs) => {
if (error) {
console.error('_receiveEvents', error);
return;
}
const events = logs.map(this._logToEvent);
const minedEvents = events
.filter((event) => event.state === 'mined')
.reverse()
.concat(this.state.minedEvents)
.sort(this._sortEvents);
const pendingEvents = events
.filter((event) => event.state === 'pending')
.reverse()
.concat(this.state.pendingEvents.filter((pending) => {
return !events.find((event) => {
const isMined = (event.state === 'mined') && (event.transactionHash === pending.transactionHash);
const isPending = (event.state === 'pending') && (event.key === pending.key);
return isMined || isPending;
});
}))
.sort(this._sortEvents);
const allEvents = pendingEvents.concat(minedEvents);
this.setState({
allEvents,
minedEvents,
pendingEvents
});
}
attachContract (props) {
if (!props) {
return;
}
const { api } = this.context;
const { contracts, params } = props;
const account = contracts[params.address];
if (!account) {
return;
}
const contract = api.newContract(account.meta.abi, params.address);
contract
.subscribe(null, { limit: 50, fromBlock: 0, toBlock: 'pending' }, this._receiveEvents)
.then((subscriptionId) => {
this.setState({ subscriptionId });
});
this.setState({ contract }, this.queryContract);
}
setBaseAccount (props) {
const { fromAccount } = this.state;
if (!props || fromAccount) {
return;
}
const { accounts } = props;
this.setState({
fromAddress: Object.keys(accounts)[0]
});
}
onFromAddressChange = (event, fromAddress) => {
this.setState({
fromAddress
});
}
}
function mapStateToProps (state) {
const { accounts, contracts } = state.personal;
const { balances } = state.balances;
const { isTest } = state.nodeStatus;
return {
isTest,
accounts,
contracts,
balances
};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({ newError }, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Contract);

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

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

View File

@@ -0,0 +1,52 @@
// 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 { 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>
);
}
}

View File

@@ -0,0 +1,18 @@
/* 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/>.
*/
.contracts {
}

View File

@@ -0,0 +1,154 @@
// 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 ContentAdd from 'material-ui/svg-icons/content/add';
import { Actionbar, Button, Page } from '../../ui';
import { AddContract, DeployContract } from '../../modals';
import List from '../Accounts/List';
import styles from './contracts.css';
class Contracts extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
}
static propTypes = {
balances: PropTypes.object,
accounts: PropTypes.object,
contracts: PropTypes.object,
hasContracts: PropTypes.bool
}
state = {
addContract: false,
deployContract: false
}
render () {
const { contracts, hasContracts, balances } = this.props;
return (
<div className={ styles.contracts }>
{ this.renderActionbar() }
{ this.renderAddContract() }
{ this.renderAddContract() }
{ this.renderDeployContract() }
<Page>
<List
link='contract'
accounts={ contracts }
balances={ balances }
empty={ !hasContracts } />
</Page>
</div>
);
}
renderActionbar () {
const buttons = [
<Button
key='addContract'
icon={ <ContentAdd /> }
label='watch contract'
onClick={ this.onAddContract } />,
<Button
key='deployContract'
icon={ <ContentAdd /> }
label='deploy contract'
onClick={ this.onDeployContract } />
];
return (
<Actionbar
className={ styles.toolbar }
title='Contracts'
buttons={ buttons } />
);
}
renderAddContract () {
const { contracts } = this.props;
const { addContract } = this.state;
if (!addContract) {
return null;
}
return (
<AddContract
contracts={ contracts }
onClose={ this.onAddContractClose } />
);
}
renderDeployContract () {
const { accounts } = this.props;
const { deployContract } = this.state;
if (!deployContract) {
return null;
}
return (
<DeployContract
accounts={ accounts }
onClose={ this.onDeployContractClose } />
);
}
onDeployContractClose = () => {
this.setState({ deployContract: false });
}
onDeployContract = () => {
this.setState({ deployContract: true });
}
onAddContractClose = () => {
this.setState({ addContract: false });
}
onAddContract = () => {
this.setState({ addContract: true });
}
}
function mapStateToProps (state) {
const { accounts, contracts, hasContracts } = state.personal;
const { balances } = state.balances;
return {
accounts,
contracts,
hasContracts,
balances
};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({}, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Contracts);

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

View File

@@ -0,0 +1,22 @@
/* 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/>.
*/
.frame {
border: 0;
position: absolute;
height: 100%;
width: 100%;
}

48
js/src/views/Dapp/dapp.js Normal file
View File

@@ -0,0 +1,48 @@
// 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 './dapp.css';
const hostname = `${window.location.hostname}:${window.location.port}`;
const dapphost = (hostname === 'localhost:3000') || (hostname === '127.0.0.1:3000')
? hostname
: '127.0.0.1:8080/ui';
export default class Dapp extends Component {
static propTypes = {
params: PropTypes.object
};
render () {
const { name, type } = this.props.params;
const src = type === 'global'
? `http://${dapphost}/${name}.html`
: `http://127.0.0.1:8080/${name}/`;
return (
<iframe
className={ styles.frame }
frameBorder={ 0 }
name={ name }
sandbox='allow-scripts'
scrolling='auto'
src={ src }>
</iframe>
);
}
}

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

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

View File

@@ -0,0 +1,43 @@
/* 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/>.
*/
.container {
position: relative;
}
.image {
position: absolute;
top: 1.5em;
left: 1.5em;
border-radius: 50%;
width: 56px;
height: 56px;
}
.description {
margin-left: 72px;
}
.title {
mragin-bottom: 0.5em;
}
.author, .version {
font-size: 0.75em;
opacity: 0.5;
margin-top: 0.5em;
}

View File

@@ -0,0 +1,60 @@
// 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 { Link } from 'react-router';
import { Container, ContainerTitle } from '../../../ui';
import styles from './summary.css';
export default class Summary extends Component {
static contextTypes = {
api: React.PropTypes.object
}
static propTypes = {
app: PropTypes.object.isRequired,
children: PropTypes.node
}
render () {
const { app } = this.props;
if (!app) {
return null;
}
const url = `/app/${app.local ? 'local' : 'global'}/${app.url}`;
const image = app.image
? <img src={ app.image } className={ styles.image } />
: <div className={ styles.image }>&nbsp;</div>;
return (
<Container className={ styles.container }>
{ image }
<div className={ styles.description }>
<ContainerTitle
className={ styles.title }
title={ <Link to={ url }>{ app.name }</Link> }
byline={ app.description } />
<div className={ styles.author }>{ app.author }, v{ app.version }</div>
{ this.props.children }
</div>
</Container>
);
}
}

View File

@@ -0,0 +1,40 @@
/* 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/>.
*/
.list {
display: flex;
flex-wrap: wrap;
}
.list+.list {
margin-top: -0.25em;
}
.item {
flex: 0 1 50%;
width: 50%;
position: relative;
box-sizing: border-box;
padding-bottom: 0.25em;
}
.item:nth-child(odd) {
padding-right: 0.125em;
}
.item:nth-child(even) {
padding-left: 0.125em;
}

168
js/src/views/Dapps/dapps.js Normal file
View File

@@ -0,0 +1,168 @@
// 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 { sha3 } from '../../api/util/sha3';
import Contracts from '../../contracts';
import { hashToImageUrl } from '../../redux/util';
import { Actionbar, Page } from '../../ui';
import Summary from './Summary';
import styles from './dapps.css';
const APPS = [
{
name: 'Token Deployment',
description: 'Deploy new basic tokens that you are able to send around',
author: 'Ethcore <admin@ethcore.io>',
url: 'basiccoin',
version: '1.0.0'
},
{
name: 'GAVcoin',
description: 'Manage your GAVcoins, the hottest new property in crypto',
author: 'Ethcore <admin@ethcore.io>',
url: 'gavcoin',
version: '1.0.0'
},
{
name: 'Registry',
description: 'A global registry of addresses on the network',
author: 'Ethcore <admin@ethcore.io>',
url: 'registry',
version: '1.0.0'
},
{
name: 'Token Registry',
description: 'A registry of transactable tokens on the network',
author: 'Ethcore <admin@ethcore.io>',
url: 'tokenreg',
version: '1.0.0'
},
{
name: 'Method Registry',
description: 'A registry of method signatures for lookups on transactions',
author: 'Ethcore <admin@ethcore.io>',
url: 'signaturereg',
version: '1.0.0'
},
{
name: 'GitHub Hint',
description: 'A mapping of GitHub URLs to hashes for use in contracts as references',
author: 'Ethcore <admin@ethcore.io>',
url: 'githubhint',
version: '1.0.0'
}
];
APPS.forEach((app) => {
app.id = sha3(app.url);
console.log(`dapps ${app.id} -> ${app.url}`);
});
export default class Dapps extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
}
state = {
globalApps: APPS,
localApps: []
}
componentDidMount () {
this.loadLocalApps();
this.loadImages();
}
render () {
return (
<div>
<Actionbar
title='Decentralized Applications' />
<Page>
<div className={ styles.list }>
{ this.renderGlobalApps() }
</div>
<div className={ styles.list }>
{ this.renderLocalApps() }
</div>
</Page>
</div>
);
}
renderApp = (app) => {
return (
<div
className={ styles.item }
key={ app.url }>
<Summary app={ app } />
</div>
);
}
renderGlobalApps () {
const { globalApps } = this.state;
return globalApps.map(this.renderApp);
}
renderLocalApps () {
const { localApps } = this.state;
return localApps.map(this.renderApp);
}
loadLocalApps () {
fetch('http://127.0.0.1:8080/api/apps', { method: 'GET' })
.then((response) => response.ok ? response.json() : [])
.then((_localApps) => {
const localApps = _localApps
.filter((app) => !['home', 'status', 'parity', 'wallet'].includes(app.id))
.map((app) => {
app.image = `/app/${app.id}/${app.iconUrl}`;
app.url = app.id;
app.local = true;
return app;
});
console.log('loadLocalApps', localApps);
this.setState({ localApps });
})
.catch((error) => {
console.error('loadLocalApps', error);
});
}
loadImages () {
const { globalApps } = this.state;
const { dappReg } = Contracts.get();
Promise
.all(globalApps.map((app) => dappReg.getImage(app.id)))
.then((images) => {
globalApps.forEach((app, index) => {
app.image = hashToImageUrl(images[index]);
});
this.setState({ globalApps });
})
.catch((error) => {
console.error('loadImages', error);
});
}
}

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

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

View File

@@ -0,0 +1,153 @@
/* 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/>.
*/
.bar, .expanded {
position: fixed;
bottom: 0;
right: 0;
font-size: 16px;
font-family: 'Roboto', sans-serif;
z-index: 10001;
}
.overlay {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(255, 255, 255, 0.5);
z-index: 10000;
}
.bar {
vertical-align: middle;
display: flex;
flex-wrap: wrap;
width: 100%;
}
.expanded {
right: 16px;
width: 964px;
height: 288px;
border-radius: 4px 4px 0 0;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.expanded .content {
flex: 1;
overflow: auto;
}
.corner {
position: absolute;
bottom: 0;
right: 16px;
border-radius: 4px 4px 0 0;
}
.cornercolor {
background: rgba(0, 0, 0, 0.5);
padding: 0.5em 1em;
}
.link {
white-space: nowrap;
border: none;
outline: none !important;
color: white !important;
display: inline-block;
}
.link img, .link svg {
height: 24px !important;
width: 24px !important;
margin: 2px 0.5em 0 0;
}
.link+.link {
margin-left: 1em;
}
.button {
overflow: visible !important;
}
.label {
position: relative;
display: inline-block;
vertical-align: top;
}
.labelText {
text-transform: uppercase;
vertical-align: top;
}
.labelBubble {
position: absolute;
top: 0px;
right: -10px;
}
.header {
height: 36px;
padding: 0.5em 1em;
background: rgba(0, 0, 0, 0.25);
margin-bottom: 0;
}
.header:after {
clear: both;
}
.header button,
.corner button {
color: white !important;
}
.header svg ,
.coner svg {
fill: white !important;
}
.body {
padding: 1em;
}
.title {
float: left;
}
.actions {
float: right;
}
.actions div {
margin-left: 1em;
display: inline-block;
cursor: pointer;
}
.parityIcon, .signerIcon {
width: 24px;
height: 24px;
vertical-align: middle;
margin-left: 12px;
}

View File

@@ -0,0 +1,170 @@
// 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 { Link } from 'react-router';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import ContentClear from 'material-ui/svg-icons/content/clear';
import { Badge, Button, ContainerTitle, ParityBackground, SignerIcon } from '../../ui';
import { Embedded as Signer } from '../Signer';
import imagesEthcoreBlock from '../../../assets/images/ethcore-block.png';
import styles from './parityBar.css';
class ParityBar extends Component {
static propTypes = {
pending: PropTypes.array,
dapp: PropTypes.bool
}
state = {
opened: false
}
componentWillReceiveProps (nextProps) {
const count = this.props.pending.length;
const newCount = nextProps.pending.length;
if (count === newCount) {
return;
}
if (count < newCount) {
this.setState({ opened: true });
} else if (newCount === 0 && count === 1) {
this.setState({ opened: false });
}
}
render () {
const { opened } = this.state;
return opened
? this.renderExpanded()
: this.renderBar();
}
renderBar () {
const { dapp } = this.props;
if (!dapp) {
return null;
}
const parityIcon = (
<img
src={ imagesEthcoreBlock }
className={ styles.parityIcon } />
);
return (
<div className={ styles.bar }>
<ParityBackground className={ styles.corner }>
<div className={ styles.cornercolor }>
<Link to='/apps'>
<Button
className={ styles.button }
icon={ parityIcon }
label={ this.renderLabel('Parity') } />
</Link>
<Button
className={ styles.button }
icon={ <SignerIcon className={ styles.signerIcon } /> }
label={ this.renderSignerLabel() }
onClick={ this.toggleDisplay } />
</div>
</ParityBackground>
</div>
);
}
renderExpanded () {
return (
<div className={ styles.overlay }>
<ParityBackground className={ styles.expanded }>
<div className={ styles.header }>
<div className={ styles.title }>
<ContainerTitle title='Parity Signer: Pending' />
</div>
<div className={ styles.actions }>
<Button
icon={ <ContentClear /> }
label='Close'
onClick={ this.toggleDisplay } />
</div>
</div>
<div className={ styles.content }>
<Signer />
</div>
</ParityBackground>
</div>
);
}
renderLabel (name, bubble) {
return (
<div className={ styles.label }>
<div className={ styles.labelText }>
{ name }
</div>
{ bubble }
</div>
);
}
renderSignerLabel () {
const { pending } = this.props;
let bubble = null;
if (pending && pending.length) {
bubble = (
<Badge
color='red'
className={ styles.labelBubble }
value={ pending.length } />
);
}
return this.renderLabel('Signer', bubble);
}
toggleDisplay = () => {
const { opened } = this.state;
this.setState({
opened: !opened
});
}
}
function mapStateToProps (state) {
const { pending } = state.signer;
return {
pending
};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({}, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(ParityBar);

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/>.
*/
.bgcontainer {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.bgflex {
flex-basis: 25%;
box-sizing: border-box;
display: inline-block;
padding: 0 0.5em 1em 0.5em;
}
.bgseed {
background: black;
border-radius: 4px;
}
.seed,
.seedactive {
height: 10em;
border-radius: 4px;
cursor: pointer;
border: 2px solid rgba(255, 255, 255, 1);
}
.seed {
opacity: 0.5;
}

View File

@@ -0,0 +1,142 @@
// 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 NavigationRefresh from 'material-ui/svg-icons/navigation/refresh';
import { Button, Container, ContainerTitle, ParityBackground } from '../../../ui';
import { updateBackground } from '../actions';
import layout from '../layout.css';
import styles from './background.css';
let counter = 0;
class Background extends Component {
static contextTypes = {
api: PropTypes.object.isRequired,
muiTheme: PropTypes.object.isRequired
}
static propTypes = {
settings: PropTypes.object.isRequired,
updateBackground: PropTypes.func.isRequired
}
state = {
seeds: []
}
componentDidMount () {
const { settings } = this.props;
this.setState({
seeds: [settings.backgroundSeed]
}, () => this.addSeeds(19));
}
render () {
return (
<Container>
<ContainerTitle title='Background Pattern' />
<div className={ layout.layout }>
<div className={ layout.overview }>
<p><strong>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.</strong> This is so that decentralized applications cannot pretend to be trustworthy.</p>
<p>Pick a pattern you like and memorize it. This Pattern will always be shown from now on, unless you clear your browser's cache or use a new Signer token.</p>
</div>
<div className={ layout.details }>
<div className={ styles.bgcontainer }>
{ this.renderBackgrounds() }
</div>
<Button
icon={ <NavigationRefresh /> }
label='generate more'
onClick={ this.generateMore } />
</div>
</div>
</Container>
);
}
renderBackgrounds () {
const { settings } = this.props;
const { seeds } = this.state;
return seeds.map((seed) => {
return (
<div className={ styles.bgflex } key={ seed }>
<div className={ styles.bgseed }>
<ParityBackground
className={ settings.backgroundSeed === seed ? styles.seedactive : styles.seed }
seed={ seed }
onClick={ this.onSelect(seed) } />
</div>
</div>
);
});
}
onSelect = (seed) => {
const { muiTheme } = this.context;
const { updateBackground } = this.props;
return (event) => {
muiTheme.parity.setBackgroundSeed(seed);
updateBackground(seed);
};
}
generateMore = () => {
this.addSeeds(20);
}
addSeeds (count) {
const { seeds } = this.state;
const newSeeds = [];
for (let index = 0; index < count; index++) {
newSeeds.push(this.generateSeed());
}
this.setState({
seeds: seeds.concat(newSeeds)
});
}
generateSeed () {
const { api, muiTheme } = this.context;
return api.util.sha3(`${muiTheme.backgroundSeed}${Math.random()}${counter++}`);
}
}
function mapStateToProps (state) {
const { settings } = state;
return { settings };
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({ updateBackground }, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Background);

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

View File

@@ -0,0 +1,97 @@
// 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 from 'react';
import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet';
import ActionTrackChanges from 'material-ui/svg-icons/action/track-changes';
import ActionSettings from 'material-ui/svg-icons/action/settings';
import CommunicationContacts from 'material-ui/svg-icons/communication/contacts';
import ImageGridOn from 'material-ui/svg-icons/image/grid-on';
import NavigationApps from 'material-ui/svg-icons/navigation/apps';
import { SignerIcon } from '../../../ui';
import styles from './views.css';
const defaultViews = {
accounts: {
active: true,
fixed: true,
icon: <ActionAccountBalanceWallet />,
label: 'Accounts',
route: '/accounts',
value: 'account',
description: 'A list of all the accounts associated to and imported into this Parity instance. Send transactions, receive incoming values, manage your balances and fund your accounts.'
},
addresses: {
active: true,
icon: <CommunicationContacts />,
label: 'Addressbook',
route: '/addresses',
value: 'address',
description: 'A list of all contacts and address book entries that is managed by this Parity instance. Watch accounts and have the details available at the click of a button when transacting.'
},
apps: {
active: true,
icon: <NavigationApps />,
label: 'Applications',
route: '/apps',
value: 'app',
description: 'Distributed applications that interact with the underlying network. Add applications, manage you application portfolio and interact with application from around the newtork.'
},
contracts: {
active: false,
icon: <ImageGridOn />,
label: 'Contracts',
route: '/contracts',
value: 'contract',
description: 'Watch and interact with specific contracts that have been deployed on the network. This is a more technically-focussed environment, specifically for advanced users that understand the inner working of certain contracts.'
},
status: {
active: false,
icon: <ActionTrackChanges />,
label: 'Status',
route: '/status',
value: 'status',
description: 'See how the Parity node is performing in terms of connections to the network, logs from the actual running instance and details of mining (if enabled and configured).'
},
signer: {
active: true,
fixed: true,
icon: <SignerIcon className={ styles.signerIcon } />,
label: 'Signer',
route: '/signer',
value: 'signer',
description: 'The security focussed area of the application where you can approve any outgoing transactions made from the application as well as those placed into the queue by distributed applications.'
},
settings: {
active: true,
fixed: true,
icon: <ActionSettings />,
label: 'Settings',
route: '/settings',
value: 'settings',
description: 'This view. Allows you to customize the application in term of options, operation and look and feel.'
}
};
export default defaultViews;

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/>.
import defaultViews from './defaults';
export default from './views';
export {
defaultViews
};

View File

@@ -0,0 +1,49 @@
/* 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/>.
*/
.signerIcon {
width: 24px;
height: 24px;
margin-bottom: 5px;
}
.view {
}
.view+.view {
padding-top: 1.5em;
}
.header {
}
.labelicon {
display: inline-block;
margin-right: 0.75em;
}
.label {
display: inline-block;
vertical-align: top;
line-height: 24px;
color: white !important;
}
.info {
color: #aaa;
padding-left: 4.75em;
}

View File

@@ -0,0 +1,101 @@
// 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 { Checkbox } from 'material-ui';
import { Container, ContainerTitle } from '../../../ui';
import { toggleView } from '../actions';
import layout from '../layout.css';
import styles from './views.css';
class Views extends Component {
static propTypes = {
settings: PropTypes.object.isRequired,
toggleView: PropTypes.func.isRequired
}
render () {
return (
<Container>
<ContainerTitle 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>
<div>Are you an end-user? The defaults are setups for both beginner and advanced users alike.</div>
<div>Are you a developer? Add some features to manage contracts are interact with application develoyments.</div>
<div>Are you a miner or run a large-scale node? Add the features to give you all the information needed to watch the node operation.</div>
</div>
<div className={ layout.details }>
{ this.renderViews() }
</div>
</div>
</Container>
);
}
renderViews () {
const { settings, toggleView } = this.props;
return Object.keys(settings.views).map((id) => {
const toggle = () => toggleView(id);
const view = settings.views[id];
const label = (
<div className={ styles.header }>
<div className={ styles.labelicon }>
{ view.icon }
</div>
<div className={ styles.label }>
{ view.label }
</div>
</div>
);
return (
<div className={ styles.view } key={ id }>
<Checkbox
disabled={ view.fixed }
label={ label }
onCheck={ toggle }
checked={ view.active }
value={ view.active } />
<div className={ styles.info }>
{ view.description }
</div>
</div>
);
});
}
}
function mapStateToProps (state) {
const { settings } = state;
return { settings };
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({ toggleView }, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Views);

View File

@@ -0,0 +1,29 @@
// 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 function toggleView (viewId) {
return {
type: 'toggleView',
viewId
};
}
export function updateBackground (backgroundSeed) {
return {
type: 'updateBackground',
backgroundSeed
};
}

View File

@@ -0,0 +1,31 @@
// 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 settingsReducer from './reducers';
import { toggleView, updateBackground } from './actions';
import SettingsBackground from './Background';
import SettingsViews, { defaultViews } from './Views';
export default from './settings';
export {
SettingsBackground,
SettingsViews,
defaultViews,
settingsReducer,
toggleView,
updateBackground
};

View File

@@ -0,0 +1,54 @@
/* 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/>.
*/
.layout {
padding-top: 1.5em;
}
.layout::after {
display: table;
clear: both;
content: '';
}
.overview, .details {
float: left;
box-sizing: border-box;
}
.overview {
width: 33.33333%;
width: -webkit-calc(100% / 12 * 4);
width: -moz-calc(100% / 12 * 4);
width: calc(100% / 12 * 4);
}
.overview {
opacity: 0.5;
}
.overview>div+div {
padding-top: 1.25em;
}
.details {
width: 66.66665%;
width: -webkit-calc(100% / 12 * 8);
width: -moz-calc(100% / 12 * 8);
width: calc(100% / 12 * 8);
padding-left: 3em;
}

View File

@@ -0,0 +1,125 @@
// 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 defaultViews from './Views/defaults';
function initBackground (store, api) {
const backgroundSeed = loadBackground() || api.util.sha3(`${Date.now()}`);
store.dispatch({
type: 'updateBackground',
backgroundSeed
});
}
function loadBackground () {
return window.localStorage.getItem('backgroundSeed');
}
function saveBackground (backgroundSeed) {
window.localStorage.setItem('backgroundSeed', backgroundSeed);
}
function initViews (store) {
const { settings } = store.getState();
const data = loadViews();
const viewIds = Object.keys(data).filter((viewId) => {
return settings.views[viewId] && data[viewId].active !== settings.views[viewId].active;
});
if (viewIds.length) {
store.dispatch({ type: 'toggleViews', viewIds });
}
}
function getFixedViews () {
const views = {};
Object.keys(defaultViews).forEach((id) => {
if (defaultViews[id].fixed) {
views[id] = { active: true };
}
});
return views;
}
function getDefaultViews () {
const views = {};
Object.keys(defaultViews).forEach((id) => {
views[id] = {
active: defaultViews[id].active || false
};
});
return views;
}
function loadViews () {
const fixed = getFixedViews();
const defaults = getDefaultViews();
let data;
try {
const json = window.localStorage.getItem('views') || '{}';
data = Object.assign(defaults, JSON.parse(json), fixed);
} catch (e) {
data = defaults;
}
return data;
}
function saveViews (store) {
window.localStorage.setItem('views', JSON.stringify(getDefaultViews()));
}
function toggleViews (store, viewIds) {
viewIds.forEach((id) => {
defaultViews[id].active = !defaultViews[id].active;
});
saveViews(store);
}
export default class SettingsMiddleware {
toMiddleware () {
return (store) => (next) => (action) => {
switch (action.type) {
case 'initAll':
initBackground(store, action.api);
initViews(store);
break;
case 'toggleView':
toggleViews(store, [action.viewId]);
break;
case 'toggleViews':
toggleViews(store, action.viewIds);
break;
case 'updateBackground':
saveBackground(action.backgroundSeed);
break;
}
next(action);
};
}
}

View File

@@ -0,0 +1,40 @@
// 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 { handleActions } from 'redux-actions';
import views from './Views/defaults';
const initialState = {
views,
backgroundSeed: `${Date.now()}`
};
export default handleActions({
toggleView (state, action) {
return Object.assign({}, state, { views });
},
toggleViews (state, action) {
return Object.assign({}, state, { views });
},
updateBackground (state, action) {
const { backgroundSeed } = action;
return Object.assign({}, state, { backgroundSeed });
}
}, initialState);

View File

@@ -0,0 +1,62 @@
/* 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/>.
*/
.layout {
}
.menu {
display: inline-block;
}
.bar {
justify-content: flex-start !important;
}
.tabs {
margin-left: 3em;
}
.tab,
.tabactive {
padding: 16px 2em !important;
line-height: 24px !important;
}
.tabactive {
}
.tab>div,
.tabactive>div {
height: 24px !important;
}
.tab>div>div,
.tabactive>div>div {
display: inline-block !important;
}
.tab svg,
.tabactive svg {
margin-right: 0.5em;
margin-bottom: 0 !important;
}
.tab .menu,
.tabactive .menu {
vertical-align: top;
display: inline-block;
}

View File

@@ -0,0 +1,82 @@
// 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/>.
// 0xecf69634885f27a8f78161e530f15a8d3b57d39e755c222c92cf297b6e25aaaa
import React, { Component, PropTypes } from 'react';
import { Tab, Tabs } from 'material-ui';
import ImageBlurOn from 'material-ui/svg-icons/image/blur-on';
import ImageRemoveRedEye from 'material-ui/svg-icons/image/remove-red-eye';
import { Actionbar, Page } from '../../ui';
import styles from './settings.css';
export default class Settings extends Component {
static contextTypes = {
router: PropTypes.object.isRequired
}
static propTypes = {
children: PropTypes.object.isRequired
}
render () {
const { children } = this.props;
return (
<div className={ styles.layout }>
<Actionbar title='settings' className={ styles.bar }>
{ this.renderTabs() }
</Actionbar>
<Page>
{ children }
</Page>
</div>
);
}
renderTabs () {
const hash = (window.location.hash || '').split('?')[0].split('/')[2];
return (
<Tabs className={ styles.tabs } value={ hash }>
<Tab
className={ hash === 'views' ? styles.tabactive : styles.tab }
value='views'
key='views'
icon={ <ImageRemoveRedEye /> }
label={ <div className={ styles.menu }>views</div> }
onActive={ this.onActivate('views') } />
<Tab
className={ hash === 'background' ? styles.tabactive : styles.tab }
value='background'
key='background'
icon={ <ImageBlurOn /> }
label={ <div className={ styles.menu }>background</div> }
onActive={ this.onActivate('background') } />
</Tabs>
);
}
onActivate = (section) => {
const { router } = this.context;
return (event) => {
router.push(`/settings/${section}`);
};
}
}

View File

@@ -0,0 +1,44 @@
/* 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/>.
*/
.acc {
text-align: center;
display: inline-block;
}
.acc > * {
display: block;
}
.address {
font-family: monospace;
}
.acc img {
width: 28px;
height: 28px;
vertical-align: middle;
margin-right: 3px;
}
.name {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
display: lock;
vertical-align: middle;
text-transform: uppercase;
}

View File

@@ -0,0 +1,109 @@
// 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 { IdentityIcon, IdentityName } from '../../../../ui';
import AccountLink from './AccountLink';
import styles from './Account.css';
export default class Account extends Component {
static propTypes = {
className: PropTypes.string,
address: PropTypes.string.isRequired,
chain: PropTypes.string.isRequired,
balance: PropTypes.object // eth BigNumber, not required since it mght take time to fetch
};
state = {
balanceDisplay: '?'
};
componentWillMount () {
this.updateBalanceDisplay(this.props.balance);
}
componentWillReceiveProps (nextProps) {
if (nextProps.balance === this.props.balance) {
return;
}
this.updateBalanceDisplay(nextProps.balance);
}
updateBalanceDisplay (balance) {
this.setState({
balanceDisplay: balance ? balance.div(1e18).toFormat(3) : '?'
});
}
render () {
const { address, chain, className } = this.props;
return (
<div className={ `${styles.acc} ${className}` }>
<AccountLink address={ address } chain={ chain }>
<IdentityIcon
center
address={ address } />
</AccountLink>
{ this.renderName() }
{ this.renderBalance() }
</div>
);
}
renderBalance () {
const { balanceDisplay } = this.state;
return (
<span> <strong>{ balanceDisplay }</strong> <small>ETH</small></span>
);
}
renderName () {
const { address } = this.props;
const name = <IdentityName address={ address } empty />;
if (!name) {
return (
<AccountLink address={ address } chain={ this.props.chain }>
[{ this.shortAddress(address) }]
</AccountLink>
);
}
return (
<AccountLink address={ address } chain={ this.props.chain } >
<span>
<span className={ styles.name }>{ name }</span>
<span className={ styles.address }>[{ this.tinyAddress(address) }]</span>
</span>
</AccountLink>
);
}
tinyAddress () {
const { address } = this.props;
const len = address.length;
return address.slice(2, 4) + '..' + address.slice(len - 2);
}
shortAddress () {
const { address } = this.props;
const len = address.length;
return address.slice(2, 8) + '..' + address.slice(len - 7);
}
}

View File

@@ -0,0 +1,20 @@
/* 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/>.
*/
.container {
text-decoration: none;
color: inherit;
}

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 React, { Component, PropTypes } from 'react';
import { getAccountLink } from '../../util/account';
import styles from './AccountLink.css';
export default class AccountLink extends Component {
static propTypes = {
chain: PropTypes.string.isRequired,
address: PropTypes.string.isRequired,
className: PropTypes.string,
children: PropTypes.node
}
state = {
link: null
};
componentWillMount () {
const { address, chain } = this.props;
this.updateLink(address, chain);
}
componentWillReceiveProps (nextProps) {
const { address, chain } = nextProps;
this.updateLink(address, chain);
}
render () {
const { children, address, className } = this.props;
return (
<a
href={ this.state.link }
target='_blank'
className={ `${styles.container} ${className}` }
>
{ children || address }
</a>
);
}
updateLink (address, chain) {
const link = getAccountLink(address, chain);
this.setState({
link
});
}
}

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

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

View File

@@ -0,0 +1,80 @@
// 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 TransactionFinishedWeb3 from '../TransactionFinishedWeb3';
import SignWeb3 from '../SignRequestWeb3';
export default class RequestFinishedWeb3 extends Component {
static propTypes = {
id: PropTypes.object.isRequired,
result: PropTypes.any.isRequired,
date: PropTypes.instanceOf(Date).isRequired,
payload: PropTypes.oneOfType([
PropTypes.shape({ transaction: PropTypes.object.isRequired }),
PropTypes.shape({ sign: PropTypes.object.isRequired })
]).isRequired,
msg: PropTypes.string,
status: PropTypes.string,
error: PropTypes.string,
className: PropTypes.string
}
render () {
const { payload, id, result, msg, status, error, date, className } = this.props;
if (payload.sign) {
const { sign } = payload;
return (
<SignWeb3
className={ className }
isFinished
id={ id }
address={ sign.address }
hash={ sign.hash }
result={ result }
msg={ msg }
status={ status }
error={ error }
/>
);
}
if (payload.transaction) {
const { transaction } = payload;
return (
<TransactionFinishedWeb3
className={ className }
txHash={ result }
id={ id }
gasPrice={ transaction.gasPrice }
gas={ transaction.gas }
from={ transaction.from }
to={ transaction.to }
value={ transaction.value }
msg={ msg }
date={ date }
status={ status }
error={ error }
/>
);
}
// Unknown payload
return null;
}
}

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

View File

@@ -0,0 +1,78 @@
// 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 TransactionPendingWeb3 from '../TransactionPendingWeb3';
import SignRequestWeb3 from '../SignRequestWeb3';
export default class RequestPendingWeb3 extends Component {
static propTypes = {
id: PropTypes.object.isRequired,
onConfirm: PropTypes.func.isRequired,
onReject: PropTypes.func.isRequired,
isSending: PropTypes.bool.isRequired,
date: PropTypes.instanceOf(Date).isRequired,
payload: PropTypes.oneOfType([
PropTypes.shape({ transaction: PropTypes.object.isRequired }),
PropTypes.shape({ sign: PropTypes.object.isRequired })
]).isRequired,
className: PropTypes.string
};
render () {
const { payload, id, className, isSending, date, onConfirm, onReject } = this.props;
if (payload.sign) {
const { sign } = payload;
return (
<SignRequestWeb3
className={ className }
onConfirm={ onConfirm }
onReject={ onReject }
isSending={ isSending }
isFinished={ false }
id={ id }
address={ sign.address }
hash={ sign.hash }
/>
);
}
if (payload.transaction) {
const { transaction } = payload;
return (
<TransactionPendingWeb3
className={ className }
onConfirm={ onConfirm }
onReject={ onReject }
isSending={ isSending }
id={ id }
gasPrice={ transaction.gasPrice }
gas={ transaction.gas }
data={ transaction.data }
from={ transaction.from }
to={ transaction.to }
value={ transaction.value }
date={ date }
/>
);
}
// Unknown payload
return null;
}
}

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

View File

@@ -0,0 +1,74 @@
/* 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/>.
*/
.container {
padding: 25px 0 15px;
}
.actions, .signDetails {
display: inline-block;
vertical-align: middle;
min-height: 120px;
}
.signDetails {
border-right: 1px solid #eee;
margin-right: 2rem;
/* TODO [todr] mess - just to align with transaction */
width: 430px;
}
.address, .info {
display: inline-block;
}
.info {
padding: 0 30px;
width: 250px;
color: #E53935;
vertical-align: top;
}
.info p:first-child {
margin-top: 0;
}
/* TODO [todr] copy&paste from transactions */
.isConfirmed {
color: green;
}
.isRejected {
opacity: 0.7;
}
.txHash {
display: block;
word-break: break-all;
}
.actions {
width: 180px;
display: inline-block;
min-height: 120px;
}
.signDetails img {
display: inline-block;
width: 50px;
height: 50px;
margin: 5px;
}

View File

@@ -0,0 +1,113 @@
// 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 Account from '../Account';
import TransactionPendingForm from '../TransactionPendingForm';
import TxHashLink from '../TxHashLink';
import styles from './SignRequest.css';
export default class SignRequest extends Component {
// TODO [todr] re-use proptypes?
static propTypes = {
id: PropTypes.string.isRequired,
address: PropTypes.string.isRequired,
hash: PropTypes.string.isRequired,
isFinished: PropTypes.bool.isRequired,
chain: PropTypes.string.isRequired,
balance: PropTypes.object,
isSending: PropTypes.bool,
onConfirm: PropTypes.func,
onReject: PropTypes.func,
status: PropTypes.string,
className: PropTypes.string
};
render () {
const className = this.props.className || '';
return (
<div className={ `${styles.container} ${className}` }>
{ this.renderDetails() }
{ this.renderActions() }
</div>
);
}
renderDetails () {
const { address, balance, chain, hash } = this.props;
return (
<div className={ styles.signDetails }>
<div className={ styles.address }>
<Account address={ address } balance={ balance } chain={ chain } />
</div>
<div className={ styles.info } title={ hash }>
<p>Dapp is requesting to sign arbitrary transaction using this account.</p>
<p><strong>Confirm the transaction only if you trust the app.</strong></p>
</div>
</div>
);
}
renderActions () {
const { address, isFinished, status } = this.props;
if (isFinished) {
if (status === 'confirmed') {
const { chain, hash } = this.props;
return (
<div className={ styles.actions }>
<span className={ styles.isConfirmed }>Confirmed</span>
<div>
Transaction hash:
<TxHashLink chain={ chain } txHash={ hash } className={ styles.txHash } />
</div>
</div>
);
}
return (
<div className={ styles.actions }>
<span className={ styles.isRejected }>Rejected</span>
</div>
);
}
return (
<TransactionPendingForm
address={ address }
isSending={ this.props.isSending }
onConfirm={ this.onConfirm }
onReject={ this.onReject }
className={ styles.actions }
/>
);
}
onConfirm = password => {
const { id } = this.props;
this.props.onConfirm({ id, password });
}
onReject = () => {
this.props.onReject(this.props.id);
}
}

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

View File

@@ -0,0 +1,95 @@
// 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 SignRequest from '../SignRequest';
export default class SignRequestWeb3 extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
}
static propTypes = {
id: PropTypes.string.isRequired,
address: PropTypes.string.isRequired,
hash: PropTypes.string.isRequired,
isFinished: PropTypes.bool.isRequired,
isSending: PropTypes.bool,
onConfirm: PropTypes.func,
onReject: PropTypes.func,
status: PropTypes.string,
className: PropTypes.string
};
state = {
chain: 'homestead',
balance: null // avoid required prop loading warning
}
componentDidMount () {
this.fetchChain();
this.fetchBalance();
}
render () {
const { balance, chain } = this.state;
const { address, onConfirm, onReject, isSending, isFinished, hash, className, id, status } = this.props;
return (
<SignRequest
address={ address }
hash={ hash }
balance={ balance }
onConfirm={ onConfirm }
onReject={ onReject }
isSending={ isSending }
isFinished={ isFinished }
id={ id }
chain={ chain }
status={ status }
className={ className }
/>
);
}
fetchChain () {
const { api } = this.context;
api.ethcore
.getNetChain()
.then((chain) => {
this.setState({ chain });
})
.catch((error) => {
console.error('fetchChain', error);
});
}
fetchBalance () {
const { api } = this.context;
const { address } = this.props;
api.eth
.getBalance(address)
.then((balance) => {
this.setState({ balance });
})
.catch((error) => {
console.error('fetchBalance', error);
});
}
}

Some files were not shown because too many files have changed in this diff Show More