Cleanup the Status View (#5317)
* Better view of Settings and Mining Settings * Cleanup Status view * Node Logs refactoring * Cleanup Status * Move RPC Calls files * Basic Peers view * Add Peers table * style table header
This commit is contained in:
parent
8930f510fc
commit
5fa088114c
@ -17,16 +17,14 @@
|
||||
import { newError } from '~/ui/Errors/actions';
|
||||
import { setAddressImage } from './providers/imagesActions';
|
||||
import { openSnackbar, showSnackbar } from './providers/snackbarActions';
|
||||
import { clearStatusLogs, toggleStatusLogs, toggleStatusRefresh } from './providers/statusActions';
|
||||
import { toggleStatusRefresh } from './providers/statusActions';
|
||||
import { toggleView } from '~/views/Settings/actions';
|
||||
|
||||
export {
|
||||
newError,
|
||||
clearStatusLogs,
|
||||
setAddressImage,
|
||||
openSnackbar,
|
||||
showSnackbar,
|
||||
toggleStatusLogs,
|
||||
toggleStatusRefresh,
|
||||
toggleView
|
||||
};
|
||||
|
@ -20,7 +20,6 @@ import ErrorsMiddleware from '~/ui/Errors/middleware';
|
||||
import SettingsMiddleware from '~/views/Settings/middleware';
|
||||
import SignerMiddleware from './providers/signerMiddleware';
|
||||
|
||||
import statusMiddleware from '~/views/Status/middleware';
|
||||
import CertificationsMiddleware from './providers/certifications/middleware';
|
||||
import ChainMiddleware from './providers/chainMiddleware';
|
||||
import RegistryMiddleware from './providers/registry/middleware';
|
||||
@ -44,8 +43,7 @@ export default function (api, browserHistory, forEmbed = false) {
|
||||
middleware.push(certifications, registry);
|
||||
}
|
||||
|
||||
const status = statusMiddleware();
|
||||
const routeMiddleware = browserHistory ? routerMiddleware(browserHistory) : [];
|
||||
|
||||
return middleware.concat(status, routeMiddleware, thunk);
|
||||
return middleware.concat(routeMiddleware, thunk);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import { LOG_KEYS, getLogger } from '~/config';
|
||||
import UpgradeStore from '~/modals/UpgradeParity/store';
|
||||
|
||||
import BalancesProvider from './balances';
|
||||
import { statusBlockNumber, statusCollection, statusLogs } from './statusActions';
|
||||
import { statusBlockNumber, statusCollection } from './statusActions';
|
||||
|
||||
const log = getLogger(LOG_KEYS.Signer);
|
||||
let instance = null;
|
||||
@ -59,6 +59,14 @@ export default class Status {
|
||||
return instance;
|
||||
}
|
||||
|
||||
static get () {
|
||||
if (!instance) {
|
||||
throw new Error('The Status Provider has not been initialized yet');
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
start () {
|
||||
log.debug('status::start');
|
||||
|
||||
@ -66,7 +74,6 @@ export default class Status {
|
||||
.all([
|
||||
this._subscribeBlockNumber(),
|
||||
|
||||
this._pollLogs(),
|
||||
this._pollLongStatus(),
|
||||
this._pollStatus()
|
||||
])
|
||||
@ -187,25 +194,12 @@ export default class Status {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const { refreshStatus } = this._store.getState().nodeStatus;
|
||||
|
||||
const statusPromises = [ this._api.eth.syncing() ];
|
||||
|
||||
if (refreshStatus) {
|
||||
statusPromises.push(this._api.parity.netPeers());
|
||||
statusPromises.push(this._api.eth.hashrate());
|
||||
}
|
||||
const statusPromises = [ this._api.eth.syncing(), this._api.parity.netPeers() ];
|
||||
|
||||
return Promise
|
||||
.all(statusPromises)
|
||||
.then(([ syncing, ...statusResults ]) => {
|
||||
const status = statusResults.length === 0
|
||||
? { syncing }
|
||||
: {
|
||||
syncing,
|
||||
netPeers: statusResults[0],
|
||||
hashrate: statusResults[1]
|
||||
};
|
||||
.then(([ syncing, netPeers ]) => {
|
||||
const status = { netPeers, syncing };
|
||||
|
||||
if (!isEqual(status, this._status)) {
|
||||
this._store.dispatch(statusCollection(status));
|
||||
@ -220,39 +214,6 @@ export default class Status {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Miner settings should never changes unless
|
||||
* Parity is restarted, or if the values are changed
|
||||
* from the UI
|
||||
*/
|
||||
_pollMinerSettings = () => {
|
||||
return Promise
|
||||
.all([
|
||||
this._api.eth.coinbase(),
|
||||
this._api.parity.extraData(),
|
||||
this._api.parity.minGasPrice(),
|
||||
this._api.parity.gasFloorTarget()
|
||||
])
|
||||
.then(([
|
||||
coinbase, extraData, minGasPrice, gasFloorTarget
|
||||
]) => {
|
||||
const minerSettings = {
|
||||
coinbase,
|
||||
extraData,
|
||||
minGasPrice,
|
||||
gasFloorTarget
|
||||
};
|
||||
|
||||
if (!isEqual(minerSettings, this._minerSettings)) {
|
||||
this._store.dispatch(statusCollection(minerSettings));
|
||||
this._minerSettings = minerSettings;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('_pollMinerSettings', error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The data fetched here should not change
|
||||
* unless Parity is restarted. They are thus
|
||||
@ -272,23 +233,16 @@ export default class Status {
|
||||
this._timeoutIds.longStatus = setTimeout(() => this._pollLongStatus(), timeout);
|
||||
};
|
||||
|
||||
// Poll Miner settings just in case
|
||||
const minerPromise = this._pollMinerSettings();
|
||||
|
||||
const mainPromise = Promise
|
||||
return Promise
|
||||
.all([
|
||||
this._api.parity.netPeers(),
|
||||
this._api.web3.clientVersion(),
|
||||
this._api.net.version(),
|
||||
this._api.parity.defaultExtraData(),
|
||||
this._api.parity.netChain(),
|
||||
this._api.parity.netPort(),
|
||||
this._api.parity.rpcSettings(),
|
||||
this._api.parity.enode().then((enode) => enode).catch(() => '-'),
|
||||
this._upgradeStore.checkUpgrade()
|
||||
])
|
||||
.then(([
|
||||
netPeers, clientVersion, netVersion, defaultExtraData, netChain, netPort, rpcSettings, enode, upgradeStatus
|
||||
netPeers, clientVersion, netVersion, netChain, upgradeStatus
|
||||
]) => {
|
||||
const isTest = [
|
||||
'2', // morden
|
||||
@ -299,13 +253,9 @@ export default class Status {
|
||||
const longStatus = {
|
||||
netPeers,
|
||||
clientVersion,
|
||||
defaultExtraData,
|
||||
netChain,
|
||||
netPort,
|
||||
netVersion,
|
||||
rpcSettings,
|
||||
isTest,
|
||||
enode
|
||||
isTest
|
||||
};
|
||||
|
||||
if (!isEqual(longStatus, this._longStatus)) {
|
||||
@ -319,42 +269,5 @@ export default class Status {
|
||||
.then(() => {
|
||||
nextTimeout(60000);
|
||||
});
|
||||
|
||||
return Promise.all([ minerPromise, mainPromise ]);
|
||||
}
|
||||
|
||||
_pollLogs = () => {
|
||||
const nextTimeout = (timeout = 1000) => {
|
||||
if (this._timeoutIds.logs) {
|
||||
clearTimeout(this._timeoutIds.logs);
|
||||
}
|
||||
|
||||
this._timeoutIds.logs = setTimeout(this._pollLogs, timeout);
|
||||
};
|
||||
|
||||
const { devLogsEnabled } = this._store.getState().nodeStatus;
|
||||
|
||||
if (!devLogsEnabled) {
|
||||
nextTimeout();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise
|
||||
.all([
|
||||
this._api.parity.devLogs(),
|
||||
this._api.parity.devLogsLevels()
|
||||
])
|
||||
.then(([devLogs, devLogsLevels]) => {
|
||||
this._store.dispatch(statusLogs({
|
||||
devLogs: devLogs.slice(-1024),
|
||||
devLogsLevels
|
||||
}));
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('_pollLogs', error);
|
||||
})
|
||||
.then(() => {
|
||||
return nextTimeout();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -27,30 +27,3 @@ export function statusCollection (collection) {
|
||||
collection
|
||||
};
|
||||
}
|
||||
|
||||
export function statusLogs (logInfo) {
|
||||
return {
|
||||
type: 'statusLogs',
|
||||
logInfo
|
||||
};
|
||||
}
|
||||
|
||||
export function toggleStatusLogs (devLogsEnabled) {
|
||||
return {
|
||||
type: 'toggleStatusLogs',
|
||||
devLogsEnabled
|
||||
};
|
||||
}
|
||||
|
||||
export function clearStatusLogs () {
|
||||
return {
|
||||
type: 'clearStatusLogs'
|
||||
};
|
||||
}
|
||||
|
||||
export function toggleStatusRefresh (refreshStatus) {
|
||||
return {
|
||||
type: 'toggleStatusRefresh',
|
||||
refreshStatus
|
||||
};
|
||||
}
|
||||
|
@ -21,32 +21,20 @@ const DEFAULT_NETCHAIN = '(unknown)';
|
||||
const initialState = {
|
||||
blockNumber: new BigNumber(0),
|
||||
blockTimestamp: new Date(),
|
||||
devLogs: [],
|
||||
devLogsLevels: null,
|
||||
devLogsEnabled: false,
|
||||
clientVersion: '',
|
||||
coinbase: '',
|
||||
defaultExtraData: '',
|
||||
enode: '',
|
||||
extraData: '',
|
||||
gasFloorTarget: new BigNumber(0),
|
||||
gasLimit: new BigNumber(0),
|
||||
hashrate: new BigNumber(0),
|
||||
minGasPrice: new BigNumber(0),
|
||||
netChain: DEFAULT_NETCHAIN,
|
||||
netPeers: {
|
||||
active: new BigNumber(0),
|
||||
connected: new BigNumber(0),
|
||||
max: new BigNumber(0)
|
||||
max: new BigNumber(0),
|
||||
peers: []
|
||||
},
|
||||
netPort: new BigNumber(0),
|
||||
netVersion: '0',
|
||||
rpcSettings: {},
|
||||
syncing: true,
|
||||
isConnected: false,
|
||||
isConnecting: false,
|
||||
isTest: undefined,
|
||||
refreshStatus: false,
|
||||
traceMode: undefined
|
||||
};
|
||||
|
||||
@ -61,28 +49,6 @@ export default handleActions({
|
||||
const { collection } = action;
|
||||
|
||||
return Object.assign({}, state, collection);
|
||||
},
|
||||
|
||||
statusLogs (state, action) {
|
||||
const { logInfo } = action;
|
||||
|
||||
return Object.assign({}, state, logInfo);
|
||||
},
|
||||
|
||||
toggleStatusLogs (state, action) {
|
||||
const { devLogsEnabled } = action;
|
||||
|
||||
return Object.assign({}, state, { devLogsEnabled });
|
||||
},
|
||||
|
||||
clearStatusLogs (state, action) {
|
||||
return Object.assign({}, state, { devLogs: [] });
|
||||
},
|
||||
|
||||
toggleStatusRefresh (state, action) {
|
||||
const { refreshStatus } = action;
|
||||
|
||||
return Object.assign({}, state, { refreshStatus });
|
||||
}
|
||||
}, initialState);
|
||||
|
||||
|
@ -56,10 +56,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
.inputAddress {
|
||||
position: relative;
|
||||
.copy {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
&:hover, *:hover {
|
||||
.inputAddressContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.inputAddress {
|
||||
flex: 1;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
> *:hover {
|
||||
cursor: text !important;
|
||||
}
|
||||
}
|
||||
@ -67,10 +82,6 @@
|
||||
.main {
|
||||
position: relative;
|
||||
left: 0;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
|
@ -25,6 +25,7 @@ import TextFieldUnderline from 'material-ui/TextField/TextFieldUnderline';
|
||||
|
||||
import apiutil from '~/api/util';
|
||||
import AccountCard from '~/ui/AccountCard';
|
||||
import CopyToClipboard from '~/ui/CopyToClipboard';
|
||||
import InputAddress from '~/ui/Form/InputAddress';
|
||||
import Loading from '~/ui/Loading';
|
||||
import Portal from '~/ui/Portal';
|
||||
@ -107,18 +108,8 @@ class AddressSelect extends Component {
|
||||
const input = this.renderInput();
|
||||
const content = this.renderContent();
|
||||
|
||||
const classes = [ styles.main ];
|
||||
|
||||
return (
|
||||
<div
|
||||
className={ classes.join(' ') }
|
||||
onBlur={ this.handleMainBlur }
|
||||
onClick={ this.handleFocus }
|
||||
onFocus={ this.handleMainFocus }
|
||||
onKeyDown={ this.handleInputAddresKeydown }
|
||||
ref='inputAddress'
|
||||
tabIndex={ 0 }
|
||||
>
|
||||
<div className={ styles.main }>
|
||||
{ input }
|
||||
{ content }
|
||||
</div>
|
||||
@ -151,8 +142,37 @@ class AddressSelect extends Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ styles.inputAddress }>
|
||||
{ input }
|
||||
<div className={ styles.inputAddressContainer }>
|
||||
{ this.renderCopyButton() }
|
||||
<div
|
||||
className={ styles.inputAddress }
|
||||
onBlur={ this.handleMainBlur }
|
||||
onClick={ this.handleFocus }
|
||||
onFocus={ this.handleMainFocus }
|
||||
onKeyDown={ this.handleInputAddresKeydown }
|
||||
ref='inputAddress'
|
||||
tabIndex={ 0 }
|
||||
>
|
||||
{ input }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderCopyButton () {
|
||||
const { allowCopy, value } = this.props;
|
||||
|
||||
if (!allowCopy) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const text = typeof allowCopy === 'string'
|
||||
? allowCopy
|
||||
: value.toString();
|
||||
|
||||
return (
|
||||
<div className={ styles.copy }>
|
||||
<CopyToClipboard data={ text } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -59,11 +59,15 @@ export default class Input extends Component {
|
||||
autoFocus: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
className: PropTypes.string,
|
||||
defaultValue: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
error: nodeOrStringProptype(),
|
||||
escape: PropTypes.oneOf([
|
||||
'default',
|
||||
'initial'
|
||||
]),
|
||||
focused: PropTypes.bool,
|
||||
readOnly: PropTypes.bool,
|
||||
floatCopy: PropTypes.bool,
|
||||
hint: nodeOrStringProptype(),
|
||||
hideUnderline: PropTypes.bool,
|
||||
label: nodeOrStringProptype(),
|
||||
@ -92,8 +96,8 @@ export default class Input extends Component {
|
||||
|
||||
static defaultProps = {
|
||||
allowCopy: false,
|
||||
escape: 'initial',
|
||||
hideUnderline: false,
|
||||
floatCopy: false,
|
||||
onBlur: noop,
|
||||
onFocus: noop,
|
||||
onChange: noop,
|
||||
@ -124,8 +128,8 @@ export default class Input extends Component {
|
||||
|
||||
render () {
|
||||
const { value } = this.state;
|
||||
const { autoFocus, children, className, hideUnderline, disabled, error, focused, label } = this.props;
|
||||
const { hint, onClick, multiLine, rows, type, min, max, step, style, tabIndex } = this.props;
|
||||
const { autoFocus, children, className, defaultValue, hideUnderline, disabled, error } = this.props;
|
||||
const { focused, label, hint, onClick, multiLine, rows, type, min, max, step, style, tabIndex } = this.props;
|
||||
|
||||
const readOnly = this.props.readOnly || disabled;
|
||||
|
||||
@ -159,6 +163,7 @@ export default class Input extends Component {
|
||||
autoComplete='off'
|
||||
autoFocus={ autoFocus }
|
||||
className={ className }
|
||||
defaultValue={ defaultValue }
|
||||
errorText={ error }
|
||||
floatingLabelFixed
|
||||
floatingLabelText={ label }
|
||||
@ -275,14 +280,22 @@ export default class Input extends Component {
|
||||
* if we only want to revert to initial value
|
||||
*/
|
||||
onKeyUp = (event) => {
|
||||
const { escape } = this.props;
|
||||
const codeName = keycode(event);
|
||||
|
||||
if (codeName === 'esc' && !this.pressedEsc && this.intialValue !== undefined) {
|
||||
if (codeName === 'esc' && !this.pressedEsc) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
this.pressedEsc = true;
|
||||
this.onChange(event, this.intialValue);
|
||||
|
||||
if (escape === 'initial' && this.intialValue !== undefined) {
|
||||
return this.onChange(event, this.intialValue);
|
||||
}
|
||||
|
||||
if (escape === 'default' && this.props.defaultValue !== undefined) {
|
||||
return this.onSubmit(this.props.defaultValue);
|
||||
}
|
||||
} else if (this.pressedEsc) {
|
||||
this.pressedEsc = false;
|
||||
}
|
||||
|
@ -16,5 +16,4 @@
|
||||
|
||||
import { createAction } from 'redux-actions';
|
||||
|
||||
export const error = createAction('error');
|
||||
export const syncRpcStateFromLocalStorage = createAction('sync rpcStateFromLocalStorage');
|
@ -14,6 +14,10 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { createAction } from 'redux-actions';
|
||||
import rpc from './rpc';
|
||||
import logger from './logger';
|
||||
|
||||
export const initAppAction = createAction('init app');
|
||||
export {
|
||||
rpc,
|
||||
logger
|
||||
};
|
@ -43,6 +43,7 @@
|
||||
|
||||
.log {
|
||||
font-family: monospace;
|
||||
font-size: 0.9em;
|
||||
white-space: pre-line;
|
||||
word-wrap: break-word;
|
||||
color: #aaa;
|
@ -14,30 +14,30 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { observer } from 'mobx-react';
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Container } from '~/ui';
|
||||
import { PauseIcon, PlayIcon, ReorderIcon, ReplayIcon } from '~/ui/Icons';
|
||||
|
||||
import DebugStore from './store';
|
||||
import styles from './debug.css';
|
||||
|
||||
@observer
|
||||
export default class Debug extends Component {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
clearStatusLogs: PropTypes.func.isRequired,
|
||||
toggleStatusLogs: PropTypes.func.isRequired
|
||||
}).isRequired,
|
||||
nodeStatus: PropTypes.object.isRequired
|
||||
}
|
||||
static contextTypes = {
|
||||
api: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
state = {
|
||||
reversed: true
|
||||
debugStore = new DebugStore(this.context.api);
|
||||
|
||||
componentWillUnmount () {
|
||||
this.debugStore.stopPolling();
|
||||
}
|
||||
|
||||
render () {
|
||||
const { nodeStatus } = this.props;
|
||||
const { devLogsLevels } = nodeStatus;
|
||||
const { logsLevels } = this.debugStore;
|
||||
|
||||
return (
|
||||
<Container
|
||||
@ -50,7 +50,7 @@ export default class Debug extends Component {
|
||||
>
|
||||
{ this.renderActions() }
|
||||
<h2 className={ styles.subheader }>
|
||||
{ devLogsLevels || '-' }
|
||||
{ logsLevels || '-' }
|
||||
</h2>
|
||||
{ this.renderToggle() }
|
||||
{ this.renderLogs() }
|
||||
@ -59,9 +59,9 @@ export default class Debug extends Component {
|
||||
}
|
||||
|
||||
renderToggle () {
|
||||
const { devLogsEnabled } = this.props.nodeStatus;
|
||||
const { logsEnabled } = this.debugStore;
|
||||
|
||||
if (devLogsEnabled) {
|
||||
if (logsEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -76,36 +76,18 @@ export default class Debug extends Component {
|
||||
}
|
||||
|
||||
renderLogs () {
|
||||
const { nodeStatus } = this.props;
|
||||
const { reversed } = this.state;
|
||||
const { devLogs } = nodeStatus;
|
||||
const { logs } = this.debugStore;
|
||||
|
||||
const dateRegex = /^(\d{4}.\d{2}.\d{2}.\d{2}.\d{2}.\d{2})(.*)$/i;
|
||||
|
||||
if (!devLogs) {
|
||||
if (logs.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const logs = reversed
|
||||
? [].concat(devLogs).reverse()
|
||||
: [].concat(devLogs);
|
||||
|
||||
const text = logs
|
||||
.map((log, index) => {
|
||||
const logDate = dateRegex.exec(log);
|
||||
|
||||
if (!logDate) {
|
||||
return (
|
||||
<p key={ index } className={ styles.log }>
|
||||
{ log }
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<p key={ index } className={ styles.log }>
|
||||
<span className={ styles.logDate }>{ logDate[1] }</span>
|
||||
<span className={ styles.logText }>{ logDate[2] }</span>
|
||||
<span className={ styles.logDate }>[{ log.date.toLocaleString() }]</span>
|
||||
<span className={ styles.logText }>{ log.log }</span>
|
||||
</p>
|
||||
);
|
||||
});
|
||||
@ -118,8 +100,8 @@ export default class Debug extends Component {
|
||||
}
|
||||
|
||||
renderActions () {
|
||||
const { devLogsEnabled } = this.props.nodeStatus;
|
||||
const toggleButton = devLogsEnabled
|
||||
const { logsEnabled } = this.debugStore;
|
||||
const toggleButton = logsEnabled
|
||||
? <PauseIcon />
|
||||
: <PlayIcon />;
|
||||
|
||||
@ -143,21 +125,14 @@ export default class Debug extends Component {
|
||||
}
|
||||
|
||||
clear = () => {
|
||||
const { clearStatusLogs } = this.props.actions;
|
||||
|
||||
clearStatusLogs();
|
||||
}
|
||||
this.debugStore.clearLogs();
|
||||
};
|
||||
|
||||
toggle = () => {
|
||||
const { devLogsEnabled } = this.props.nodeStatus;
|
||||
const { toggleStatusLogs } = this.props.actions;
|
||||
|
||||
toggleStatusLogs(!devLogsEnabled);
|
||||
}
|
||||
this.debugStore.toggle();
|
||||
};
|
||||
|
||||
reverse = () => {
|
||||
const { reversed } = this.state;
|
||||
|
||||
this.setState({ reversed: !reversed });
|
||||
}
|
||||
this.debugStore.reverse();
|
||||
};
|
||||
}
|
128
js/src/views/Status/Debug/store.js
Normal file
128
js/src/views/Status/Debug/store.js
Normal file
@ -0,0 +1,128 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { action, observable, transaction } from 'mobx';
|
||||
|
||||
const LOG_DATE_REGEX = /^(\d{4}.\d{2}.\d{2}.\d{2}.\d{2}.\d{2})(.*)$/i;
|
||||
const MAX_LOGS = 25;
|
||||
|
||||
export default class DebugStore {
|
||||
@observable logs = [];
|
||||
@observable logsLevels = null;
|
||||
@observable logsEnabled = false;
|
||||
@observable reversed = false;
|
||||
|
||||
api = null;
|
||||
_lastLogAdded = null;
|
||||
_timeoutId = null;
|
||||
|
||||
constructor (api) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
@action clearLogs () {
|
||||
this.logs = [];
|
||||
}
|
||||
|
||||
@action setLogs (logs, logsLevels) {
|
||||
let newLogs = [];
|
||||
|
||||
if (this._lastLogAdded) {
|
||||
const sliceIndex = logs.findIndex((log) => log === this._lastLogAdded);
|
||||
|
||||
newLogs = logs.slice(0, sliceIndex);
|
||||
} else {
|
||||
newLogs = logs.slice();
|
||||
}
|
||||
|
||||
this._lastLogAdded = logs[0];
|
||||
|
||||
const parsedLogs = newLogs
|
||||
.map((log) => {
|
||||
const logDate = LOG_DATE_REGEX.exec(log);
|
||||
|
||||
if (!logDate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
date: new Date(logDate[1]),
|
||||
log: logDate[2]
|
||||
};
|
||||
})
|
||||
.filter((log) => log);
|
||||
|
||||
transaction(() => {
|
||||
if (!this.reversed) {
|
||||
this.logs = [].concat(parsedLogs, this.logs.slice()).slice(0, MAX_LOGS);
|
||||
} else {
|
||||
parsedLogs.reverse();
|
||||
this.logs = [].concat(this.logs.slice(), parsedLogs).slice(-1 * MAX_LOGS);
|
||||
}
|
||||
|
||||
this.logsLevels = logsLevels;
|
||||
});
|
||||
}
|
||||
|
||||
@action toggle () {
|
||||
this.logsEnabled = !this.logsEnabled;
|
||||
|
||||
if (this.logsEnabled) {
|
||||
this.initPolling();
|
||||
} else {
|
||||
this.stopPolling();
|
||||
}
|
||||
}
|
||||
|
||||
@action reverse () {
|
||||
transaction(() => {
|
||||
this.reversed = !this.reversed;
|
||||
this.logs = this.logs.reverse();
|
||||
});
|
||||
}
|
||||
|
||||
initPolling () {
|
||||
this._pollLogs();
|
||||
}
|
||||
|
||||
stopPolling () {
|
||||
if (this._timeoutId) {
|
||||
clearTimeout(this._timeoutId);
|
||||
}
|
||||
}
|
||||
|
||||
_pollLogs = () => {
|
||||
const nextTimeout = (timeout = 1000) => {
|
||||
this.stopPolling();
|
||||
this._timeoutId = setTimeout(this._pollLogs, timeout);
|
||||
};
|
||||
|
||||
return Promise
|
||||
.all([
|
||||
this.api.parity.devLogs(),
|
||||
this.api.parity.devLogsLevels()
|
||||
])
|
||||
.then(([ devLogs, devLogsLevels ]) => {
|
||||
this.setLogs(devLogs, devLogsLevels);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('_pollLogs', error);
|
||||
})
|
||||
.then(() => {
|
||||
return nextTimeout();
|
||||
});
|
||||
}
|
||||
}
|
@ -14,11 +14,11 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import formatNumber from 'format-number';
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import formatNumber from 'format-number';
|
||||
|
||||
import { ContainerTitle, Input } from '~/ui';
|
||||
import { ContainerTitle, Input, TypedInput } from '~/ui';
|
||||
|
||||
import { numberFromString } from './numberFromString';
|
||||
import { decodeExtraData } from './decodeExtraData';
|
||||
@ -28,21 +28,23 @@ const toNiceNumber = formatNumber();
|
||||
export default class MiningSettings extends Component {
|
||||
static contextTypes = {
|
||||
api: PropTypes.object
|
||||
}
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
nodeStatus: PropTypes.object
|
||||
}
|
||||
coinbase: PropTypes.string,
|
||||
defaultExtraData: PropTypes.string,
|
||||
extraData: PropTypes.string,
|
||||
gasFloorTarget: PropTypes.object,
|
||||
minGasPrice: PropTypes.object,
|
||||
onUpdateSetting: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
render () {
|
||||
const { nodeStatus } = this.props;
|
||||
const { coinbase, defaultExtraData, extraData, gasFloorTarget, minGasPrice } = nodeStatus;
|
||||
|
||||
const extradata = extraData
|
||||
const { coinbase, defaultExtraData, extraData, gasFloorTarget, minGasPrice } = this.props;
|
||||
const decodedExtraData = extraData
|
||||
? decodeExtraData(extraData)
|
||||
: '';
|
||||
|
||||
const defaultExtradata = defaultExtraData
|
||||
const decodedDefaultExtraData = defaultExtraData
|
||||
? decodeExtraData(defaultExtraData)
|
||||
: '';
|
||||
|
||||
@ -56,7 +58,7 @@ export default class MiningSettings extends Component {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Input
|
||||
<TypedInput
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='status.miningSettings.input.author.label'
|
||||
@ -69,14 +71,15 @@ export default class MiningSettings extends Component {
|
||||
defaultMessage='the mining author'
|
||||
/>
|
||||
}
|
||||
param='address'
|
||||
value={ coinbase }
|
||||
onSubmit={ this.onAuthorChange }
|
||||
onChange={ this.onAuthorChange }
|
||||
allowCopy
|
||||
floatCopy
|
||||
{ ...this._test('author') }
|
||||
/>
|
||||
|
||||
<Input
|
||||
defaultValue={ decodedDefaultExtraData }
|
||||
escape='default'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='status.miningSettings.input.extradata.label'
|
||||
@ -89,12 +92,9 @@ export default class MiningSettings extends Component {
|
||||
defaultMessage='extra data for mined blocks'
|
||||
/>
|
||||
}
|
||||
value={ extradata }
|
||||
value={ decodedExtraData }
|
||||
onSubmit={ this.onExtraDataChange }
|
||||
defaultValue={ defaultExtradata }
|
||||
allowCopy
|
||||
floatCopy
|
||||
{ ...this._test('extra-data') }
|
||||
/>
|
||||
|
||||
<Input
|
||||
@ -113,8 +113,6 @@ export default class MiningSettings extends Component {
|
||||
value={ toNiceNumber(minGasPrice) }
|
||||
onSubmit={ this.onMinGasPriceChange }
|
||||
allowCopy={ minGasPrice.toString() }
|
||||
floatCopy
|
||||
{ ...this._test('min-gas-price') }
|
||||
/>
|
||||
|
||||
<Input
|
||||
@ -133,8 +131,6 @@ export default class MiningSettings extends Component {
|
||||
value={ toNiceNumber(gasFloorTarget) }
|
||||
onSubmit={ this.onGasFloorTargetChange }
|
||||
allowCopy={ gasFloorTarget.toString() }
|
||||
floatCopy
|
||||
{ ...this._test('gas-floor-target') }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@ -143,29 +139,36 @@ export default class MiningSettings extends Component {
|
||||
onMinGasPriceChange = (newVal) => {
|
||||
const { api } = this.context;
|
||||
|
||||
api.parity.setMinGasPrice(numberFromString(newVal));
|
||||
api.parity
|
||||
.setMinGasPrice(numberFromString(newVal))
|
||||
.then(() => this.updateMiningSettings());
|
||||
};
|
||||
|
||||
onExtraDataChange = (newVal, isResetToDefault) => {
|
||||
onExtraDataChange = (value) => {
|
||||
const { api } = this.context;
|
||||
const { nodeStatus } = this.props;
|
||||
|
||||
// In case of resetting to default we are just using raw bytes from defaultExtraData
|
||||
// When user sets new value we can safely send a string that will be converted to hex by formatter.
|
||||
const val = isResetToDefault ? nodeStatus.defaultExtraData : newVal;
|
||||
|
||||
api.parity.setExtraData(val);
|
||||
api.parity
|
||||
.setExtraData(value)
|
||||
.then(() => this.updateMiningSettings());
|
||||
};
|
||||
|
||||
onAuthorChange = (newVal) => {
|
||||
const { api } = this.context;
|
||||
|
||||
api.parity.setAuthor(newVal);
|
||||
api.parity
|
||||
.setAuthor(newVal)
|
||||
.then(() => this.updateMiningSettings());
|
||||
};
|
||||
|
||||
onGasFloorTargetChange = (newVal) => {
|
||||
const { api } = this.context;
|
||||
|
||||
api.parity.setGasFloorTarget(numberFromString(newVal));
|
||||
api.parity
|
||||
.setGasFloorTarget(numberFromString(newVal))
|
||||
.then(() => this.updateMiningSettings());
|
||||
};
|
||||
|
||||
updateMiningSettings () {
|
||||
this.props.onUpdateSetting();
|
||||
}
|
||||
}
|
@ -14,4 +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 from './statusPage';
|
||||
export default from './peers';
|
47
js/src/views/Status/Peers/peers.css
Normal file
47
js/src/views/Status/Peers/peers.css
Normal file
@ -0,0 +1,47 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.peers {
|
||||
margin-top: 0.5em;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
th {
|
||||
padding: 0.5em;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.peer {
|
||||
&:nth-child(odd) {
|
||||
background-color: rgba(200, 200, 200, 0.1);
|
||||
}
|
||||
|
||||
td {
|
||||
border-top: 1px solid #333;
|
||||
font-size: 0.9em;
|
||||
overflow: hidden;
|
||||
padding: 0.5em 0.25em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
163
js/src/views/Status/Peers/peers.js
Normal file
163
js/src/views/Status/Peers/peers.js
Normal file
@ -0,0 +1,163 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { Container, ContainerTitle, ScrollableText, ShortenedHash } from '~/ui';
|
||||
|
||||
import styles from './peers.css';
|
||||
|
||||
class Peers extends Component {
|
||||
static propTypes = {
|
||||
peers: PropTypes.array.isRequired
|
||||
};
|
||||
|
||||
render () {
|
||||
const { peers } = this.props;
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<ContainerTitle
|
||||
title={
|
||||
<FormattedMessage
|
||||
id='status.peers.title'
|
||||
defaultMessage='network peers'
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<div className={ styles.peers }>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th />
|
||||
<th>
|
||||
<FormattedMessage
|
||||
id='status.peers.table.header.id'
|
||||
defaultMessage='ID'
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage
|
||||
id='status.peers.table.header.remoteAddress'
|
||||
defaultMessage='Remote Address'
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage
|
||||
id='status.peers.table.header.name'
|
||||
defaultMessage='Name'
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage
|
||||
id='status.peers.table.header.ethHeader'
|
||||
defaultMessage='Header (ETH)'
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage
|
||||
id='status.peers.table.header.ethDiff'
|
||||
defaultMessage='Difficulty (ETH)'
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage
|
||||
id='status.peers.table.header.caps'
|
||||
defaultMessage='Capabilities'
|
||||
/>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{ this.renderPeers(peers) }
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
renderPeers (peers) {
|
||||
return peers.map((peer, index) => this.renderPeer(peer, index));
|
||||
}
|
||||
|
||||
renderPeer (peer, index) {
|
||||
const { caps, id, name, network, protocols } = peer;
|
||||
|
||||
return (
|
||||
<tr
|
||||
className={ styles.peer }
|
||||
key={ id }
|
||||
>
|
||||
<td>
|
||||
{ index + 1 }
|
||||
</td>
|
||||
<td>
|
||||
<ScrollableText small text={ id } />
|
||||
</td>
|
||||
<td>
|
||||
{ network.remoteAddress }
|
||||
</td>
|
||||
<td>
|
||||
{ name }
|
||||
</td>
|
||||
<td>
|
||||
{
|
||||
protocols.eth
|
||||
? <ShortenedHash data={ protocols.eth.head } />
|
||||
: null
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
{
|
||||
protocols.eth && protocols.eth.difficulty.gt(0)
|
||||
? protocols.eth.difficulty.toExponential(16)
|
||||
: null
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
{
|
||||
caps && caps.length > 0
|
||||
? caps.join(' - ')
|
||||
: null
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const handshakeRegex = /handshake/i;
|
||||
|
||||
const { netPeers } = state.nodeStatus;
|
||||
const { peers = [] } = netPeers;
|
||||
const realPeers = peers
|
||||
.filter((peer) => peer.id)
|
||||
.filter((peer) => !handshakeRegex.test(peer.network.remoteAddress))
|
||||
.filter((peer) => peer.protocols.eth && peer.protocols.eth.head)
|
||||
.sort((peerA, peerB) => {
|
||||
const idComp = peerA.id.localeCompare(peerB.id);
|
||||
|
||||
return idComp;
|
||||
});
|
||||
|
||||
return { peers: realPeers };
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Peers);
|
@ -18,28 +18,46 @@ import bytes from 'bytes';
|
||||
import moment from 'moment';
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { Container, ContainerTitle, Input } from '~/ui';
|
||||
|
||||
import MiningSettings from '../MiningSettings';
|
||||
import StatusStore from './store';
|
||||
|
||||
import styles from './status.css';
|
||||
|
||||
export default class Status extends Component {
|
||||
class Status extends Component {
|
||||
static contextTypes = {
|
||||
api: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
nodeStatus: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
blockNumber: PropTypes.object,
|
||||
blockTimestamp: PropTypes.object,
|
||||
netChain: PropTypes.string,
|
||||
netPeers: PropTypes.object
|
||||
};
|
||||
|
||||
statusStore = new StatusStore(this.context.api);
|
||||
|
||||
componentWillMount () {
|
||||
this.statusStore.startPolling();
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.statusStore.stopPolling();
|
||||
}
|
||||
|
||||
render () {
|
||||
const { nodeStatus } = this.props;
|
||||
const { netPeers } = nodeStatus;
|
||||
const { blockNumber, blockTimestamp, netPeers } = this.props;
|
||||
const { hashrate } = this.statusStore;
|
||||
|
||||
if (!netPeers || !nodeStatus.blockNumber) {
|
||||
if (!netPeers || !blockNumber) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const hashrate = bytes(nodeStatus.hashrate.toNumber()) || 0;
|
||||
const hashrateValue = bytes(hashrate.toNumber()) || 0;
|
||||
const peers = `${netPeers.active}/${netPeers.connected}/${netPeers.max}`;
|
||||
|
||||
return (
|
||||
@ -56,11 +74,11 @@ export default class Status extends Component {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<div { ...this._test('best-block') } className={ styles.blockInfo }>
|
||||
#{ nodeStatus.blockNumber.toFormat() }
|
||||
<div className={ styles.blockInfo }>
|
||||
#{ blockNumber.toFormat() }
|
||||
</div>
|
||||
<div className={ styles.blockByline }>
|
||||
{ moment(nodeStatus.blockTimestamp).calendar() }
|
||||
{ moment(blockTimestamp).calendar() }
|
||||
</div>
|
||||
</div>
|
||||
<div className={ `${styles.col12} ${styles.padBottom}` }>
|
||||
@ -72,7 +90,7 @@ export default class Status extends Component {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<div { ...this._test('peers') } className={ styles.blockInfo }>
|
||||
<div className={ styles.blockInfo }>
|
||||
{ peers }
|
||||
</div>
|
||||
</div>
|
||||
@ -85,23 +103,19 @@ export default class Status extends Component {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<div { ...this._test('hashrate') } className={ styles.blockInfo }>
|
||||
<div className={ styles.blockInfo }>
|
||||
<FormattedMessage
|
||||
id='status.status.hashrate'
|
||||
defaultMessage='{hashrate} H/s'
|
||||
values={ {
|
||||
hashrate
|
||||
hashrate: hashrateValue
|
||||
} }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={ styles.col4_5 }>
|
||||
<MiningSettings
|
||||
{ ...this._test('mining') }
|
||||
nodeStatus={ nodeStatus }
|
||||
actions={ this.props.actions }
|
||||
/>
|
||||
{ this.renderMiningSettings() }
|
||||
</div>
|
||||
<div className={ styles.col4_5 }>
|
||||
{ this.renderSettings() }
|
||||
@ -112,12 +126,27 @@ export default class Status extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
renderMiningSettings () {
|
||||
const { coinbase, defaultExtraData, extraData, gasFloorTarget, minGasPrice } = this.statusStore;
|
||||
|
||||
return (
|
||||
<MiningSettings
|
||||
coinbase={ coinbase }
|
||||
defaultExtraData={ defaultExtraData }
|
||||
extraData={ extraData }
|
||||
gasFloorTarget={ gasFloorTarget }
|
||||
minGasPrice={ minGasPrice }
|
||||
onUpdateSetting={ this.statusStore.handleUpdateSetting }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderNodeName () {
|
||||
const { nodeStatus } = this.props;
|
||||
const { nodeName } = this.statusStore;
|
||||
|
||||
return (
|
||||
<span>
|
||||
{ nodeStatus.nodeName || (
|
||||
{ nodeName || (
|
||||
<FormattedMessage
|
||||
id='status.status.title.node'
|
||||
defaultMessage='Node'
|
||||
@ -128,9 +157,8 @@ export default class Status extends Component {
|
||||
}
|
||||
|
||||
renderSettings () {
|
||||
const { nodeStatus } = this.props;
|
||||
const { rpcSettings, netPeers, netPort = '' } = nodeStatus;
|
||||
const peers = `${netPeers.active}/${netPeers.connected}/${netPeers.max}`;
|
||||
const { netChain } = this.props;
|
||||
const { enode, rpcSettings, netPort = '' } = this.statusStore;
|
||||
|
||||
if (!rpcSettings) {
|
||||
return null;
|
||||
@ -139,7 +167,7 @@ export default class Status extends Component {
|
||||
const rpcPort = rpcSettings.port || '';
|
||||
|
||||
return (
|
||||
<div { ...this._test('settings') }>
|
||||
<div>
|
||||
<ContainerTitle
|
||||
title={
|
||||
<FormattedMessage
|
||||
@ -157,8 +185,7 @@ export default class Status extends Component {
|
||||
defaultMessage='chain'
|
||||
/>
|
||||
}
|
||||
value={ nodeStatus.netChain }
|
||||
{ ...this._test('chain') }
|
||||
value={ netChain }
|
||||
/>
|
||||
<div className={ styles.row }>
|
||||
<div className={ styles.col6 }>
|
||||
@ -167,12 +194,25 @@ export default class Status extends Component {
|
||||
readOnly
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='status.status.input.peers'
|
||||
defaultMessage='peers'
|
||||
id='status.status.input.rpcEnabled'
|
||||
defaultMessage='rpc enabled'
|
||||
/>
|
||||
}
|
||||
value={ peers }
|
||||
{ ...this._test('peers') }
|
||||
value={
|
||||
rpcSettings.enabled
|
||||
? (
|
||||
<FormattedMessage
|
||||
id='status.status.input.yes'
|
||||
defaultMessage='yes'
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<FormattedMessage
|
||||
id='status.status.input.no'
|
||||
defaultMessage='no'
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className={ styles.col6 }>
|
||||
@ -186,37 +226,10 @@ export default class Status extends Component {
|
||||
/>
|
||||
}
|
||||
value={ netPort.toString() }
|
||||
{ ...this._test('network-port') }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
allowCopy
|
||||
readOnly
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='status.status.input.rpcEnabled'
|
||||
defaultMessage='rpc enabled'
|
||||
/>
|
||||
}
|
||||
value={
|
||||
rpcSettings.enabled
|
||||
? (
|
||||
<FormattedMessage
|
||||
id='status.status.input.yes'
|
||||
defaultMessage='yes'
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<FormattedMessage
|
||||
id='status.status.input.no'
|
||||
defaultMessage='no'
|
||||
/>
|
||||
)
|
||||
}
|
||||
{ ...this._test('rpc-enabled') }
|
||||
/>
|
||||
<div className={ styles.row }>
|
||||
<div className={ styles.col6 }>
|
||||
<Input
|
||||
@ -229,7 +242,6 @@ export default class Status extends Component {
|
||||
/>
|
||||
}
|
||||
value={ rpcSettings.interface }
|
||||
{ ...this._test('rpc-interface') }
|
||||
/>
|
||||
</div>
|
||||
<div className={ styles.col6 }>
|
||||
@ -243,7 +255,6 @@ export default class Status extends Component {
|
||||
/>
|
||||
}
|
||||
value={ rpcPort.toString() }
|
||||
{ ...this._test('rpc-port') }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -259,8 +270,7 @@ export default class Status extends Component {
|
||||
defaultMessage='enode'
|
||||
/>
|
||||
}
|
||||
value={ nodeStatus.enode }
|
||||
{ ...this._test('node-enode') }
|
||||
value={ enode }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -268,3 +278,24 @@ export default class Status extends Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const {
|
||||
blockNumber,
|
||||
blockTimestamp,
|
||||
netChain,
|
||||
netPeers
|
||||
} = state.nodeStatus;
|
||||
|
||||
return {
|
||||
blockNumber,
|
||||
blockTimestamp,
|
||||
netChain,
|
||||
netPeers
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
)(Status);
|
160
js/src/views/Status/Status/store.js
Normal file
160
js/src/views/Status/Status/store.js
Normal file
@ -0,0 +1,160 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { action, observable, transaction } from 'mobx';
|
||||
|
||||
export default class StatusStore {
|
||||
@observable defaultExtraData = '';
|
||||
@observable enode = '';
|
||||
@observable hashrate = new BigNumber(0);
|
||||
@observable netPort = new BigNumber(0);
|
||||
@observable nodeName = '';
|
||||
@observable rpcSettings = {};
|
||||
|
||||
@observable coinbase = '';
|
||||
@observable extraData = '';
|
||||
@observable gasFloorTarget = new BigNumber(0);
|
||||
@observable minGasPrice = new BigNumber(0);
|
||||
|
||||
api = null;
|
||||
_timeoutIds = {};
|
||||
|
||||
constructor (api) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
@action setLongStatus ({ defaultExtraData, enode, netPort, rpcSettings }) {
|
||||
transaction(() => {
|
||||
this.defaultExtraData = defaultExtraData;
|
||||
this.enode = enode;
|
||||
this.netPort = netPort;
|
||||
this.rpcSettings = rpcSettings;
|
||||
});
|
||||
}
|
||||
|
||||
@action setStatus ({ hashrate }) {
|
||||
transaction(() => {
|
||||
this.hashrate = hashrate;
|
||||
});
|
||||
}
|
||||
|
||||
@action setMinerSettings ({ coinbase, extraData, gasFloorTarget, minGasPrice }) {
|
||||
transaction(() => {
|
||||
this.coinbase = coinbase;
|
||||
this.extraData = extraData;
|
||||
this.gasFloorTarget = gasFloorTarget;
|
||||
this.minGasPrice = minGasPrice;
|
||||
});
|
||||
}
|
||||
|
||||
startPolling () {
|
||||
this._pollStatus();
|
||||
this._pollLongStatus();
|
||||
}
|
||||
|
||||
stopPolling () {
|
||||
Object.keys(this._timeoutIds).forEach((key) => clearTimeout(this._timeoutIds[key]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Miner settings should never changes unless
|
||||
* Parity is restarted, or if the values are changed
|
||||
* from the UI
|
||||
*/
|
||||
_pollMinerSettings () {
|
||||
return Promise
|
||||
.all([
|
||||
this.api.eth.coinbase(),
|
||||
this.api.parity.extraData(),
|
||||
this.api.parity.gasFloorTarget(),
|
||||
this.api.parity.minGasPrice()
|
||||
])
|
||||
.then(([
|
||||
coinbase, extraData, gasFloorTarget, minGasPrice
|
||||
]) => {
|
||||
const minerSettings = {
|
||||
coinbase,
|
||||
extraData,
|
||||
gasFloorTarget,
|
||||
minGasPrice
|
||||
};
|
||||
|
||||
this.setMinerSettings(minerSettings);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('_pollMinerSettings', error);
|
||||
});
|
||||
}
|
||||
|
||||
_pollStatus () {
|
||||
const nextTimeout = (timeout = 1000) => {
|
||||
clearTimeout(this._timeoutIds.short);
|
||||
this._timeoutIds.short = setTimeout(() => this._pollStatus(), timeout);
|
||||
};
|
||||
|
||||
return Promise
|
||||
.all([
|
||||
this.api.eth.hashrate()
|
||||
])
|
||||
.then(([
|
||||
hashrate
|
||||
]) => {
|
||||
this.setStatus({
|
||||
hashrate
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('_pollStatus', error);
|
||||
})
|
||||
.then(() => {
|
||||
nextTimeout();
|
||||
});
|
||||
}
|
||||
|
||||
_pollLongStatus () {
|
||||
const nextTimeout = (timeout = 30000) => {
|
||||
clearTimeout(this._timeoutIds.long);
|
||||
this._timeoutIds.long = setTimeout(() => this._pollLongStatus(), timeout);
|
||||
};
|
||||
|
||||
this._pollMinerSettings();
|
||||
return Promise
|
||||
.all([
|
||||
this.api.parity.defaultExtraData(),
|
||||
this.api.parity.enode().then((enode) => enode).catch(() => '-'),
|
||||
this.api.parity.netPort(),
|
||||
this.api.parity.rpcSettings()
|
||||
])
|
||||
.then(([
|
||||
defaultExtraData, enode, netPort, rpcSettings
|
||||
]) => {
|
||||
this.setLongStatus({
|
||||
defaultExtraData, enode, netPort, rpcSettings
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('_pollLongStatus', error);
|
||||
})
|
||||
.then(() => {
|
||||
nextTimeout();
|
||||
});
|
||||
}
|
||||
|
||||
handleUpdateSetting = () => {
|
||||
return this._pollMinerSettings();
|
||||
};
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { createAction } from 'redux-actions';
|
||||
|
||||
import { identity } from '../util';
|
||||
import { withError } from '~/redux/util';
|
||||
|
||||
export const copyToClipboard = createAction('copy toClipboard', identity, withError(identity));
|
@ -1,23 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { createAction } from 'redux-actions';
|
||||
|
||||
export const error = createAction('error');
|
||||
export const updateDevLogs = createAction('update devLogs');
|
||||
export const removeDevLogs = createAction('remove devLogs');
|
||||
export const updateDevLogging = createAction('update devLogging');
|
||||
export const updateDevLogsLevels = createAction('update devLogsLevels');
|
@ -1,24 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { createAction } from 'redux-actions';
|
||||
|
||||
export const error = createAction('error');
|
||||
export const updateAuthor = createAction('update author');
|
||||
export const updateMinGasPrice = createAction('update minGasPrice');
|
||||
export const updateGasFloorTarget = createAction('update gasFloorTarget');
|
||||
export const updateExtraData = createAction('update extraData');
|
||||
export const updateDefaultExtraData = createAction('update defaultExtraData');
|
@ -1,23 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { createAction } from 'redux-actions';
|
||||
|
||||
export const modifyMinGasPrice = createAction('modify minGasPrice');
|
||||
export const modifyGasFloorTarget = createAction('modify gasFloorTarget');
|
||||
export const modifyAuthor = createAction('modify author');
|
||||
export const modifyExtraData = createAction('modify extraData');
|
||||
export const resetExtraData = createAction('reset extraData');
|
@ -1,29 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { createAction } from 'redux-actions';
|
||||
|
||||
export const error = createAction('error');
|
||||
export const updateHashrate = createAction('update hashrate');
|
||||
export const updateBlockNumber = createAction('update blockNumber');
|
||||
export const updateVersion = createAction('update version');
|
||||
export const updatePeerCount = createAction('update peerCount');
|
||||
export const updateNetPeers = createAction('update netPeers');
|
||||
export const updateNetChain = createAction('update netChain');
|
||||
export const updateNetPort = createAction('update netPort');
|
||||
export const updateRpcSettings = createAction('update rpcSettings');
|
||||
export const updateNodeName = createAction('update nodeName');
|
||||
export const updateAccounts = createAction('update accounts');
|
@ -1,69 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { clearStatusLogs, toggleStatusLogs, toggleStatusRefresh } from '~/redux/actions';
|
||||
|
||||
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,
|
||||
actions: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
this.props.actions.toggleStatusRefresh(true);
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.props.actions.toggleStatusRefresh(false);
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className={ styles.body }>
|
||||
<Status { ...this.props } />
|
||||
<Debug { ...this.props } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps (state) {
|
||||
return state;
|
||||
}
|
||||
|
||||
function mapDispatchToProps (dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
clearStatusLogs,
|
||||
toggleStatusLogs,
|
||||
toggleStatusRefresh
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(StatusPage);
|
@ -1,66 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { handleActions } from 'redux-actions';
|
||||
import { union } from 'lodash';
|
||||
|
||||
const initialState = {
|
||||
levels: '',
|
||||
logging: true,
|
||||
logs: []
|
||||
};
|
||||
|
||||
const maxLogs = 1024;
|
||||
|
||||
export const actionHandlers = {
|
||||
|
||||
'update devLogsLevels' (state, action) {
|
||||
return {
|
||||
...state,
|
||||
levels: `${action.payload}`
|
||||
};
|
||||
},
|
||||
|
||||
'remove devLogs' (state, action) {
|
||||
return {
|
||||
...state,
|
||||
logs: []
|
||||
};
|
||||
},
|
||||
|
||||
'update devLogging' (state, action) {
|
||||
return {
|
||||
...state,
|
||||
logging: action.payload
|
||||
};
|
||||
},
|
||||
|
||||
'update devLogs' (state, action) {
|
||||
if (!state.logging) {
|
||||
return { ...state };
|
||||
}
|
||||
|
||||
let newLogs = union(state.logs, action.payload.reverse());
|
||||
|
||||
return {
|
||||
...state,
|
||||
logs: newLogs.slice(newLogs.length - maxLogs)
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export default handleActions(actionHandlers, initialState);
|
@ -1,31 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import status from './status';
|
||||
import settings from './settings';
|
||||
import mining from './mining';
|
||||
import debug from './debug';
|
||||
import rpc from './rpc';
|
||||
import logger from './logger';
|
||||
|
||||
export {
|
||||
status,
|
||||
settings,
|
||||
mining,
|
||||
rpc,
|
||||
logger,
|
||||
debug
|
||||
};
|
@ -1,66 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { handleActions } from 'redux-actions';
|
||||
|
||||
const initialState = {
|
||||
author: 'loading...',
|
||||
extraData: 'loading...',
|
||||
defaultExtraData: '0x01',
|
||||
minGasPrice: 'loading...',
|
||||
gasFloorTarget: 'loading...'
|
||||
};
|
||||
|
||||
export const actionHandlers = {
|
||||
|
||||
'update author' (state, action) {
|
||||
return {
|
||||
...state,
|
||||
author: `${action.payload}`
|
||||
};
|
||||
},
|
||||
|
||||
'update minGasPrice' (state, action) {
|
||||
return {
|
||||
...state,
|
||||
minGasPrice: `${action.payload}`
|
||||
};
|
||||
},
|
||||
|
||||
'update gasFloorTarget' (state, action) {
|
||||
return {
|
||||
...state,
|
||||
gasFloorTarget: `${action.payload}`
|
||||
};
|
||||
},
|
||||
|
||||
'update extraData' (state, action) {
|
||||
return {
|
||||
...state,
|
||||
extraData: `${action.payload}`
|
||||
};
|
||||
},
|
||||
|
||||
'update defaultExtraData' (state, action) {
|
||||
return {
|
||||
...state,
|
||||
defaultExtraData: `${action.payload}`
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export default handleActions(actionHandlers, initialState);
|
@ -1,60 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { handleActions } from 'redux-actions';
|
||||
|
||||
const initialState = {
|
||||
chain: 'loading...',
|
||||
networkPort: 0,
|
||||
maxPeers: 0,
|
||||
rpcEnabled: false,
|
||||
rpcInterface: '-',
|
||||
rpcPort: 0
|
||||
};
|
||||
|
||||
export default handleActions({
|
||||
'update netChain' (state, action) {
|
||||
return {
|
||||
...state,
|
||||
chain: action.payload
|
||||
};
|
||||
},
|
||||
|
||||
'update netPort' (state, action) {
|
||||
return {
|
||||
...state,
|
||||
networkPort: action.payload
|
||||
};
|
||||
},
|
||||
|
||||
'update netPeers' (state, action) {
|
||||
return {
|
||||
...state,
|
||||
maxPeers: action.payload.max
|
||||
};
|
||||
},
|
||||
|
||||
'update rpcSettings' (state, action) {
|
||||
const rpc = action.payload;
|
||||
|
||||
return {
|
||||
...state,
|
||||
rpcEnabled: rpc.enabled,
|
||||
rpcInterface: rpc.interface,
|
||||
rpcPort: rpc.port
|
||||
};
|
||||
}
|
||||
}, initialState);
|
@ -1,92 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { handleActions } from 'redux-actions';
|
||||
|
||||
const initialState = {
|
||||
error: false,
|
||||
noOfErrors: 0,
|
||||
name: 'My node',
|
||||
bestBlock: 'loading...',
|
||||
hashrate: 'loading...',
|
||||
connectedPeers: 0,
|
||||
activePeers: 0,
|
||||
peers: 0,
|
||||
accounts: [],
|
||||
version: '-'
|
||||
};
|
||||
|
||||
export default handleActions({
|
||||
error (state, action) {
|
||||
return {
|
||||
...state,
|
||||
disconnected: (action.payload.message === 'Invalid JSON RPC response: ""'),
|
||||
noOfErrors: state.noOfErrors + 1
|
||||
};
|
||||
},
|
||||
|
||||
'update blockNumber' (state, action) {
|
||||
return {
|
||||
...resetError(state),
|
||||
bestBlock: `${action.payload}`
|
||||
};
|
||||
},
|
||||
|
||||
'update hashrate' (state, action) {
|
||||
return {
|
||||
...resetError(state),
|
||||
hashrate: `${action.payload}`
|
||||
};
|
||||
},
|
||||
|
||||
'update netPeers' (state, action) {
|
||||
return {
|
||||
...state,
|
||||
connectedPeers: action.payload.connected,
|
||||
activePeers: action.payload.active
|
||||
};
|
||||
},
|
||||
|
||||
'update version' (state, action) {
|
||||
return {
|
||||
...resetError(state),
|
||||
version: action.payload
|
||||
};
|
||||
},
|
||||
|
||||
'update accounts' (state, action) {
|
||||
return {
|
||||
...resetError(state),
|
||||
accounts: action.payload
|
||||
};
|
||||
},
|
||||
|
||||
'update nodeName' (state, action) {
|
||||
return {
|
||||
...resetError(state),
|
||||
name: action.payload || ' '
|
||||
};
|
||||
}
|
||||
|
||||
}, initialState);
|
||||
|
||||
function resetError (state) {
|
||||
return {
|
||||
...state,
|
||||
disconnected: false,
|
||||
noOfErrors: 0
|
||||
};
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user