Merge branch 'master' into jg-test-ui
This commit is contained in:
		
						commit
						a73e0a987e
					
				
							
								
								
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -1271,7 +1271,7 @@ dependencies = [ | ||||
| [[package]] | ||||
| name = "parity-ui-precompiled" | ||||
| version = "1.4.0" | ||||
| source = "git+https://github.com/ethcore/js-precompiled.git#1bf7160f6c8f25353d790dbd0935560d3d395727" | ||||
| source = "git+https://github.com/ethcore/js-precompiled.git#b8e8e9a8482a51b9a86bb841674f71aca1e57934" | ||||
| dependencies = [ | ||||
|  "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "parity.js", | ||||
|   "version": "0.2.102", | ||||
|   "version": "0.2.104", | ||||
|   "main": "release/index.js", | ||||
|   "jsnext:main": "src/index.js", | ||||
|   "author": "Parity Team <admin@parity.io>", | ||||
|  | ||||
							
								
								
									
										8
									
								
								js/src/3rdparty/etherscan/links.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								js/src/3rdparty/etherscan/links.js
									
									
									
									
										vendored
									
									
								
							| @ -14,10 +14,14 @@ | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| export const url = (isTestnet = false) => { | ||||
|   return `https://${isTestnet ? 'testnet.' : ''}etherscan.io`; | ||||
| }; | ||||
| 
 | ||||
| export const txLink = (hash, isTestnet = false) => { | ||||
|   return `https://${isTestnet ? 'testnet.' : ''}etherscan.io/tx/${hash}`; | ||||
|   return `${url(isTestnet)}/tx/${hash}`; | ||||
| }; | ||||
| 
 | ||||
| export const addressLink = (address, isTestnet = false) => { | ||||
|   return `https://${isTestnet ? 'testnet.' : ''}etherscan.io/address/${address}`; | ||||
|   return `${url(isTestnet)}/address/${address}`; | ||||
| }; | ||||
|  | ||||
| @ -1,12 +0,0 @@ | ||||
| import babel from 'rollup-plugin-babel'; | ||||
| 
 | ||||
| export default { | ||||
|   entry: 'src/index.js', | ||||
|   dest: 'release/index.js', | ||||
|   format: 'cjs', | ||||
|   plugins: [babel({ | ||||
|     babelrc: false, | ||||
|     presets: ['es2015-rollup', 'stage-0'], | ||||
|     runtimeHelpers: true | ||||
|   })] | ||||
| }; | ||||
| @ -19,7 +19,7 @@ import ContentAdd from 'material-ui/svg-icons/content/add'; | ||||
| import ContentClear from 'material-ui/svg-icons/content/clear'; | ||||
| 
 | ||||
| import { Button, Modal, Form, Input, InputAddress } from '~/ui'; | ||||
| import { ERRORS, validateAddress, validateName } from '../../util/validation'; | ||||
| import { ERRORS, validateAddress, validateName } from '~/util/validation'; | ||||
| 
 | ||||
| export default class AddAddress extends Component { | ||||
|   static contextTypes = { | ||||
|  | ||||
| @ -21,7 +21,7 @@ import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forwa | ||||
| import NavigationArrowBack from 'material-ui/svg-icons/navigation/arrow-back'; | ||||
| 
 | ||||
| import { Button, Modal, Form, Input, InputAddress, RadioButtons } from '~/ui'; | ||||
| import { ERRORS, validateAbi, validateAddress, validateName } from '../../util/validation'; | ||||
| import { ERRORS, validateAbi, validateAddress, validateName } from '~/util/validation'; | ||||
| 
 | ||||
| import { eip20, wallet } from '~/contracts/abi'; | ||||
| 
 | ||||
|  | ||||
| @ -16,13 +16,12 @@ | ||||
| 
 | ||||
| import { observable, computed, action, transaction } from 'mobx'; | ||||
| 
 | ||||
| import { validateUint, validateAddress, validateName } from '~/util/validation'; | ||||
| import { ERROR_CODES } from '~/api/transport/error'; | ||||
| 
 | ||||
| import Contract from '~/api/contract'; | ||||
| import { ERROR_CODES } from '~/api/transport/error'; | ||||
| import { wallet as walletAbi } from '~/contracts/abi'; | ||||
| import { wallet as walletCode } from '~/contracts/code'; | ||||
| 
 | ||||
| import { validateUint, validateAddress, validateName } from '~/util/validation'; | ||||
| import WalletsUtils from '~/util/wallets'; | ||||
| 
 | ||||
| const STEPS = { | ||||
|  | ||||
| @ -18,8 +18,8 @@ import React, { Component, PropTypes } from 'react'; | ||||
| import { MenuItem } from 'material-ui'; | ||||
| 
 | ||||
| import { AddressSelect, Form, Input, Select } from '~/ui'; | ||||
| import { validateAbi } from '../../../util/validation'; | ||||
| import { parseAbiType } from '../../../util/abi'; | ||||
| import { validateAbi } from '~/util/validation'; | ||||
| import { parseAbiType } from '~/util/abi'; | ||||
| 
 | ||||
| export default class DetailsStep extends Component { | ||||
|   static contextTypes = { | ||||
|  | ||||
| @ -32,7 +32,7 @@ | ||||
| import React, { Component, PropTypes } from 'react'; | ||||
| 
 | ||||
| import { Form, TypedInput } from '~/ui'; | ||||
| import { parseAbiType } from '../../../util/abi'; | ||||
| import { parseAbiType } from '~/util/abi'; | ||||
| 
 | ||||
| import styles from '../deployContract.css'; | ||||
| 
 | ||||
|  | ||||
| @ -19,7 +19,7 @@ import ActionDoneAll from 'material-ui/svg-icons/action/done-all'; | ||||
| import ContentClear from 'material-ui/svg-icons/content/clear'; | ||||
| 
 | ||||
| import { BusyStep, CompletedStep, CopyToClipboard, Button, IdentityIcon, Modal, TxHash } from '~/ui'; | ||||
| import { ERRORS, validateAbi, validateCode, validateName } from '../../util/validation'; | ||||
| import { ERRORS, validateAbi, validateCode, validateName } from '~/util/validation'; | ||||
| 
 | ||||
| import DetailsStep from './DetailsStep'; | ||||
| import ParametersStep from './ParametersStep'; | ||||
|  | ||||
| @ -19,7 +19,7 @@ import ContentClear from 'material-ui/svg-icons/content/clear'; | ||||
| import ContentSave from 'material-ui/svg-icons/content/save'; | ||||
| 
 | ||||
| import { Button, Form, Input, InputChip, Modal } from '~/ui'; | ||||
| import { validateName } from '../../util/validation'; | ||||
| import { validateName } from '~/util/validation'; | ||||
| 
 | ||||
| export default class EditMeta extends Component { | ||||
|   static contextTypes = { | ||||
|  | ||||
| @ -21,8 +21,8 @@ import ActionDoneAll from 'material-ui/svg-icons/action/done-all'; | ||||
| import ContentClear from 'material-ui/svg-icons/content/clear'; | ||||
| 
 | ||||
| import { BusyStep, CompletedStep, Button, IdentityIcon, Modal, TxHash } from '~/ui'; | ||||
| import { MAX_GAS_ESTIMATION } from '../../util/constants'; | ||||
| import { validateAddress, validateUint } from '../../util/validation'; | ||||
| import { MAX_GAS_ESTIMATION } from '~/util/constants'; | ||||
| import { validateAddress, validateUint } from '~/util/validation'; | ||||
| import { parseAbiType } from '~/util/abi'; | ||||
| 
 | ||||
| import DetailsStep from './DetailsStep'; | ||||
|  | ||||
| @ -21,9 +21,8 @@ import { sha3 } from '~/api/util/sha3'; | ||||
| import Contracts from '~/contracts'; | ||||
| 
 | ||||
| import { checkIfVerified, checkIfRequested, awaitPuzzle } from '~/contracts/sms-verification'; | ||||
| import { postToServer } from '../../3rdparty/sms-verification'; | ||||
| import checkIfTxFailed from '../../util/check-if-tx-failed'; | ||||
| import waitForConfirmations from '../../util/wait-for-block-confirmations'; | ||||
| import { postToServer } from '~/3rdparty/sms-verification'; | ||||
| import { checkIfTxFailed, waitForConfirmations } from '~/util/tx'; | ||||
| 
 | ||||
| export const LOADING = 'fetching-contract'; | ||||
| export const QUERY_DATA = 'query-data'; | ||||
|  | ||||
| @ -20,7 +20,7 @@ import SaveIcon from 'material-ui/svg-icons/content/save'; | ||||
| import ContentClear from 'material-ui/svg-icons/content/clear'; | ||||
| 
 | ||||
| import { Button, Modal, Editor, Form, Input } from '~/ui'; | ||||
| import { ERRORS, validateName } from '../../util/validation'; | ||||
| import { ERRORS, validateName } from '~/util/validation'; | ||||
| 
 | ||||
| import styles from './saveContract.css'; | ||||
| 
 | ||||
|  | ||||
| @ -19,7 +19,7 @@ import ActionDoneAll from 'material-ui/svg-icons/action/done-all'; | ||||
| import ContentClear from 'material-ui/svg-icons/content/clear'; | ||||
| 
 | ||||
| import { Button, IdentityIcon, Modal } from '~/ui'; | ||||
| import initShapeshift from '../../3rdparty/shapeshift'; | ||||
| import initShapeshift from '~/3rdparty/shapeshift'; | ||||
| import shapeshiftLogo from '../../../assets/images/shapeshift-logo.png'; | ||||
| 
 | ||||
| import AwaitingDepositStep from './AwaitingDepositStep'; | ||||
|  | ||||
| @ -16,96 +16,35 @@ | ||||
| 
 | ||||
| import React, { Component, PropTypes } from 'react'; | ||||
| 
 | ||||
| import Form, { Input } from '~/ui/Form'; | ||||
| import GasPriceSelector from '../GasPriceSelector'; | ||||
| 
 | ||||
| import styles from '../transfer.css'; | ||||
| import { GasPriceEditor, Form, Input } from '~/ui'; | ||||
| 
 | ||||
| export default class Extras extends Component { | ||||
|   static propTypes = { | ||||
|     isEth: PropTypes.bool, | ||||
|     data: PropTypes.string, | ||||
|     dataError: PropTypes.string, | ||||
|     gas: PropTypes.string, | ||||
|     gasEst: PropTypes.string, | ||||
|     gasError: PropTypes.string, | ||||
|     gasPrice: PropTypes.oneOfType([ | ||||
|       PropTypes.string, | ||||
|       PropTypes.object | ||||
|     ]), | ||||
|     gasPriceDefault: PropTypes.string, | ||||
|     gasPriceError: PropTypes.string, | ||||
|     gasPriceHistogram: PropTypes.object, | ||||
|     total: PropTypes.string, | ||||
|     totalError: PropTypes.string, | ||||
|     onChange: PropTypes.func.isRequired | ||||
|     onChange: PropTypes.func.isRequired, | ||||
|     gasStore: PropTypes.object.isRequired | ||||
|   } | ||||
| 
 | ||||
|   render () { | ||||
|     const { gas, gasPrice, gasError, gasEst, gasPriceDefault, gasPriceError, gasPriceHistogram, total, totalError } = this.props; | ||||
| 
 | ||||
|     const gasLabel = `gas amount (estimated: ${gasEst})`; | ||||
|     const priceLabel = `gas price (current: ${gasPriceDefault})`; | ||||
|     const { gasStore, onChange, total, totalError } = this.props; | ||||
| 
 | ||||
|     return ( | ||||
|       <Form> | ||||
| 
 | ||||
|         { this.renderData() } | ||||
| 
 | ||||
|         <div className={ styles.columns }> | ||||
|           <div style={ { flex: 65 } }> | ||||
|             <GasPriceSelector | ||||
|               gasPriceHistogram={ gasPriceHistogram } | ||||
|               gasPrice={ gasPrice } | ||||
|               onChange={ this.onEditGasPrice } | ||||
|             /> | ||||
|           </div> | ||||
| 
 | ||||
|           <div | ||||
|             className={ styles.row } | ||||
|             style={ { | ||||
|               flex: 35, paddingLeft: '1rem', | ||||
|               justifyContent: 'space-around', | ||||
|               paddingBottom: 12 | ||||
|             } } | ||||
|           > | ||||
|             <div className={ styles.row }> | ||||
|               <Input | ||||
|                 label={ gasLabel } | ||||
|                 hint='the amount of gas to use for the transaction' | ||||
|                 error={ gasError } | ||||
|                 value={ gas } | ||||
|                 onChange={ this.onEditGas } /> | ||||
| 
 | ||||
|               <Input | ||||
|                 label={ priceLabel } | ||||
|                 hint='the price of gas to use for the transaction' | ||||
|                 error={ gasPriceError } | ||||
|                 value={ (gasPrice || '').toString() } | ||||
|                 onChange={ this.onEditGasPrice } /> | ||||
|             </div> | ||||
| 
 | ||||
|             <div className={ styles.row }> | ||||
|               <Input | ||||
|                 disabled | ||||
|                 label='total transaction amount' | ||||
|                 hint='the total amount of the transaction' | ||||
|                 error={ totalError } | ||||
|                 value={ `${total} ETH` } /> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div> | ||||
|           <p className={ styles.gasPriceDesc }> | ||||
|             You can choose the gas price based on the | ||||
|             distribution of recent included transactions' gas prices. | ||||
|             The lower the gas price is, the cheaper the transaction will | ||||
|             be. The higher the gas price is, the faster it should | ||||
|             get mined by the network. | ||||
|           </p> | ||||
|         </div> | ||||
| 
 | ||||
|         <GasPriceEditor | ||||
|           store={ gasStore } | ||||
|           onChange={ onChange }> | ||||
|           <Input | ||||
|             disabled | ||||
|             label='total transaction amount' | ||||
|             hint='the total amount of the transaction' | ||||
|             error={ totalError } | ||||
|             value={ `${total} ETH` } /> | ||||
|         </GasPriceEditor> | ||||
|       </Form> | ||||
|     ); | ||||
|   } | ||||
| @ -129,14 +68,6 @@ export default class Extras extends Component { | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   onEditGas = (event) => { | ||||
|     this.props.onChange('gas', event.target.value); | ||||
|   } | ||||
| 
 | ||||
|   onEditGasPrice = (event, value) => { | ||||
|     this.props.onChange('gasPrice', value); | ||||
|   } | ||||
| 
 | ||||
|   onEditData = (event) => { | ||||
|     this.props.onChange('data', event.target.value); | ||||
|   } | ||||
|  | ||||
| @ -23,7 +23,8 @@ import { bytesToHex } from '~/api/util/format'; | ||||
| import Contract from '~/api/contract'; | ||||
| import ERRORS from './errors'; | ||||
| import { ERROR_CODES } from '~/api/transport/error'; | ||||
| import { DEFAULT_GAS, DEFAULT_GASPRICE, MAX_GAS_ESTIMATION } from '~/util/constants'; | ||||
| import { DEFAULT_GAS, MAX_GAS_ESTIMATION } from '~/util/constants'; | ||||
| import GasPriceStore from '~/ui/GasPriceEditor/store'; | ||||
| 
 | ||||
| const TITLES = { | ||||
|   transfer: 'transfer details', | ||||
| @ -48,14 +49,6 @@ export default class TransferStore { | ||||
|   @observable data = ''; | ||||
|   @observable dataError = null; | ||||
| 
 | ||||
|   @observable gas = DEFAULT_GAS; | ||||
|   @observable gasError = null; | ||||
| 
 | ||||
|   @observable gasEst = '0'; | ||||
|   @observable gasLimitError = null; | ||||
|   @observable gasPrice = DEFAULT_GASPRICE; | ||||
|   @observable gasPriceError = null; | ||||
| 
 | ||||
|   @observable recipient = ''; | ||||
|   @observable recipientError = ERRORS.requireRecipient; | ||||
| 
 | ||||
| @ -68,11 +61,8 @@ export default class TransferStore { | ||||
|   @observable value = '0.0'; | ||||
|   @observable valueError = null; | ||||
| 
 | ||||
|   gasPriceHistogram = {}; | ||||
| 
 | ||||
|   account = null; | ||||
|   balance = null; | ||||
|   gasLimit = null; | ||||
|   onClose = null; | ||||
| 
 | ||||
|   senders = null; | ||||
| @ -81,6 +71,8 @@ export default class TransferStore { | ||||
|   isWallet = false; | ||||
|   wallet = null; | ||||
| 
 | ||||
|   gasStore = null; | ||||
| 
 | ||||
|   @computed get steps () { | ||||
|     const steps = [].concat(this.extras ? STAGES_EXTRA : STAGES_BASIC); | ||||
| 
 | ||||
| @ -93,7 +85,7 @@ export default class TransferStore { | ||||
| 
 | ||||
|   @computed get isValid () { | ||||
|     const detailsValid = !this.recipientError && !this.valueError && !this.totalError && !this.senderError; | ||||
|     const extrasValid = !this.gasError && !this.gasPriceError && !this.totalError; | ||||
|     const extrasValid = !this.gasStore.errorGas && !this.gasStore.errorPrice && !this.totalError; | ||||
|     const verifyValid = !this.passwordError; | ||||
| 
 | ||||
|     switch (this.stage) { | ||||
| @ -118,11 +110,12 @@ export default class TransferStore { | ||||
|     const { account, balance, gasLimit, senders, onClose, newError, sendersBalances } = props; | ||||
|     this.account = account; | ||||
|     this.balance = balance; | ||||
|     this.gasLimit = gasLimit; | ||||
|     this.onClose = onClose; | ||||
|     this.isWallet = account && account.wallet; | ||||
|     this.newError = newError; | ||||
| 
 | ||||
|     this.gasStore = new GasPriceStore(api, gasLimit); | ||||
| 
 | ||||
|     if (this.isWallet) { | ||||
|       this.wallet = props.wallet; | ||||
|       this.walletContract = new Contract(this.api, walletAbi); | ||||
| @ -179,26 +172,6 @@ export default class TransferStore { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @action getDefaults = () => { | ||||
|     Promise | ||||
|       .all([ | ||||
|         this.api.parity.gasPriceHistogram(), | ||||
|         this.api.eth.gasPrice() | ||||
|       ]) | ||||
|       .then(([gasPriceHistogram, gasPrice]) => { | ||||
|         transaction(() => { | ||||
|           this.gasPrice = gasPrice.toString(); | ||||
|           this.gasPriceDefault = gasPrice.toFormat(); | ||||
|           this.gasPriceHistogram = gasPriceHistogram; | ||||
| 
 | ||||
|           this.recalculate(); | ||||
|         }); | ||||
|       }) | ||||
|       .catch((error) => { | ||||
|         console.warn('getDefaults', error); | ||||
|       }); | ||||
|   } | ||||
| 
 | ||||
|   @action onSend = () => { | ||||
|     this.onNext(); | ||||
|     this.sending = true; | ||||
| @ -281,25 +254,11 @@ export default class TransferStore { | ||||
|   } | ||||
| 
 | ||||
|   @action _onUpdateGas = (gas) => { | ||||
|     const gasError = this._validatePositiveNumber(gas); | ||||
| 
 | ||||
|     transaction(() => { | ||||
|       this.gas = gas; | ||||
|       this.gasError = gasError; | ||||
| 
 | ||||
|       this.recalculate(); | ||||
|     }); | ||||
|     this.recalculate(); | ||||
|   } | ||||
| 
 | ||||
|   @action _onUpdateGasPrice = (gasPrice) => { | ||||
|     const gasPriceError = this._validatePositiveNumber(gasPrice); | ||||
| 
 | ||||
|     transaction(() => { | ||||
|       this.gasPrice = gasPrice; | ||||
|       this.gasPriceError = gasPriceError; | ||||
| 
 | ||||
|       this.recalculate(); | ||||
|     }); | ||||
|     this.recalculate(); | ||||
|   } | ||||
| 
 | ||||
|   @action _onUpdateRecipient = (recipient) => { | ||||
| @ -362,7 +321,7 @@ export default class TransferStore { | ||||
| 
 | ||||
|   @action recalculateGas = () => { | ||||
|     if (!this.isValid) { | ||||
|       this.gas = 0; | ||||
|       this.gasStore.setGas('0'); | ||||
|       return this.recalculate(); | ||||
|     } | ||||
| 
 | ||||
| @ -370,28 +329,20 @@ export default class TransferStore { | ||||
|       .estimateGas() | ||||
|       .then((gasEst) => { | ||||
|         let gas = gasEst; | ||||
|         let gasLimitError = null; | ||||
| 
 | ||||
|         if (gas.gt(DEFAULT_GAS)) { | ||||
|           gas = gas.mul(1.2); | ||||
|         } | ||||
| 
 | ||||
|         if (gas.gte(MAX_GAS_ESTIMATION)) { | ||||
|           gasLimitError = ERRORS.gasException; | ||||
|         } else if (gas.gt(this.gasLimit)) { | ||||
|           gasLimitError = ERRORS.gasBlockLimit; | ||||
|         } | ||||
| 
 | ||||
|         transaction(() => { | ||||
|           this.gas = gas.toFixed(0); | ||||
|           this.gasEst = gasEst.toFormat(); | ||||
|           this.gasLimitError = gasLimitError; | ||||
|           this.gasStore.setEstimated(gasEst.toFixed(0)); | ||||
|           this.gasStore.setGas(gas.toFixed(0)); | ||||
| 
 | ||||
|           this.recalculate(); | ||||
|         }); | ||||
|       }) | ||||
|       .catch((error) => { | ||||
|         console.error('etimateGas', error); | ||||
|         console.warn('etimateGas', error); | ||||
|         this.recalculate(); | ||||
|       }); | ||||
|   } | ||||
| @ -411,9 +362,9 @@ export default class TransferStore { | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     const { gas, gasPrice, tag, valueAll, isEth, isWallet } = this; | ||||
|     const { tag, valueAll, isEth, isWallet } = this; | ||||
| 
 | ||||
|     const gasTotal = new BigNumber(gasPrice || 0).mul(new BigNumber(gas || 0)); | ||||
|     const gasTotal = new BigNumber(this.gasStore.price || 0).mul(new BigNumber(this.gasStore.gas || 0)); | ||||
| 
 | ||||
|     const availableEth = new BigNumber(balance.tokens[0].value); | ||||
| 
 | ||||
| @ -453,7 +404,7 @@ export default class TransferStore { | ||||
|     } | ||||
| 
 | ||||
|     transaction(() => { | ||||
|       this.total = this.api.util.fromWei(totalEth).toString(); | ||||
|       this.total = this.api.util.fromWei(totalEth).toFixed(); | ||||
|       this.totalError = totalError; | ||||
|       this.value = value; | ||||
|       this.valueError = valueError; | ||||
| @ -522,8 +473,8 @@ export default class TransferStore { | ||||
|     }; | ||||
| 
 | ||||
|     if (!gas) { | ||||
|       options.gas = this.gas; | ||||
|       options.gasPrice = this.gasPrice; | ||||
|       options.gas = this.gasStore.gas; | ||||
|       options.gasPrice = this.gasStore.price; | ||||
|     } else { | ||||
|       options.gas = MAX_GAS_ESTIMATION; | ||||
|     } | ||||
|  | ||||
| @ -144,15 +144,6 @@ | ||||
|   font-size: 1.2rem; | ||||
| } | ||||
| 
 | ||||
| .chart { | ||||
|   position: absolute; | ||||
|   width: 100%; | ||||
| } | ||||
| 
 | ||||
| .gasPriceDesc { | ||||
|   font-size: 0.9em; | ||||
| } | ||||
| 
 | ||||
| .warning { | ||||
|   border-radius: 0.5em; | ||||
|   background: #f80; | ||||
|  | ||||
| @ -56,10 +56,6 @@ class Transfer extends Component { | ||||
| 
 | ||||
|   store = new TransferStore(this.context.api, this.props); | ||||
| 
 | ||||
|   componentDidMount () { | ||||
|     this.store.getDefaults(); | ||||
|   } | ||||
| 
 | ||||
|   render () { | ||||
|     const { stage, extras, steps } = this.store; | ||||
| 
 | ||||
| @ -186,27 +182,20 @@ class Transfer extends Component { | ||||
|   } | ||||
| 
 | ||||
|   renderExtrasPage () { | ||||
|     if (!this.store.gasPriceHistogram) { | ||||
|     if (!this.store.gasStore.histogram) { | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     const { isEth, data, dataError, gas, gasEst, gasError, gasPrice } = this.store; | ||||
|     const { gasPriceDefault, gasPriceError, gasPriceHistogram, total, totalError } = this.store; | ||||
|     const { isEth, data, dataError, total, totalError } = this.store; | ||||
| 
 | ||||
|     return ( | ||||
|       <Extras | ||||
|         isEth={ isEth } | ||||
|         data={ data } | ||||
|         dataError={ dataError } | ||||
|         gas={ gas } | ||||
|         gasEst={ gasEst } | ||||
|         gasError={ gasError } | ||||
|         gasPrice={ gasPrice } | ||||
|         gasPriceDefault={ gasPriceDefault } | ||||
|         gasPriceError={ gasPriceError } | ||||
|         gasPriceHistogram={ gasPriceHistogram } | ||||
|         total={ total } | ||||
|         totalError={ totalError } | ||||
|         gasStore={ this.store.gasStore } | ||||
|         onChange={ this.store.onUpdateDetails } /> | ||||
|     ); | ||||
|   } | ||||
| @ -263,15 +252,15 @@ class Transfer extends Component { | ||||
|   } | ||||
| 
 | ||||
|   renderWarning () { | ||||
|     const { gasLimitError } = this.store; | ||||
|     const { errorEstimated } = this.store.gasStore; | ||||
| 
 | ||||
|     if (!gasLimitError) { | ||||
|     if (!errorEstimated) { | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     return ( | ||||
|       <div className={ styles.warning }> | ||||
|         { gasLimitError } | ||||
|         { errorEstimated } | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| @ -17,12 +17,10 @@ | ||||
| import { isEqual, uniq } from 'lodash'; | ||||
| 
 | ||||
| import Contract from '~/api/contract'; | ||||
| import { wallet as WALLET_ABI } from '~/contracts/abi'; | ||||
| import { bytesToHex, toHex } from '~/api/util/format'; | ||||
| 
 | ||||
| import { ERROR_CODES } from '~/api/transport/error'; | ||||
| import { MAX_GAS_ESTIMATION } from '../../util/constants'; | ||||
| 
 | ||||
| import { wallet as WALLET_ABI } from '~/contracts/abi'; | ||||
| import { MAX_GAS_ESTIMATION } from '~/util/constants'; | ||||
| import WalletsUtils from '~/util/wallets'; | ||||
| 
 | ||||
| import { newError } from '~/ui/Errors/actions'; | ||||
|  | ||||
| @ -22,12 +22,11 @@ import IconButton from 'material-ui/IconButton'; | ||||
| import AddIcon from 'material-ui/svg-icons/content/add'; | ||||
| import RemoveIcon from 'material-ui/svg-icons/content/remove'; | ||||
| 
 | ||||
| import { fromWei, toWei } from '~/api/util/wei'; | ||||
| import Input from '~/ui/Form/Input'; | ||||
| import InputAddressSelect from '~/ui/Form/InputAddressSelect'; | ||||
| import Select from '~/ui/Form/Select'; | ||||
| 
 | ||||
| import { ABI_TYPES } from '~/util/abi'; | ||||
| import { fromWei, toWei } from '~/api/util/wei'; | ||||
| 
 | ||||
| import styles from './typedInput.css'; | ||||
| 
 | ||||
|  | ||||
| @ -15,3 +15,13 @@ | ||||
| /* along with Parity.  If not, see <http://www.gnu.org/licenses/>. | ||||
| */ | ||||
| 
 | ||||
| .chart { | ||||
|   position: absolute; | ||||
|   width: 100%; | ||||
| } | ||||
| 
 | ||||
| .columns { | ||||
|   display: flex; | ||||
|   flex-wrap: wrap; | ||||
|   position: relative; | ||||
| } | ||||
| @ -29,10 +29,7 @@ import { | ||||
| import Slider from 'material-ui/Slider'; | ||||
| import BigNumber from 'bignumber.js'; | ||||
| 
 | ||||
| import componentStyles from './gasPriceSelector.css'; | ||||
| import mainStyles from '../transfer.css'; | ||||
| 
 | ||||
| const styles = Object.assign({}, mainStyles, componentStyles); | ||||
| import styles from './gasPriceSelector.css'; | ||||
| 
 | ||||
| const COLORS = { | ||||
|   default: 'rgba(255, 99, 132, 0.2)', | ||||
| @ -194,10 +191,7 @@ class CustomizedShape extends Component { | ||||
| 
 | ||||
| class CustomTooltip extends Component { | ||||
|   static propTypes = { | ||||
|     gasPriceHistogram: PropTypes.shape({ | ||||
|       bucketBounds: PropTypes.array.isRequired, | ||||
|       counts: PropTypes.array.isRequired | ||||
|     }).isRequired, | ||||
|     gasPriceHistogram: PropTypes.object.isRequired, | ||||
|     type: PropTypes.string, | ||||
|     payload: PropTypes.array, | ||||
|     label: PropTypes.number, | ||||
| @ -231,12 +225,16 @@ class CustomTooltip extends Component { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| const TOOL_STYLE = { | ||||
|   color: 'rgba(255,255,255,0.5)', | ||||
|   backgroundColor: 'rgba(0, 0, 0, 0.75)', | ||||
|   padding: '0 0.5em', | ||||
|   fontSize: '0.75em' | ||||
| }; | ||||
| 
 | ||||
| export default class GasPriceSelector extends Component { | ||||
|   static propTypes = { | ||||
|     gasPriceHistogram: PropTypes.shape({ | ||||
|       bucketBounds: PropTypes.array.isRequired, | ||||
|       counts: PropTypes.array.isRequired | ||||
|     }).isRequired, | ||||
|     gasPriceHistogram: PropTypes.object.isRequired, | ||||
|     onChange: PropTypes.func.isRequired, | ||||
| 
 | ||||
|     gasPrice: PropTypes.oneOfType([ | ||||
| @ -287,21 +285,23 @@ export default class GasPriceSelector extends Component { | ||||
|   renderSlider () { | ||||
|     const { sliderValue } = this.state; | ||||
| 
 | ||||
|     return (<div className={ styles.columns }> | ||||
|       <Slider | ||||
|         min={ 0 } | ||||
|         max={ 1 } | ||||
|         value={ sliderValue } | ||||
|         onChange={ this.onEditGasPriceSlider } | ||||
|         style={ { | ||||
|           flex: 1, | ||||
|           padding: '0 0.3em' | ||||
|         } } | ||||
|         sliderStyle={ { | ||||
|           marginBottom: 12 | ||||
|         } } | ||||
|       /> | ||||
|     </div>); | ||||
|     return ( | ||||
|       <div className={ styles.columns }> | ||||
|         <Slider | ||||
|           min={ 0 } | ||||
|           max={ 1 } | ||||
|           value={ sliderValue } | ||||
|           onChange={ this.onEditGasPriceSlider } | ||||
|           style={ { | ||||
|             flex: 1, | ||||
|             padding: '0 0.3em' | ||||
|           } } | ||||
|           sliderStyle={ { | ||||
|             marginBottom: 12 | ||||
|           } } | ||||
|         /> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   renderChart () { | ||||
| @ -316,85 +316,83 @@ export default class GasPriceSelector extends Component { | ||||
|     const countIndex = Math.max(0, Math.min(selectedIndex, gasPriceHistogram.counts.length - 1)); | ||||
|     const selectedCount = countModifier(gasPriceHistogram.counts[countIndex]); | ||||
| 
 | ||||
|     return (<div className={ styles.columns }> | ||||
|       <div style={ { flex: 1, height } }> | ||||
|         <div className={ styles.chart }> | ||||
|           <ResponsiveContainer | ||||
|             height={ height } | ||||
|           > | ||||
|             <ScatterChart | ||||
|               margin={ { top: 0, right: 0, left: 0, bottom: 0 } } | ||||
|     return ( | ||||
|       <div className={ styles.columns }> | ||||
|         <div style={ { flex: 1, height } }> | ||||
|           <div className={ styles.chart }> | ||||
|             <ResponsiveContainer | ||||
|               height={ height } | ||||
|             > | ||||
|               <Scatter | ||||
|                 data={ [ | ||||
|                   { x: sliderValue, y: 0 }, | ||||
|                   { x: sliderValue, y: selectedCount }, | ||||
|                   { x: sliderValue, y: chartData.yDomain[1] } | ||||
|                 ] } | ||||
|                 shape={ <CustomizedShape showValue={ selectedCount } /> } | ||||
|                 line | ||||
|                 isAnimationActive={ false } | ||||
|               /> | ||||
|               <ScatterChart | ||||
|                 margin={ { top: 0, right: 0, left: 0, bottom: 0 } } | ||||
|               > | ||||
|                 <Scatter | ||||
|                   data={ [ | ||||
|                     { x: sliderValue, y: 0 }, | ||||
|                     { x: sliderValue, y: selectedCount }, | ||||
|                     { x: sliderValue, y: chartData.yDomain[1] } | ||||
|                   ] } | ||||
|                   shape={ <CustomizedShape showValue={ selectedCount } /> } | ||||
|                   line | ||||
|                   isAnimationActive={ false } | ||||
|                 /> | ||||
| 
 | ||||
|               <XAxis | ||||
|                 hide | ||||
|                 height={ 0 } | ||||
|                 dataKey='x' | ||||
|                 domain={ [0, 1] } | ||||
|               /> | ||||
|               <YAxis | ||||
|                 hide | ||||
|                 width={ 0 } | ||||
|                 dataKey='y' | ||||
|                 domain={ chartData.yDomain } | ||||
|               /> | ||||
|             </ScatterChart> | ||||
|           </ResponsiveContainer> | ||||
|         </div> | ||||
|                 <XAxis | ||||
|                   hide | ||||
|                   height={ 0 } | ||||
|                   dataKey='x' | ||||
|                   domain={ [0, 1] } | ||||
|                 /> | ||||
|                 <YAxis | ||||
|                   hide | ||||
|                   width={ 0 } | ||||
|                   dataKey='y' | ||||
|                   domain={ chartData.yDomain } | ||||
|                 /> | ||||
|               </ScatterChart> | ||||
|             </ResponsiveContainer> | ||||
|           </div> | ||||
| 
 | ||||
|         <div className={ styles.chart }> | ||||
|           <ResponsiveContainer | ||||
|             height={ height } | ||||
|           > | ||||
|             <BarChart | ||||
|               data={ chartData.values } | ||||
|               margin={ { top: 0, right: 0, left: 0, bottom: 0 } } | ||||
|               barCategoryGap={ 1 } | ||||
|               ref='barChart' | ||||
|           <div className={ styles.chart }> | ||||
|             <ResponsiveContainer | ||||
|               height={ height } | ||||
|             > | ||||
|               <Bar | ||||
|                 dataKey='value' | ||||
|                 stroke={ COLORS.line } | ||||
|                 onClick={ this.onClickGasPrice } | ||||
|                 shape={ <CustomBar selected={ selectedIndex } onClick={ this.onClickGasPrice } /> } | ||||
|               /> | ||||
|               <BarChart | ||||
|                 data={ chartData.values } | ||||
|                 margin={ { top: 0, right: 0, left: 0, bottom: 0 } } | ||||
|                 barCategoryGap={ 1 } | ||||
|                 ref='barChart' | ||||
|               > | ||||
|                 <Bar | ||||
|                   dataKey='value' | ||||
|                   stroke={ COLORS.line } | ||||
|                   onClick={ this.onClickGasPrice } | ||||
|                   shape={ <CustomBar selected={ selectedIndex } onClick={ this.onClickGasPrice } /> } | ||||
|                 /> | ||||
| 
 | ||||
|               <Tooltip | ||||
|                 wrapperStyle={ { | ||||
|                   backgroundColor: 'rgba(0, 0, 0, 0.75)', | ||||
|                   padding: '0 0.5em', | ||||
|                   fontSize: '0.9em' | ||||
|                 } } | ||||
|                 cursor={ this.renderCustomCursor() } | ||||
|                 content={ <CustomTooltip gasPriceHistogram={ gasPriceHistogram } /> } | ||||
|               /> | ||||
|                 <Tooltip | ||||
|                   wrapperStyle={ TOOL_STYLE } | ||||
|                   cursor={ this.renderCustomCursor() } | ||||
|                   content={ <CustomTooltip gasPriceHistogram={ gasPriceHistogram } /> } | ||||
|                 /> | ||||
| 
 | ||||
|               <XAxis | ||||
|                 hide | ||||
|                 dataKey='index' | ||||
|                 type='category' | ||||
|                 domain={ chartData.xDomain } | ||||
|               /> | ||||
|               <YAxis | ||||
|                 hide | ||||
|                 type='number' | ||||
|                 domain={ chartData.yDomain } | ||||
|               /> | ||||
|             </BarChart> | ||||
|           </ResponsiveContainer> | ||||
|                 <XAxis | ||||
|                   hide | ||||
|                   dataKey='index' | ||||
|                   type='category' | ||||
|                   domain={ chartData.xDomain } | ||||
|                 /> | ||||
|                 <YAxis | ||||
|                   hide | ||||
|                   type='number' | ||||
|                   domain={ chartData.yDomain } | ||||
|                 /> | ||||
|               </BarChart> | ||||
|             </ResponsiveContainer> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div>); | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   renderCustomCursor = () => { | ||||
| @ -14,11 +14,36 @@ | ||||
| /* You should have received a copy of the GNU General Public License | ||||
| /* along with Parity.  If not, see <http://www.gnu.org/licenses/>. | ||||
| */ | ||||
| .signer { | ||||
| 
 | ||||
| .columns { | ||||
|   display: flex; | ||||
|   flex-wrap: wrap; | ||||
|   position: relative; | ||||
| } | ||||
| 
 | ||||
| .container { | ||||
| .graphColumn { | ||||
|   flex: 65; | ||||
| } | ||||
| 
 | ||||
| .mainContainer { | ||||
| .editColumn { | ||||
|   flex: 35; | ||||
|   padding-left: 1em; | ||||
|   justify-ontent: space-around; | ||||
|   padding-bottom: 12; | ||||
|   display: flex; | ||||
|   flex-wrap: wrap; | ||||
|   position: relative; | ||||
|   flex-direction: column; | ||||
| } | ||||
| 
 | ||||
| .gasPriceDesc { | ||||
|   font-size: 0.75em; | ||||
|   opacity: 0.5; | ||||
| } | ||||
| 
 | ||||
| .row { | ||||
|   display: flex; | ||||
|   flex-wrap: wrap; | ||||
|   position: relative; | ||||
|   flex-direction: column; | ||||
| } | ||||
							
								
								
									
										98
									
								
								js/src/ui/GasPriceEditor/gasPriceEditor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								js/src/ui/GasPriceEditor/gasPriceEditor.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | ||||
| // 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 { observer } from 'mobx-react'; | ||||
| 
 | ||||
| import Input from '../Form/Input'; | ||||
| import GasPriceSelector from './GasPriceSelector'; | ||||
| import Store from './store'; | ||||
| 
 | ||||
| import styles from './gasPriceEditor.css'; | ||||
| 
 | ||||
| @observer | ||||
| export default class GasPriceEditor extends Component { | ||||
|   static propTypes = { | ||||
|     children: PropTypes.node, | ||||
|     store: PropTypes.object.isRequired, | ||||
|     onChange: PropTypes.func | ||||
|   } | ||||
| 
 | ||||
|   static Store = Store; | ||||
| 
 | ||||
|   render () { | ||||
|     const { children, store } = this.props; | ||||
|     const { estimated, priceDefault, price, gas, histogram, errorGas, errorPrice } = store; | ||||
| 
 | ||||
|     const gasLabel = `gas (estimated: ${new BigNumber(estimated).toFormat()})`; | ||||
|     const priceLabel = `price (current: ${new BigNumber(priceDefault).toFormat()})`; | ||||
| 
 | ||||
|     return ( | ||||
|       <div className={ styles.columns }> | ||||
|         <div className={ styles.graphColumn }> | ||||
|           <GasPriceSelector | ||||
|             gasPriceHistogram={ histogram } | ||||
|             gasPrice={ price } | ||||
|             onChange={ this.onEditGasPrice } /> | ||||
|           <div className={ styles.gasPriceDesc }> | ||||
|             You can choose the gas price based on the | ||||
|             distribution of recent included transaction gas prices. | ||||
|             The lower the gas price is, the cheaper the transaction will | ||||
|             be. The higher the gas price is, the faster it should | ||||
|             get mined by the network. | ||||
|           </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div className={ styles.editColumn }> | ||||
|           <div className={ styles.row }> | ||||
|             <Input | ||||
|               label={ gasLabel } | ||||
|               hint='the amount of gas to use for the transaction' | ||||
|               error={ errorGas } | ||||
|               value={ gas } | ||||
|               onChange={ this.onEditGas } /> | ||||
| 
 | ||||
|             <Input | ||||
|               label={ priceLabel } | ||||
|               hint='the price of gas to use for the transaction' | ||||
|               error={ errorPrice } | ||||
|               value={ price } | ||||
|               onChange={ this.onEditGasPrice } /> | ||||
|           </div> | ||||
| 
 | ||||
|           <div className={ styles.row }> | ||||
|             { children } | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   onEditGas = (event, gas) => { | ||||
|     const { store, onChange } = this.props; | ||||
| 
 | ||||
|     store.setGas(gas); | ||||
|     onChange && onChange('gas', gas); | ||||
|   } | ||||
| 
 | ||||
|   onEditGasPrice = (event, price) => { | ||||
|     const { store, onChange } = this.props; | ||||
| 
 | ||||
|     store.setPrice(price); | ||||
|     onChange && onChange('gasPrice', price); | ||||
|   } | ||||
| } | ||||
| @ -14,6 +14,4 @@ | ||||
| // 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 (chain) => { | ||||
|   return chain === 'morden' || chain === 'ropsten' || chain === 'testnet'; | ||||
| }; | ||||
| export default from './gasPriceEditor'; | ||||
							
								
								
									
										105
									
								
								js/src/ui/GasPriceEditor/store.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								js/src/ui/GasPriceEditor/store.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,105 @@ | ||||
| // 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 { action, observable, transaction } from 'mobx'; | ||||
| 
 | ||||
| import { ERRORS, validatePositiveNumber } from '~/util/validation'; | ||||
| import { DEFAULT_GAS, DEFAULT_GASPRICE, MAX_GAS_ESTIMATION } from '~/util/constants'; | ||||
| 
 | ||||
| export default class GasPriceEditor { | ||||
|   @observable errorEstimated = null; | ||||
|   @observable errorGas = null; | ||||
|   @observable errorPrice = null; | ||||
|   @observable estimated = DEFAULT_GAS; | ||||
|   @observable histogram = null; | ||||
|   @observable price = DEFAULT_GASPRICE; | ||||
|   @observable priceDefault = DEFAULT_GASPRICE; | ||||
|   @observable gas = DEFAULT_GAS; | ||||
|   @observable gasLimit = 0; | ||||
| 
 | ||||
|   constructor (api, gasLimit, loadDefaults = true) { | ||||
|     this._api = api; | ||||
|     this.gasLimit = gasLimit; | ||||
| 
 | ||||
|     if (loadDefaults) { | ||||
|       this.loadDefaults(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @action setEstimated = (estimated) => { | ||||
|     transaction(() => { | ||||
|       const bn = new BigNumber(estimated); | ||||
| 
 | ||||
|       this.estimated = estimated; | ||||
| 
 | ||||
|       if (bn.gte(MAX_GAS_ESTIMATION)) { | ||||
|         this.errorEstimated = ERRORS.gasException; | ||||
|       } else if (bn.gte(this.gasLimit)) { | ||||
|         this.errorEstimated = ERRORS.gasBlockLimit; | ||||
|       } else { | ||||
|         this.errorEstimated = null; | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   @action setHistogram = (gasHistogram) => { | ||||
|     this.histogram = gasHistogram; | ||||
|   } | ||||
| 
 | ||||
|   @action setPrice = (price) => { | ||||
|     transaction(() => { | ||||
|       this.errorPrice = validatePositiveNumber(price).numberError; | ||||
|       this.price = price; | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   @action setGas = (gas) => { | ||||
|     transaction(() => { | ||||
|       const { numberError } = validatePositiveNumber(gas); | ||||
|       const bn = new BigNumber(gas); | ||||
| 
 | ||||
|       this.gas = gas; | ||||
| 
 | ||||
|       if (numberError) { | ||||
|         this.errorGas = numberError; | ||||
|       } else if (bn.gte(this.gasLimit)) { | ||||
|         this.errorGas = ERRORS.gasBlockLimit; | ||||
|       } else { | ||||
|         this.errorGas = null; | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   @action loadDefaults () { | ||||
|     Promise | ||||
|       .all([ | ||||
|         this._api.parity.gasPriceHistogram(), | ||||
|         this._api.eth.gasPrice() | ||||
|       ]) | ||||
|       .then(([gasPriceHistogram, gasPrice]) => { | ||||
|         transaction(() => { | ||||
|           this.setPrice(gasPrice.toFixed(0)); | ||||
|           this.setHistogram(gasPriceHistogram); | ||||
| 
 | ||||
|           this.priceDefault = gasPrice.toFixed(); | ||||
|         }); | ||||
|       }) | ||||
|       .catch((error) => { | ||||
|         console.warn('getDefaults', error); | ||||
|       }); | ||||
|   } | ||||
| } | ||||
| @ -20,7 +20,7 @@ import { connect } from 'react-redux'; | ||||
| import { bindActionCreators } from 'redux'; | ||||
| import { LinearProgress } from 'material-ui'; | ||||
| 
 | ||||
| import { txLink } from '../../3rdparty/etherscan/links'; | ||||
| import { txLink } from '~/3rdparty/etherscan/links'; | ||||
| import ShortenedHash from '../ShortenedHash'; | ||||
| 
 | ||||
| import styles from './txHash.css'; | ||||
|  | ||||
| @ -31,6 +31,7 @@ import CopyToClipboard from './CopyToClipboard'; | ||||
| import Editor from './Editor'; | ||||
| import Errors from './Errors'; | ||||
| import Form, { AddressSelect, FormWrap, TypedInput, Input, InputAddress, InputAddressSelect, InputChip, InputInline, Select, RadioButtons } from './Form'; | ||||
| import GasPriceEditor from './GasPriceEditor'; | ||||
| import IdentityIcon from './IdentityIcon'; | ||||
| import IdentityName from './IdentityName'; | ||||
| import Loading from './Loading'; | ||||
| @ -67,7 +68,7 @@ export { | ||||
|   Errors, | ||||
|   Form, | ||||
|   FormWrap, | ||||
|   TypedInput, | ||||
|   GasPriceEditor, | ||||
|   Input, | ||||
|   InputAddress, | ||||
|   InputAddressSelect, | ||||
| @ -91,5 +92,6 @@ export { | ||||
|   Tooltip, | ||||
|   Tooltips, | ||||
|   TxHash, | ||||
|   TxList | ||||
|   TxList, | ||||
|   TypedInput | ||||
| }; | ||||
|  | ||||
| @ -1,28 +0,0 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| 
 | ||||
| // Parity is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||
| // GNU General Public License for more details.
 | ||||
| 
 | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| const checkIfTxFailed = (api, tx, gasSent) => { | ||||
|   return api.pollMethod('eth_getTransactionReceipt', tx) | ||||
|   .then((receipt) => { | ||||
|     // TODO: Right now, there's no way to tell wether the EVM code crashed.
 | ||||
|     // Because you usually send a bit more gas than estimated (to make sure
 | ||||
|     // it gets mined quickly), we transaction probably failed if all the gas
 | ||||
|     // has been used up.
 | ||||
|     return receipt.gasUsed.eq(gasSent); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| export default checkIfTxFailed; | ||||
| @ -18,7 +18,18 @@ const isValidReceipt = (receipt) => { | ||||
|   return receipt && receipt.blockNumber && receipt.blockNumber.gt(0); | ||||
| }; | ||||
| 
 | ||||
| const waitForConfirmations = (api, tx, confirmations) => { | ||||
| export function checkIfTxFailed (api, tx, gasSent) { | ||||
|   return api.pollMethod('eth_getTransactionReceipt', tx) | ||||
|   .then((receipt) => { | ||||
|     // TODO: Right now, there's no way to tell wether the EVM code crashed.
 | ||||
|     // Because you usually send a bit more gas than estimated (to make sure
 | ||||
|     // it gets mined quickly), we transaction probably failed if all the gas
 | ||||
|     // has been used up.
 | ||||
|     return receipt.gasUsed.eq(gasSent); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| export function waitForConfirmations (api, tx, confirmations) { | ||||
|   return new Promise((resolve, reject) => { | ||||
|     api.pollMethod('eth_getTransactionReceipt', tx, isValidReceipt) | ||||
|     .then((receipt) => { | ||||
| @ -39,6 +50,4 @@ const waitForConfirmations = (api, tx, confirmations) => { | ||||
|       .catch(reject); | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| export default waitForConfirmations; | ||||
| } | ||||
| @ -20,6 +20,7 @@ import util from '~/api/util'; | ||||
| 
 | ||||
| export const ERRORS = { | ||||
|   invalidAddress: 'address is an invalid network address', | ||||
|   invalidAmount: 'the supplied amount should be a valid positive number', | ||||
|   duplicateAddress: 'the address is already in your address book', | ||||
|   invalidChecksum: 'address has failed the checksum formatting', | ||||
|   invalidName: 'name should not be blank and longer than 2', | ||||
| @ -27,7 +28,9 @@ export const ERRORS = { | ||||
|   invalidCode: 'code should be the compiled hex string', | ||||
|   invalidNumber: 'invalid number format', | ||||
|   negativeNumber: 'input number should be positive', | ||||
|   decimalNumber: 'input number should not contain decimals' | ||||
|   decimalNumber: 'input number should not contain decimals', | ||||
|   gasException: 'the transaction will throw an exception with the current values', | ||||
|   gasBlockLimit: 'the transaction execution will exceed the block gas limit' | ||||
| }; | ||||
| 
 | ||||
| export function validateAbi (abi, api) { | ||||
| @ -133,6 +136,25 @@ export function validateName (name) { | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| export function validatePositiveNumber (number) { | ||||
|   let numberError = null; | ||||
| 
 | ||||
|   try { | ||||
|     const v = new BigNumber(number); | ||||
| 
 | ||||
|     if (v.lt(0)) { | ||||
|       numberError = ERRORS.invalidAmount; | ||||
|     } | ||||
|   } catch (e) { | ||||
|     numberError = ERRORS.invalidAmount; | ||||
|   } | ||||
| 
 | ||||
|   return { | ||||
|     number, | ||||
|     numberError | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| export function validateUint (value) { | ||||
|   let valueError = null; | ||||
| 
 | ||||
|  | ||||
| @ -15,9 +15,6 @@ | ||||
| /* along with Parity.  If not, see <http://www.gnu.org/licenses/>. | ||||
| */ | ||||
| 
 | ||||
| .transactions { | ||||
| } | ||||
| 
 | ||||
| .infonone { | ||||
|   opacity: 0.25; | ||||
| } | ||||
|  | ||||
| @ -18,7 +18,7 @@ import React, { Component, PropTypes } from 'react'; | ||||
| import { connect } from 'react-redux'; | ||||
| import { bindActionCreators } from 'redux'; | ||||
| 
 | ||||
| import etherscan from '../../../3rdparty/etherscan'; | ||||
| import etherscan from '~/3rdparty/etherscan'; | ||||
| import { Container, TxList } from '~/ui'; | ||||
| 
 | ||||
| import styles from './transactions.css'; | ||||
|  | ||||
| @ -14,8 +14,6 @@ | ||||
| /* 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; | ||||
|  | ||||
| @ -105,7 +105,7 @@ class Account extends Component { | ||||
|     } | ||||
| 
 | ||||
|     return ( | ||||
|       <div className={ styles.account }> | ||||
|       <div> | ||||
|         { this.renderDeleteDialog(account) } | ||||
|         { this.renderEditDialog(account) } | ||||
|         { this.renderFundDialog() } | ||||
|  | ||||
| @ -14,6 +14,7 @@ | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| import BigNumber from 'bignumber.js'; | ||||
| import React, { Component, PropTypes } from 'react'; | ||||
| import { Link } from 'react-router'; | ||||
| import { isEqual } from 'lodash'; | ||||
| @ -113,15 +114,16 @@ export default class Summary extends Component { | ||||
| 
 | ||||
|   renderOwners () { | ||||
|     const { owners } = this.props; | ||||
|     const ownersValid = (owners || []).filter((owner) => owner.address && new BigNumber(owner.address).gt(0)); | ||||
| 
 | ||||
|     if (!owners || owners.length === 0) { | ||||
|     if (!ownersValid || ownersValid.length === 0) { | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     return ( | ||||
|       <div className={ styles.owners }> | ||||
|         { | ||||
|           owners.map((owner) => ( | ||||
|           ownersValid.map((owner) => ( | ||||
|             <div key={ owner.address }> | ||||
|               <div | ||||
|                 data-tip | ||||
|  | ||||
| @ -14,8 +14,6 @@ | ||||
| /* 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; | ||||
|  | ||||
| @ -82,7 +82,7 @@ class Accounts extends Component { | ||||
| 
 | ||||
|   render () { | ||||
|     return ( | ||||
|       <div className={ styles.accounts }> | ||||
|       <div> | ||||
|         { this.renderNewDialog() } | ||||
|         { this.renderNewWalletDialog() } | ||||
|         { this.renderActionbar() } | ||||
| @ -293,13 +293,17 @@ function mapStateToProps (state) { | ||||
| 
 | ||||
|   const walletsOwners = Object | ||||
|     .keys(walletsInfo) | ||||
|     .map((wallet) => ({ | ||||
|       owners: walletsInfo[wallet].owners.map((owner) => ({ | ||||
|         address: owner, | ||||
|         name: accountsInfo[owner] && accountsInfo[owner].name || owner | ||||
|       })), | ||||
|       address: wallet | ||||
|     })) | ||||
|     .map((wallet) => { | ||||
|       const owners = walletsInfo[wallet].owners || []; | ||||
| 
 | ||||
|       return { | ||||
|         owners: owners.map((owner) => ({ | ||||
|           address: owner, | ||||
|           name: accountsInfo[owner] && accountsInfo[owner].name || owner | ||||
|         })), | ||||
|         address: wallet | ||||
|       }; | ||||
|     }) | ||||
|     .reduce((walletsOwners, wallet) => { | ||||
|       walletsOwners[wallet.address] = wallet.owners; | ||||
|       return walletsOwners; | ||||
|  | ||||
| @ -14,37 +14,37 @@ | ||||
| /* 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 { | ||||
|   .hero { | ||||
|     padding-bottom: 1em; | ||||
|   } | ||||
| 
 | ||||
| .delete .info { | ||||
|   display: inline-block; | ||||
| } | ||||
|   .info { | ||||
|     display: inline-block; | ||||
|   } | ||||
| 
 | ||||
| .delete .icon { | ||||
|   display: inline-block; | ||||
| } | ||||
|   .icon { | ||||
|     display: inline-block; | ||||
|   } | ||||
| 
 | ||||
| .delete .nameinfo { | ||||
|   display: inline-block; | ||||
|   text-align: left; | ||||
| } | ||||
|   .nameinfo { | ||||
|     display: inline-block; | ||||
|     text-align: left; | ||||
|   } | ||||
| 
 | ||||
| .delete .header { | ||||
|   text-transform: uppercase; | ||||
|   font-size: 1.25em; | ||||
|   padding-bottom: 0.25em; | ||||
| } | ||||
|   .header { | ||||
|     text-transform: uppercase; | ||||
|     font-size: 1.25em; | ||||
|     padding-bottom: 0.25em; | ||||
|   } | ||||
| 
 | ||||
| .delete .address { | ||||
| } | ||||
|   .address { | ||||
|   } | ||||
| 
 | ||||
| .delete .description { | ||||
|   padding-top: 1em; | ||||
|   font-size: 0.75em; | ||||
|   color: #aaa; | ||||
|   .description { | ||||
|     padding-top: 1em; | ||||
|     font-size: 0.75em; | ||||
|     color: #aaa; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -28,8 +28,6 @@ import Transactions from '../Account/Transactions'; | ||||
| import Delete from './Delete'; | ||||
| import { setVisibleAccounts } from '~/redux/providers/personalActions'; | ||||
| 
 | ||||
| import styles from './address.css'; | ||||
| 
 | ||||
| class Address extends Component { | ||||
|   static contextTypes = { | ||||
|     api: PropTypes.object.isRequired, | ||||
| @ -85,7 +83,7 @@ class Address extends Component { | ||||
|     } | ||||
| 
 | ||||
|     return ( | ||||
|       <div className={ styles.address }> | ||||
|       <div> | ||||
|         { this.renderEditDialog(contact) } | ||||
|         { this.renderActionbar(contact) } | ||||
|         <Delete | ||||
|  | ||||
| @ -14,8 +14,6 @@ | ||||
| /* 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; | ||||
| @ -26,21 +24,21 @@ | ||||
|   flex: 0 1 50%; | ||||
|   width: 50%; | ||||
|   position: relative; | ||||
| } | ||||
| 
 | ||||
| .address:nth-child(odd)>div { | ||||
|   padding-right: 0.5em !important; | ||||
| } | ||||
|   &:nth-child(odd)>div { | ||||
|     padding-right: 0.5em !important; | ||||
|   } | ||||
| 
 | ||||
| .address:nth-child(even)>div { | ||||
|   padding-left: 0.5em !important; | ||||
|   &:nth-child(even)>div { | ||||
|     padding-left: 0.5em !important; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .empty { | ||||
|   width: 100%; | ||||
|   display: block; | ||||
| } | ||||
| 
 | ||||
| .empty div { | ||||
|   color: #aaa; | ||||
|   div { | ||||
|     color: #aaa; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -76,7 +76,7 @@ class Addresses extends Component { | ||||
|     const { searchValues, sortOrder } = this.state; | ||||
| 
 | ||||
|     return ( | ||||
|       <div className={ styles.addresses }> | ||||
|       <div> | ||||
|         { this.renderActionbar() } | ||||
|         { this.renderAddAddress() } | ||||
|         <Page> | ||||
|  | ||||
| @ -19,7 +19,6 @@ 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'; | ||||
| 
 | ||||
|  | ||||
| @ -20,7 +20,7 @@ import React, { Component, PropTypes } from 'react'; | ||||
| 
 | ||||
| import { IdentityIcon, IdentityName, Input, InputAddress } from '~/ui'; | ||||
| import ShortenedHash from '~/ui/ShortenedHash'; | ||||
| import { txLink } from '../../../../3rdparty/etherscan/links'; | ||||
| import { txLink } from '~/3rdparty/etherscan/links'; | ||||
| 
 | ||||
| import styles from '../../contract.css'; | ||||
| 
 | ||||
|  | ||||
| @ -15,26 +15,26 @@ | ||||
| /* along with Parity.  If not, see <http://www.gnu.org/licenses/>. | ||||
| */ | ||||
| 
 | ||||
| .contract { | ||||
| } | ||||
| 
 | ||||
| .events { | ||||
|   width: 100%; | ||||
|   border: none; | ||||
|   border-spacing: 0; | ||||
| } | ||||
| 
 | ||||
| .events tr { | ||||
|   line-height: 32px; | ||||
|   vertical-align: top; | ||||
|   tr { | ||||
|     line-height: 32px; | ||||
|     vertical-align: top; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .event { | ||||
| } | ||||
|   td { | ||||
|     vertical-align: top; | ||||
|     padding: 1em 0.5em; | ||||
| 
 | ||||
| .event td { | ||||
|   vertical-align: top; | ||||
|   padding: 1em 0.5em; | ||||
|     div { | ||||
|       white-space: nowrap; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .txhash { | ||||
| @ -47,10 +47,6 @@ | ||||
|   color: #aaa; | ||||
| } | ||||
| 
 | ||||
| .event td div { | ||||
|   white-space: nowrap; | ||||
| } | ||||
| 
 | ||||
| .mined { | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -124,7 +124,7 @@ class Contract extends Component { | ||||
|     } | ||||
| 
 | ||||
|     return ( | ||||
|       <div className={ styles.contract }> | ||||
|       <div> | ||||
|         { this.renderActionbar(account) } | ||||
|         { this.renderDeleteDialog(account) } | ||||
|         { this.renderEditDialog(account) } | ||||
|  | ||||
| @ -1,18 +0,0 @@ | ||||
| /* 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 { | ||||
| } | ||||
| @ -28,8 +28,6 @@ import { setVisibleAccounts } from '~/redux/providers/personalActions'; | ||||
| 
 | ||||
| import List from '../Accounts/List'; | ||||
| 
 | ||||
| import styles from './contracts.css'; | ||||
| 
 | ||||
| class Contracts extends Component { | ||||
|   static contextTypes = { | ||||
|     api: PropTypes.object.isRequired | ||||
| @ -80,7 +78,7 @@ class Contracts extends Component { | ||||
|     const { searchValues, sortOrder } = this.state; | ||||
| 
 | ||||
|     return ( | ||||
|       <div className={ styles.contracts }> | ||||
|       <div> | ||||
|         { this.renderActionbar() } | ||||
|         { this.renderAddContract() } | ||||
|         { this.renderAddContract() } | ||||
| @ -159,7 +157,6 @@ class Contracts extends Component { | ||||
| 
 | ||||
|     return ( | ||||
|       <Actionbar | ||||
|         className={ styles.toolbar } | ||||
|         title='Contracts' | ||||
|         buttons={ buttons } /> | ||||
|     ); | ||||
|  | ||||
| @ -15,9 +15,6 @@ | ||||
| /* along with Parity.  If not, see <http://www.gnu.org/licenses/>. | ||||
| */ | ||||
| 
 | ||||
| .layout { | ||||
| } | ||||
| 
 | ||||
| .menu { | ||||
|   display: inline-block; | ||||
| } | ||||
| @ -35,31 +32,24 @@ | ||||
|   padding: 16px 2em !important; | ||||
|   line-height: 24px !important; | ||||
|   width: auto !important; | ||||
| } | ||||
| 
 | ||||
| .tabactive { | ||||
| } | ||||
|   &>div { | ||||
|     height: 24px !important; | ||||
| 
 | ||||
| .tab>div, | ||||
| .tabactive>div { | ||||
|   height: 24px !important; | ||||
| } | ||||
|     &>div { | ||||
|       display: inline-block !important; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| .tab>div>div, | ||||
| .tabactive>div>div { | ||||
|   display: inline-block !important; | ||||
| } | ||||
|   svg { | ||||
|     margin-right: 0.5em; | ||||
|     margin-bottom: 0 !important; | ||||
|   } | ||||
| 
 | ||||
| .tab svg, | ||||
| .tabactive svg { | ||||
|   margin-right: 0.5em; | ||||
|   margin-bottom: 0 !important; | ||||
| } | ||||
| 
 | ||||
| .tab .menu, | ||||
| .tabactive .menu { | ||||
|   vertical-align: top; | ||||
|   display: inline-block; | ||||
|   .menu { | ||||
|     vertical-align: top; | ||||
|     display: inline-block; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .imageIcon { | ||||
| @ -68,6 +58,8 @@ | ||||
|   opacity: 0.5; | ||||
| } | ||||
| 
 | ||||
| .tabactive .imageIcon { | ||||
|   opacity: 1; | ||||
| .tabactive { | ||||
|   .imageIcon { | ||||
|     opacity: 1; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -45,7 +45,7 @@ export default class Settings extends Component { | ||||
|     } | ||||
| 
 | ||||
|     return ( | ||||
|       <div className={ styles.layout }> | ||||
|       <div> | ||||
|         <Actionbar title='settings' className={ styles.bar }> | ||||
|           <Tabs className={ styles.tabs } value={ hash }> | ||||
|             { this.renderTab(hash, 'views', <ImageRemoveRedEye />) } | ||||
|  | ||||
| @ -16,7 +16,7 @@ | ||||
| 
 | ||||
| import React, { Component, PropTypes } from 'react'; | ||||
| 
 | ||||
| import { addressLink } from '../../../../../3rdparty/etherscan/links'; | ||||
| import { addressLink } from '~/3rdparty/etherscan/links'; | ||||
| import styles from './AccountLink.css'; | ||||
| 
 | ||||
| export default class AccountLink extends Component { | ||||
|  | ||||
| @ -16,7 +16,7 @@ | ||||
| 
 | ||||
| import React, { Component, PropTypes } from 'react'; | ||||
| 
 | ||||
| import { txLink } from '../../../../3rdparty/etherscan/links'; | ||||
| import { txLink } from '~/3rdparty/etherscan/links'; | ||||
| 
 | ||||
| export default class TxHashLink extends Component { | ||||
| 
 | ||||
|  | ||||
| @ -23,9 +23,6 @@ | ||||
|   width: $embedWidth; | ||||
| } | ||||
| 
 | ||||
| .pending { | ||||
| } | ||||
| 
 | ||||
| .none { | ||||
|   color: #aaa; | ||||
| } | ||||
|  | ||||
| @ -71,7 +71,7 @@ class Embedded extends Component { | ||||
|     const items = pending.sort(this._sortRequests).map(this.renderPending); | ||||
| 
 | ||||
|     return ( | ||||
|       <div className={ styles.pending }> | ||||
|       <div> | ||||
|         { items } | ||||
|       </div> | ||||
|     ); | ||||
|  | ||||
| @ -15,12 +15,6 @@ | ||||
| /* along with Parity.  If not, see <http://www.gnu.org/licenses/>. | ||||
| */ | ||||
| 
 | ||||
| .request { | ||||
| } | ||||
| 
 | ||||
| .noRequestsMsg { | ||||
|   color: #aaa; | ||||
| } | ||||
| 
 | ||||
| .items { | ||||
| } | ||||
|  | ||||
| @ -98,9 +98,7 @@ class RequestsPage extends Component { | ||||
| 
 | ||||
|     return ( | ||||
|       <Container title='Pending Requests'> | ||||
|         <div className={ styles.items }> | ||||
|           { items } | ||||
|         </div> | ||||
|         { items } | ||||
|       </Container> | ||||
|     ); | ||||
|   } | ||||
| @ -111,7 +109,6 @@ class RequestsPage extends Component { | ||||
| 
 | ||||
|     return ( | ||||
|       <RequestPending | ||||
|         className={ styles.request } | ||||
|         onConfirm={ actions.startConfirmRequest } | ||||
|         onReject={ actions.startRejectRequest } | ||||
|         isSending={ isSending || false } | ||||
|  | ||||
| @ -19,12 +19,10 @@ import React, { Component } from 'react'; | ||||
| import { Actionbar } from '~/ui'; | ||||
| import RequestsPage from './containers/RequestsPage'; | ||||
| 
 | ||||
| import styles from './signer.css'; | ||||
| 
 | ||||
| export default class Signer extends Component { | ||||
|   render () { | ||||
|     return ( | ||||
|       <div className={ styles.signer }> | ||||
|       <div> | ||||
|         <Actionbar | ||||
|           title='Trusted Signer' /> | ||||
|         <RequestsPage /> | ||||
|  | ||||
| @ -23,8 +23,6 @@ import { clearStatusLogs, toggleStatusLogs, toggleStatusRefresh } from '~/redux/ | ||||
| import Debug from '../../components/Debug'; | ||||
| import Status from '../../components/Status'; | ||||
| 
 | ||||
| import styles from './statusPage.css'; | ||||
| 
 | ||||
| class StatusPage extends Component { | ||||
|   static propTypes = { | ||||
|     nodeStatus: PropTypes.object.isRequired, | ||||
| @ -41,7 +39,7 @@ class StatusPage extends Component { | ||||
| 
 | ||||
|   render () { | ||||
|     return ( | ||||
|       <div className={ styles.body }> | ||||
|       <div> | ||||
|         <Status { ...this.props } /> | ||||
|         <Debug { ...this.props } /> | ||||
|       </div> | ||||
|  | ||||
| @ -1,18 +0,0 @@ | ||||
| /* 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/>. | ||||
| */ | ||||
| .body { | ||||
| } | ||||
| @ -23,7 +23,7 @@ import { bindActionCreators } from 'redux'; | ||||
| import { confirmOperation, revokeOperation } from '~/redux/providers/walletActions'; | ||||
| import { bytesToHex } from '~/api/util/format'; | ||||
| import { Container, InputAddress, Button, IdentityIcon } from '~/ui'; | ||||
| import { TxRow } from '~/ui/TxList/txList'; | ||||
| import TxRow from '~/ui/TxList/TxRow'; | ||||
| 
 | ||||
| import styles from '../wallet.css'; | ||||
| import txListStyles from '~/ui/TxList/txList.css'; | ||||
|  | ||||
| @ -18,7 +18,7 @@ import React, { Component, PropTypes } from 'react'; | ||||
| 
 | ||||
| import { bytesToHex } from '~/api/util/format'; | ||||
| import { Container } from '~/ui'; | ||||
| import { TxRow } from '~/ui/TxList/txList'; | ||||
| import TxRow from '~/ui/TxList/TxRow'; | ||||
| 
 | ||||
| import txListStyles from '~/ui/TxList/txList.css'; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user