From 860d6c01ed3f0ac06cb1aa24a74f8e614c736bd5 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 10 May 2017 14:41:52 +0200 Subject: [PATCH 1/8] Set block condition to BigNumber in MethodDecoding (#5592) * Set block condition to BigNumber in MethodDecoding * Add gt(0) --- js/src/ui/MethodDecoding/methodDecoding.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/js/src/ui/MethodDecoding/methodDecoding.js b/js/src/ui/MethodDecoding/methodDecoding.js index d143cd267..eb42a8bff 100644 --- a/js/src/ui/MethodDecoding/methodDecoding.js +++ b/js/src/ui/MethodDecoding/methodDecoding.js @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +import BigNumber from 'bignumber.js'; import { CircularProgress } from 'material-ui'; import moment from 'moment'; import React, { Component, PropTypes } from 'react'; @@ -177,10 +178,12 @@ class MethodDecoding extends Component { return null; } - if (condition.block && condition.block.gt(0)) { + const blockCondition = new BigNumber(condition.block || 0); + + if (blockCondition.gt(0)) { const blockNumber = ( - #{ condition.block.toFormat(0) } + #{ blockCondition.toFormat(0) } ); From 076b602343ea180a27432a5fc4f35a3da067d470 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 10 May 2017 14:42:26 +0200 Subject: [PATCH 2/8] Update registry middleware (#5585) --- js/src/redux/middleware.js | 2 +- js/src/redux/providers/registry/middleware.js | 206 ++++++++++-------- 2 files changed, 111 insertions(+), 97 deletions(-) diff --git a/js/src/redux/middleware.js b/js/src/redux/middleware.js index 9cc413dc0..f83251f51 100644 --- a/js/src/redux/middleware.js +++ b/js/src/redux/middleware.js @@ -38,7 +38,7 @@ export default function (api, browserHistory, forEmbed = false) { if (!forEmbed) { const certifications = new CertificationsMiddleware().toMiddleware(); - const registry = new RegistryMiddleware(api); + const registry = new RegistryMiddleware(api).toMiddleware(); middleware.push(certifications, registry); } diff --git a/js/src/redux/providers/registry/middleware.js b/js/src/redux/providers/registry/middleware.js index c6c961765..eebbe9d14 100644 --- a/js/src/redux/providers/registry/middleware.js +++ b/js/src/redux/providers/registry/middleware.js @@ -15,7 +15,7 @@ // along with Parity. If not, see . import { debounce } from 'lodash'; -import store from 'store'; +import lsstore from 'store'; import Contracts from '~/contracts'; import subscribeToEvents from '~/util/subscribe-to-events'; @@ -25,126 +25,140 @@ import { setReverse, startCachingReverses } from './actions'; const STORE_KEY = '_parity::reverses'; -const read = (chain) => { - const reverses = store.get(`${STORE_KEY}::${chain}::data`); - const lastBlock = store.get(`${STORE_KEY}::${chain}::lastBlock`); +export default class RegistryMiddleware { + contract; + interval; + store; + subscription; + timeout; - if (!reverses || !lastBlock) { - return null; + addressesToCheck = {}; + + constructor (api) { + this._api = api; } - return { reverses, lastBlock }; -}; -const write = debounce((getChain, getReverses, getLastBlock) => { - const chain = getChain(); - const reverses = getReverses(); - const lastBlock = getLastBlock(); + toMiddleware () { + return (store) => { + this.store = store; - store.set(`${STORE_KEY}::${chain}::data`, reverses); - store.set(`${STORE_KEY}::${chain}::lastBlock`, lastBlock); -}, 20000); + return (next) => (action) => { + switch (action.type) { + case 'initAll': + next(action); + store.dispatch(startCachingReverses()); + break; -export default (api) => (store) => { - let contract; - let subscription; - let timeout; - let interval; + case 'startCachingReverses': + this.cacheReverses(); + break; - let addressesToCheck = {}; + case 'stopCachingReverses': + if (this.subscription) { + this.subscription.unsubscribe(); + } + if (this.interval) { + clearInterval(this.interval); + } + if (this.timeout) { + clearTimeout(this.timeout); + } - const onLog = (log) => { - switch (log.event) { - case 'ReverseConfirmed': - addressesToCheck[log.params.reverse.value] = true; + this.write.flush(); + break; - break; - case 'ReverseRemoved': - delete addressesToCheck[log.params.reverse.value]; + case 'setReverse': + this.write( + () => store.getState().nodeStatus.netChain, + () => store.getState().registry.reverse, + () => +store.getState().nodeStatus.blockNumber + ); + next(action); + break; - break; + default: + next(action); + } + }; + }; + } + + cacheReverses () { + const { registry } = Contracts.get(); + const cached = this.read(this.store.getState().nodeStatus.netChain); + + if (cached) { + Object + .entries(cached.reverses) + .forEach(([ address, reverse ]) => this.store.dispatch(setReverse(address, reverse))); } - }; - const checkReverses = () => { + registry.getInstance() + .then((instance) => this._api.newContract(registryABI, instance.address)) + .then((_contract) => { + this.contract = _contract; + + this.subscription = subscribeToEvents(this.contract, [ + 'ReverseConfirmed', 'ReverseRemoved' + ], { + from: cached ? cached.lastBlock : 0 + }); + this.subscription.on('log', this.onLog); + + this.timeout = setTimeout(this.checkReverses, 10000); + this.interval = setInterval(this.checkReverses, 20000); + }) + .catch((err) => { + console.error('Failed to start caching reverses:', err); + throw err; + }); + } + + checkReverses = () => { Object - .keys(addressesToCheck) + .keys(this.addressesToCheck) .forEach((address) => { - contract + this.contract .instance .reverse .call({}, [ address ]) .then((reverse) => { - store.dispatch(setReverse(address, reverse)); + this.store.dispatch(setReverse(address, reverse)); }); }); - addressesToCheck = {}; + this.addressesToCheck = {}; }; - return (next) => (action) => { - switch (action.type) { - case 'initAll': - next(action); - store.dispatch(startCachingReverses()); + onLog = (log) => { + switch (log.event) { + case 'ReverseConfirmed': + this.addressesToCheck[log.params.reverse.value] = true; break; - - case 'startCachingReverses': - const { registry } = Contracts.get(); - const cached = read(store.getState().nodeStatus.netChain); - - if (cached) { - Object - .entries(cached.reverses) - .forEach(([ address, reverse ]) => store.dispatch(setReverse(address, reverse))); - } - - registry.getInstance() - .then((instance) => api.newContract(registryABI, instance.address)) - .then((_contract) => { - contract = _contract; - - subscription = subscribeToEvents(_contract, [ - 'ReverseConfirmed', 'ReverseRemoved' - ], { - from: cached ? cached.lastBlock : 0 - }); - subscription.on('log', onLog); - - timeout = setTimeout(checkReverses, 10000); - interval = setInterval(checkReverses, 20000); - }) - .catch((err) => { - console.error('Failed to start caching reverses:', err); - throw err; - }); + case 'ReverseRemoved': + delete this.addressesToCheck[log.params.reverse.value]; break; - case 'stopCachingReverses': - if (subscription) { - subscription.unsubscribe(); - } - if (interval) { - clearInterval(interval); - } - if (timeout) { - clearTimeout(timeout); - } - - write.flush(); - break; - - case 'setReverse': - write( - () => store.getState().nodeStatus.netChain, - () => store.getState().registry.reverse, - () => +store.getState().nodeStatus.blockNumber - ); - next(action); - break; - - default: - next(action); } }; -}; + + read = (chain) => { + const reverses = lsstore.get(`${STORE_KEY}::${chain}::data`); + const lastBlock = lsstore.get(`${STORE_KEY}::${chain}::lastBlock`); + + if (!reverses || !lastBlock) { + return null; + } + return { reverses, lastBlock }; + }; + + write = debounce((getChain, getReverses, getLastBlock) => { + const chain = getChain(); + const reverses = getReverses(); + const lastBlock = getLastBlock(); + + lsstore.set(`${STORE_KEY}::${chain}::data`, reverses); + lsstore.set(`${STORE_KEY}::${chain}::lastBlock`, lastBlock); + }, 20000); +} From 5baccafb23644fc33018b182633043fb8e6ab903 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 10 May 2017 15:02:47 +0200 Subject: [PATCH 3/8] Add a warning when node is syncing (#5565) * Add a warning when node is syncing * Linting * Linting * PR Grumbles --- js/src/redux/providers/balances.js | 2 +- js/src/redux/providers/statusReducer.js | 2 +- js/src/views/Application/application.js | 7 + js/src/views/SyncWarning/index.js | 17 +++ js/src/views/SyncWarning/syncWarning.css | 60 +++++++++ js/src/views/SyncWarning/syncWarning.js | 130 +++++++++++++++++++ js/src/views/SyncWarning/syncWarning.spec.js | 57 ++++++++ 7 files changed, 273 insertions(+), 2 deletions(-) create mode 100644 js/src/views/SyncWarning/index.js create mode 100644 js/src/views/SyncWarning/syncWarning.css create mode 100644 js/src/views/SyncWarning/syncWarning.js create mode 100644 js/src/views/SyncWarning/syncWarning.spec.js diff --git a/js/src/redux/providers/balances.js b/js/src/redux/providers/balances.js index cc7df73dd..a2f49cfa8 100644 --- a/js/src/redux/providers/balances.js +++ b/js/src/redux/providers/balances.js @@ -241,7 +241,7 @@ export default class Balances { // If syncing, only retrieve balances once every // few seconds - if (syncing) { + if (syncing || syncing === null) { this.shortThrottledFetch.cancel(); this.longThrottledFetch(skipNotifications); diff --git a/js/src/redux/providers/statusReducer.js b/js/src/redux/providers/statusReducer.js index 12fe9654d..3a6968548 100644 --- a/js/src/redux/providers/statusReducer.js +++ b/js/src/redux/providers/statusReducer.js @@ -33,7 +33,7 @@ const initialState = { netVersion: '0', nodeKind: null, nodeKindFull: null, - syncing: true, + syncing: null, isConnected: false, isConnecting: false, isTest: undefined, diff --git a/js/src/views/Application/application.js b/js/src/views/Application/application.js index 2fac18c6f..73f0cdda8 100644 --- a/js/src/views/Application/application.js +++ b/js/src/views/Application/application.js @@ -22,6 +22,7 @@ import UpgradeStore from '~/modals/UpgradeParity/store'; import Connection from '../Connection'; import ParityBar from '../ParityBar'; +import SyncWarning, { showSyncWarning } from '../SyncWarning'; import Snackbar from './Snackbar'; import Container from './Container'; @@ -36,6 +37,7 @@ import Requests from './Requests'; import styles from './application.css'; const inFrame = window.parent !== window && window.parent.frames.length !== 0; +const doShowSyncWarning = showSyncWarning(); @observer class Application extends Component { @@ -78,6 +80,11 @@ class Application extends Component { ? this.renderMinimized() : this.renderApp() } + { + doShowSyncWarning + ? () + : null + } diff --git a/js/src/views/SyncWarning/index.js b/js/src/views/SyncWarning/index.js new file mode 100644 index 000000000..098605b2a --- /dev/null +++ b/js/src/views/SyncWarning/index.js @@ -0,0 +1,17 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default, { showSyncWarning } from './syncWarning'; diff --git a/js/src/views/SyncWarning/syncWarning.css b/js/src/views/SyncWarning/syncWarning.css new file mode 100644 index 000000000..828036499 --- /dev/null +++ b/js/src/views/SyncWarning/syncWarning.css @@ -0,0 +1,60 @@ +/* Copyright 2015-2017 Parity Technologies (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation; either version 3 of the License; or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful; +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not; see . +*/ + +.overlay { + background: rgba(255, 255, 255, 0.75); + bottom: 0; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 10000; +} + +.modal { + align-items: flex-start; + bottom: 0; + display: flex; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 10001; +} + +.body { + background: rgba(25, 25, 25, 0.75); + box-shadow: rgba(0, 0, 0, 0.25) 0 14px 45px, rgba(0, 0, 0, 0.22) 0 10px 18px; + color: rgb(208, 208, 208); + display: flex; + flex-direction: column; + margin: 0 auto; + max-width: 20em; + padding: 2em 4em; + text-align: center; +} + +.button { + margin-top: 1em; +} + +.body, +.button { + > * { + margin: 0.5em 0; + } +} diff --git a/js/src/views/SyncWarning/syncWarning.js b/js/src/views/SyncWarning/syncWarning.js new file mode 100644 index 000000000..67deff075 --- /dev/null +++ b/js/src/views/SyncWarning/syncWarning.js @@ -0,0 +1,130 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import { Checkbox } from 'material-ui'; +import React, { Component, PropTypes } from 'react'; +import { FormattedMessage } from 'react-intl'; +import { connect } from 'react-redux'; +import store from 'store'; + +import { Button } from '~/ui'; + +import styles from './syncWarning.css'; + +const LS_DONT_SHOW_AGAIN = '_parity::syncWarning::dontShowAgain'; + +export const showSyncWarning = () => { + const dontShowAgain = store.get(LS_DONT_SHOW_AGAIN); + + if (dontShowAgain === undefined || dontShowAgain === null) { + return true; + } + + return !dontShowAgain; +}; + +class SyncWarning extends Component { + static propTypes = { + isSyncing: PropTypes.bool + }; + + state = { + dontShowAgain: false, + show: true + }; + + render () { + const { isSyncing } = this.props; + const { dontShowAgain, show } = this.state; + + if (!isSyncing || isSyncing === null || !show) { + return null; + } + + return ( +
+
+
+
+ + + +
+ + } + checked={ dontShowAgain } + onCheck={ this.handleCheck } + /> +
+
+
+
+ ); + } + + handleCheck = () => { + this.setState({ dontShowAgain: !this.state.dontShowAgain }); + } + + handleAgreeClick = () => { + if (this.state.dontShowAgain) { + store.set(LS_DONT_SHOW_AGAIN, true); + } + + this.setState({ show: false }); + } +} + +function mapStateToProps (state) { + const { syncing } = state.nodeStatus; + // syncing could be an Object, false, or null + const isSyncing = syncing + ? true + : syncing; + + return { + isSyncing + }; +} + +export default connect( + mapStateToProps, + null +)(SyncWarning); diff --git a/js/src/views/SyncWarning/syncWarning.spec.js b/js/src/views/SyncWarning/syncWarning.spec.js new file mode 100644 index 000000000..36c3c2436 --- /dev/null +++ b/js/src/views/SyncWarning/syncWarning.spec.js @@ -0,0 +1,57 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import { shallow } from 'enzyme'; +import React from 'react'; + +import SyncWarning from './'; + +let component; + +function createRedux (syncing = null) { + return { + getState: () => { + return { + nodeStatus: { + syncing + } + }; + } + }; +} + +function render (store) { + component = shallow( + , + { context: { store: store || createRedux() } } + ).find('SyncWarning').shallow(); + + return component; +} + +describe('views/SyncWarning', () => { + it('renders defaults', () => { + expect(render()).to.be.ok; + }); + + it('does render when syncing', () => { + expect(render(createRedux({})).find('div')).to.have.length.gte(1); + }); + + it('does not render when not syncing', () => { + expect(render(createRedux(false)).find('div')).to.have.length(0); + }); +}); From c58c253cbf491826bab2906e4feb01c54c367c19 Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Wed, 10 May 2017 13:17:46 +0000 Subject: [PATCH 4/8] [ci skip] js-precompiled 20170510-131400 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 472e11fe5..18dcc7ab8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1781,7 +1781,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/paritytech/js-precompiled.git#cff0aec1877a4b75f51de3facee9fe439a41a90d" +source = "git+https://github.com/paritytech/js-precompiled.git#d00be5ab7f4338b14b95fbdac29097b9f9fa0848" dependencies = [ "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index 61f239cbd..3188163fd 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "1.7.70", + "version": "1.7.71", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From 0a16c350d150f4a0cdcc10ca7d356ef5242a03d6 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 10 May 2017 15:24:24 +0200 Subject: [PATCH 5/8] Can't deploy without compiling Contract (#5593) --- js/src/views/WriteContract/writeContract.js | 3 ++- .../views/WriteContract/writeContractStore.js | 20 ++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/js/src/views/WriteContract/writeContract.js b/js/src/views/WriteContract/writeContract.js index df5ade348..634804c9c 100644 --- a/js/src/views/WriteContract/writeContract.js +++ b/js/src/views/WriteContract/writeContract.js @@ -345,12 +345,13 @@ class WriteContract extends Component { } onClick={ this.store.handleCompile } primary={ false } - disabled={ compiling } + disabled={ compiling || this.store.isPristine } /> { contract ? (