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 { newError } from '~/ui/Errors/actions';
|
||||||
import { setAddressImage } from './providers/imagesActions';
|
import { setAddressImage } from './providers/imagesActions';
|
||||||
import { openSnackbar, showSnackbar } from './providers/snackbarActions';
|
import { openSnackbar, showSnackbar } from './providers/snackbarActions';
|
||||||
import { clearStatusLogs, toggleStatusLogs, toggleStatusRefresh } from './providers/statusActions';
|
import { toggleStatusRefresh } from './providers/statusActions';
|
||||||
import { toggleView } from '~/views/Settings/actions';
|
import { toggleView } from '~/views/Settings/actions';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
newError,
|
newError,
|
||||||
clearStatusLogs,
|
|
||||||
setAddressImage,
|
setAddressImage,
|
||||||
openSnackbar,
|
openSnackbar,
|
||||||
showSnackbar,
|
showSnackbar,
|
||||||
toggleStatusLogs,
|
|
||||||
toggleStatusRefresh,
|
toggleStatusRefresh,
|
||||||
toggleView
|
toggleView
|
||||||
};
|
};
|
||||||
|
@ -20,7 +20,6 @@ import ErrorsMiddleware from '~/ui/Errors/middleware';
|
|||||||
import SettingsMiddleware from '~/views/Settings/middleware';
|
import SettingsMiddleware from '~/views/Settings/middleware';
|
||||||
import SignerMiddleware from './providers/signerMiddleware';
|
import SignerMiddleware from './providers/signerMiddleware';
|
||||||
|
|
||||||
import statusMiddleware from '~/views/Status/middleware';
|
|
||||||
import CertificationsMiddleware from './providers/certifications/middleware';
|
import CertificationsMiddleware from './providers/certifications/middleware';
|
||||||
import ChainMiddleware from './providers/chainMiddleware';
|
import ChainMiddleware from './providers/chainMiddleware';
|
||||||
import RegistryMiddleware from './providers/registry/middleware';
|
import RegistryMiddleware from './providers/registry/middleware';
|
||||||
@ -44,8 +43,7 @@ export default function (api, browserHistory, forEmbed = false) {
|
|||||||
middleware.push(certifications, registry);
|
middleware.push(certifications, registry);
|
||||||
}
|
}
|
||||||
|
|
||||||
const status = statusMiddleware();
|
|
||||||
const routeMiddleware = browserHistory ? routerMiddleware(browserHistory) : [];
|
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 UpgradeStore from '~/modals/UpgradeParity/store';
|
||||||
|
|
||||||
import BalancesProvider from './balances';
|
import BalancesProvider from './balances';
|
||||||
import { statusBlockNumber, statusCollection, statusLogs } from './statusActions';
|
import { statusBlockNumber, statusCollection } from './statusActions';
|
||||||
|
|
||||||
const log = getLogger(LOG_KEYS.Signer);
|
const log = getLogger(LOG_KEYS.Signer);
|
||||||
let instance = null;
|
let instance = null;
|
||||||
@ -59,6 +59,14 @@ export default class Status {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get () {
|
||||||
|
if (!instance) {
|
||||||
|
throw new Error('The Status Provider has not been initialized yet');
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
start () {
|
start () {
|
||||||
log.debug('status::start');
|
log.debug('status::start');
|
||||||
|
|
||||||
@ -66,7 +74,6 @@ export default class Status {
|
|||||||
.all([
|
.all([
|
||||||
this._subscribeBlockNumber(),
|
this._subscribeBlockNumber(),
|
||||||
|
|
||||||
this._pollLogs(),
|
|
||||||
this._pollLongStatus(),
|
this._pollLongStatus(),
|
||||||
this._pollStatus()
|
this._pollStatus()
|
||||||
])
|
])
|
||||||
@ -187,25 +194,12 @@ export default class Status {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
const { refreshStatus } = this._store.getState().nodeStatus;
|
const statusPromises = [ this._api.eth.syncing(), this._api.parity.netPeers() ];
|
||||||
|
|
||||||
const statusPromises = [ this._api.eth.syncing() ];
|
|
||||||
|
|
||||||
if (refreshStatus) {
|
|
||||||
statusPromises.push(this._api.parity.netPeers());
|
|
||||||
statusPromises.push(this._api.eth.hashrate());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise
|
return Promise
|
||||||
.all(statusPromises)
|
.all(statusPromises)
|
||||||
.then(([ syncing, ...statusResults ]) => {
|
.then(([ syncing, netPeers ]) => {
|
||||||
const status = statusResults.length === 0
|
const status = { netPeers, syncing };
|
||||||
? { syncing }
|
|
||||||
: {
|
|
||||||
syncing,
|
|
||||||
netPeers: statusResults[0],
|
|
||||||
hashrate: statusResults[1]
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!isEqual(status, this._status)) {
|
if (!isEqual(status, this._status)) {
|
||||||
this._store.dispatch(statusCollection(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
|
* The data fetched here should not change
|
||||||
* unless Parity is restarted. They are thus
|
* unless Parity is restarted. They are thus
|
||||||
@ -272,23 +233,16 @@ export default class Status {
|
|||||||
this._timeoutIds.longStatus = setTimeout(() => this._pollLongStatus(), timeout);
|
this._timeoutIds.longStatus = setTimeout(() => this._pollLongStatus(), timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Poll Miner settings just in case
|
return Promise
|
||||||
const minerPromise = this._pollMinerSettings();
|
|
||||||
|
|
||||||
const mainPromise = Promise
|
|
||||||
.all([
|
.all([
|
||||||
this._api.parity.netPeers(),
|
this._api.parity.netPeers(),
|
||||||
this._api.web3.clientVersion(),
|
this._api.web3.clientVersion(),
|
||||||
this._api.net.version(),
|
this._api.net.version(),
|
||||||
this._api.parity.defaultExtraData(),
|
|
||||||
this._api.parity.netChain(),
|
this._api.parity.netChain(),
|
||||||
this._api.parity.netPort(),
|
|
||||||
this._api.parity.rpcSettings(),
|
|
||||||
this._api.parity.enode().then((enode) => enode).catch(() => '-'),
|
|
||||||
this._upgradeStore.checkUpgrade()
|
this._upgradeStore.checkUpgrade()
|
||||||
])
|
])
|
||||||
.then(([
|
.then(([
|
||||||
netPeers, clientVersion, netVersion, defaultExtraData, netChain, netPort, rpcSettings, enode, upgradeStatus
|
netPeers, clientVersion, netVersion, netChain, upgradeStatus
|
||||||
]) => {
|
]) => {
|
||||||
const isTest = [
|
const isTest = [
|
||||||
'2', // morden
|
'2', // morden
|
||||||
@ -299,13 +253,9 @@ export default class Status {
|
|||||||
const longStatus = {
|
const longStatus = {
|
||||||
netPeers,
|
netPeers,
|
||||||
clientVersion,
|
clientVersion,
|
||||||
defaultExtraData,
|
|
||||||
netChain,
|
netChain,
|
||||||
netPort,
|
|
||||||
netVersion,
|
netVersion,
|
||||||
rpcSettings,
|
isTest
|
||||||
isTest,
|
|
||||||
enode
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isEqual(longStatus, this._longStatus)) {
|
if (!isEqual(longStatus, this._longStatus)) {
|
||||||
@ -319,42 +269,5 @@ export default class Status {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
nextTimeout(60000);
|
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
|
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 = {
|
const initialState = {
|
||||||
blockNumber: new BigNumber(0),
|
blockNumber: new BigNumber(0),
|
||||||
blockTimestamp: new Date(),
|
blockTimestamp: new Date(),
|
||||||
devLogs: [],
|
|
||||||
devLogsLevels: null,
|
|
||||||
devLogsEnabled: false,
|
|
||||||
clientVersion: '',
|
clientVersion: '',
|
||||||
coinbase: '',
|
|
||||||
defaultExtraData: '',
|
|
||||||
enode: '',
|
|
||||||
extraData: '',
|
|
||||||
gasFloorTarget: new BigNumber(0),
|
|
||||||
gasLimit: new BigNumber(0),
|
gasLimit: new BigNumber(0),
|
||||||
hashrate: new BigNumber(0),
|
|
||||||
minGasPrice: new BigNumber(0),
|
|
||||||
netChain: DEFAULT_NETCHAIN,
|
netChain: DEFAULT_NETCHAIN,
|
||||||
netPeers: {
|
netPeers: {
|
||||||
active: new BigNumber(0),
|
active: new BigNumber(0),
|
||||||
connected: new BigNumber(0),
|
connected: new BigNumber(0),
|
||||||
max: new BigNumber(0)
|
max: new BigNumber(0),
|
||||||
|
peers: []
|
||||||
},
|
},
|
||||||
netPort: new BigNumber(0),
|
|
||||||
netVersion: '0',
|
netVersion: '0',
|
||||||
rpcSettings: {},
|
|
||||||
syncing: true,
|
syncing: true,
|
||||||
isConnected: false,
|
isConnected: false,
|
||||||
isConnecting: false,
|
isConnecting: false,
|
||||||
isTest: undefined,
|
isTest: undefined,
|
||||||
refreshStatus: false,
|
|
||||||
traceMode: undefined
|
traceMode: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -61,28 +49,6 @@ export default handleActions({
|
|||||||
const { collection } = action;
|
const { collection } = action;
|
||||||
|
|
||||||
return Object.assign({}, state, collection);
|
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);
|
}, initialState);
|
||||||
|
|
||||||
|
@ -56,10 +56,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.inputAddress {
|
.copy {
|
||||||
position: relative;
|
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;
|
cursor: text !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,10 +82,6 @@
|
|||||||
.main {
|
.main {
|
||||||
position: relative;
|
position: relative;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
|
@ -25,6 +25,7 @@ import TextFieldUnderline from 'material-ui/TextField/TextFieldUnderline';
|
|||||||
|
|
||||||
import apiutil from '~/api/util';
|
import apiutil from '~/api/util';
|
||||||
import AccountCard from '~/ui/AccountCard';
|
import AccountCard from '~/ui/AccountCard';
|
||||||
|
import CopyToClipboard from '~/ui/CopyToClipboard';
|
||||||
import InputAddress from '~/ui/Form/InputAddress';
|
import InputAddress from '~/ui/Form/InputAddress';
|
||||||
import Loading from '~/ui/Loading';
|
import Loading from '~/ui/Loading';
|
||||||
import Portal from '~/ui/Portal';
|
import Portal from '~/ui/Portal';
|
||||||
@ -107,18 +108,8 @@ class AddressSelect extends Component {
|
|||||||
const input = this.renderInput();
|
const input = this.renderInput();
|
||||||
const content = this.renderContent();
|
const content = this.renderContent();
|
||||||
|
|
||||||
const classes = [ styles.main ];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={ styles.main }>
|
||||||
className={ classes.join(' ') }
|
|
||||||
onBlur={ this.handleMainBlur }
|
|
||||||
onClick={ this.handleFocus }
|
|
||||||
onFocus={ this.handleMainFocus }
|
|
||||||
onKeyDown={ this.handleInputAddresKeydown }
|
|
||||||
ref='inputAddress'
|
|
||||||
tabIndex={ 0 }
|
|
||||||
>
|
|
||||||
{ input }
|
{ input }
|
||||||
{ content }
|
{ content }
|
||||||
</div>
|
</div>
|
||||||
@ -151,8 +142,37 @@ class AddressSelect extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.inputAddress }>
|
<div className={ styles.inputAddressContainer }>
|
||||||
{ input }
|
{ 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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -59,11 +59,15 @@ export default class Input extends Component {
|
|||||||
autoFocus: PropTypes.bool,
|
autoFocus: PropTypes.bool,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
|
defaultValue: PropTypes.string,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
error: nodeOrStringProptype(),
|
error: nodeOrStringProptype(),
|
||||||
|
escape: PropTypes.oneOf([
|
||||||
|
'default',
|
||||||
|
'initial'
|
||||||
|
]),
|
||||||
focused: PropTypes.bool,
|
focused: PropTypes.bool,
|
||||||
readOnly: PropTypes.bool,
|
readOnly: PropTypes.bool,
|
||||||
floatCopy: PropTypes.bool,
|
|
||||||
hint: nodeOrStringProptype(),
|
hint: nodeOrStringProptype(),
|
||||||
hideUnderline: PropTypes.bool,
|
hideUnderline: PropTypes.bool,
|
||||||
label: nodeOrStringProptype(),
|
label: nodeOrStringProptype(),
|
||||||
@ -92,8 +96,8 @@ export default class Input extends Component {
|
|||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
allowCopy: false,
|
allowCopy: false,
|
||||||
|
escape: 'initial',
|
||||||
hideUnderline: false,
|
hideUnderline: false,
|
||||||
floatCopy: false,
|
|
||||||
onBlur: noop,
|
onBlur: noop,
|
||||||
onFocus: noop,
|
onFocus: noop,
|
||||||
onChange: noop,
|
onChange: noop,
|
||||||
@ -124,8 +128,8 @@ export default class Input extends Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { value } = this.state;
|
const { value } = this.state;
|
||||||
const { autoFocus, children, className, hideUnderline, disabled, error, focused, label } = this.props;
|
const { autoFocus, children, className, defaultValue, hideUnderline, disabled, error } = this.props;
|
||||||
const { hint, onClick, multiLine, rows, type, min, max, step, style, tabIndex } = this.props;
|
const { focused, label, hint, onClick, multiLine, rows, type, min, max, step, style, tabIndex } = this.props;
|
||||||
|
|
||||||
const readOnly = this.props.readOnly || disabled;
|
const readOnly = this.props.readOnly || disabled;
|
||||||
|
|
||||||
@ -159,6 +163,7 @@ export default class Input extends Component {
|
|||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
autoFocus={ autoFocus }
|
autoFocus={ autoFocus }
|
||||||
className={ className }
|
className={ className }
|
||||||
|
defaultValue={ defaultValue }
|
||||||
errorText={ error }
|
errorText={ error }
|
||||||
floatingLabelFixed
|
floatingLabelFixed
|
||||||
floatingLabelText={ label }
|
floatingLabelText={ label }
|
||||||
@ -275,14 +280,22 @@ export default class Input extends Component {
|
|||||||
* if we only want to revert to initial value
|
* if we only want to revert to initial value
|
||||||
*/
|
*/
|
||||||
onKeyUp = (event) => {
|
onKeyUp = (event) => {
|
||||||
|
const { escape } = this.props;
|
||||||
const codeName = keycode(event);
|
const codeName = keycode(event);
|
||||||
|
|
||||||
if (codeName === 'esc' && !this.pressedEsc && this.intialValue !== undefined) {
|
if (codeName === 'esc' && !this.pressedEsc) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
this.pressedEsc = true;
|
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) {
|
} else if (this.pressedEsc) {
|
||||||
this.pressedEsc = false;
|
this.pressedEsc = false;
|
||||||
}
|
}
|
||||||
|
@ -16,5 +16,4 @@
|
|||||||
|
|
||||||
import { createAction } from 'redux-actions';
|
import { createAction } from 'redux-actions';
|
||||||
|
|
||||||
export const error = createAction('error');
|
|
||||||
export const syncRpcStateFromLocalStorage = createAction('sync rpcStateFromLocalStorage');
|
export const syncRpcStateFromLocalStorage = createAction('sync rpcStateFromLocalStorage');
|
@ -14,6 +14,10 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// 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 {
|
.log {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
|
font-size: 0.9em;
|
||||||
white-space: pre-line;
|
white-space: pre-line;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
color: #aaa;
|
color: #aaa;
|
@ -14,30 +14,30 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { Container } from '~/ui';
|
import { Container } from '~/ui';
|
||||||
import { PauseIcon, PlayIcon, ReorderIcon, ReplayIcon } from '~/ui/Icons';
|
import { PauseIcon, PlayIcon, ReorderIcon, ReplayIcon } from '~/ui/Icons';
|
||||||
|
|
||||||
|
import DebugStore from './store';
|
||||||
import styles from './debug.css';
|
import styles from './debug.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
export default class Debug extends Component {
|
export default class Debug extends Component {
|
||||||
static propTypes = {
|
static contextTypes = {
|
||||||
actions: PropTypes.shape({
|
api: PropTypes.object.isRequired
|
||||||
clearStatusLogs: PropTypes.func.isRequired,
|
};
|
||||||
toggleStatusLogs: PropTypes.func.isRequired
|
|
||||||
}).isRequired,
|
|
||||||
nodeStatus: PropTypes.object.isRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
state = {
|
debugStore = new DebugStore(this.context.api);
|
||||||
reversed: true
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
this.debugStore.stopPolling();
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { nodeStatus } = this.props;
|
const { logsLevels } = this.debugStore;
|
||||||
const { devLogsLevels } = nodeStatus;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container
|
||||||
@ -50,7 +50,7 @@ export default class Debug extends Component {
|
|||||||
>
|
>
|
||||||
{ this.renderActions() }
|
{ this.renderActions() }
|
||||||
<h2 className={ styles.subheader }>
|
<h2 className={ styles.subheader }>
|
||||||
{ devLogsLevels || '-' }
|
{ logsLevels || '-' }
|
||||||
</h2>
|
</h2>
|
||||||
{ this.renderToggle() }
|
{ this.renderToggle() }
|
||||||
{ this.renderLogs() }
|
{ this.renderLogs() }
|
||||||
@ -59,9 +59,9 @@ export default class Debug extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderToggle () {
|
renderToggle () {
|
||||||
const { devLogsEnabled } = this.props.nodeStatus;
|
const { logsEnabled } = this.debugStore;
|
||||||
|
|
||||||
if (devLogsEnabled) {
|
if (logsEnabled) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,36 +76,18 @@ export default class Debug extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderLogs () {
|
renderLogs () {
|
||||||
const { nodeStatus } = this.props;
|
const { logs } = this.debugStore;
|
||||||
const { reversed } = this.state;
|
|
||||||
const { devLogs } = nodeStatus;
|
|
||||||
|
|
||||||
const dateRegex = /^(\d{4}.\d{2}.\d{2}.\d{2}.\d{2}.\d{2})(.*)$/i;
|
if (logs.length === 0) {
|
||||||
|
|
||||||
if (!devLogs) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const logs = reversed
|
|
||||||
? [].concat(devLogs).reverse()
|
|
||||||
: [].concat(devLogs);
|
|
||||||
|
|
||||||
const text = logs
|
const text = logs
|
||||||
.map((log, index) => {
|
.map((log, index) => {
|
||||||
const logDate = dateRegex.exec(log);
|
|
||||||
|
|
||||||
if (!logDate) {
|
|
||||||
return (
|
|
||||||
<p key={ index } className={ styles.log }>
|
|
||||||
{ log }
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p key={ index } className={ styles.log }>
|
<p key={ index } className={ styles.log }>
|
||||||
<span className={ styles.logDate }>{ logDate[1] }</span>
|
<span className={ styles.logDate }>[{ log.date.toLocaleString() }]</span>
|
||||||
<span className={ styles.logText }>{ logDate[2] }</span>
|
<span className={ styles.logText }>{ log.log }</span>
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -118,8 +100,8 @@ export default class Debug extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderActions () {
|
renderActions () {
|
||||||
const { devLogsEnabled } = this.props.nodeStatus;
|
const { logsEnabled } = this.debugStore;
|
||||||
const toggleButton = devLogsEnabled
|
const toggleButton = logsEnabled
|
||||||
? <PauseIcon />
|
? <PauseIcon />
|
||||||
: <PlayIcon />;
|
: <PlayIcon />;
|
||||||
|
|
||||||
@ -143,21 +125,14 @@ export default class Debug extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clear = () => {
|
clear = () => {
|
||||||
const { clearStatusLogs } = this.props.actions;
|
this.debugStore.clearLogs();
|
||||||
|
};
|
||||||
clearStatusLogs();
|
|
||||||
}
|
|
||||||
|
|
||||||
toggle = () => {
|
toggle = () => {
|
||||||
const { devLogsEnabled } = this.props.nodeStatus;
|
this.debugStore.toggle();
|
||||||
const { toggleStatusLogs } = this.props.actions;
|
};
|
||||||
|
|
||||||
toggleStatusLogs(!devLogsEnabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse = () => {
|
reverse = () => {
|
||||||
const { reversed } = this.state;
|
this.debugStore.reverse();
|
||||||
|
};
|
||||||
this.setState({ reversed: !reversed });
|
|
||||||
}
|
|
||||||
}
|
}
|
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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import formatNumber from 'format-number';
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
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 { numberFromString } from './numberFromString';
|
||||||
import { decodeExtraData } from './decodeExtraData';
|
import { decodeExtraData } from './decodeExtraData';
|
||||||
@ -28,21 +28,23 @@ const toNiceNumber = formatNumber();
|
|||||||
export default class MiningSettings extends Component {
|
export default class MiningSettings extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
api: PropTypes.object
|
api: PropTypes.object
|
||||||
}
|
};
|
||||||
|
|
||||||
static propTypes = {
|
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 () {
|
render () {
|
||||||
const { nodeStatus } = this.props;
|
const { coinbase, defaultExtraData, extraData, gasFloorTarget, minGasPrice } = this.props;
|
||||||
const { coinbase, defaultExtraData, extraData, gasFloorTarget, minGasPrice } = nodeStatus;
|
const decodedExtraData = extraData
|
||||||
|
|
||||||
const extradata = extraData
|
|
||||||
? decodeExtraData(extraData)
|
? decodeExtraData(extraData)
|
||||||
: '';
|
: '';
|
||||||
|
const decodedDefaultExtraData = defaultExtraData
|
||||||
const defaultExtradata = defaultExtraData
|
|
||||||
? decodeExtraData(defaultExtraData)
|
? decodeExtraData(defaultExtraData)
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
@ -56,7 +58,7 @@ export default class MiningSettings extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Input
|
<TypedInput
|
||||||
label={
|
label={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='status.miningSettings.input.author.label'
|
id='status.miningSettings.input.author.label'
|
||||||
@ -69,14 +71,15 @@ export default class MiningSettings extends Component {
|
|||||||
defaultMessage='the mining author'
|
defaultMessage='the mining author'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
param='address'
|
||||||
value={ coinbase }
|
value={ coinbase }
|
||||||
onSubmit={ this.onAuthorChange }
|
onChange={ this.onAuthorChange }
|
||||||
allowCopy
|
allowCopy
|
||||||
floatCopy
|
|
||||||
{ ...this._test('author') }
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
|
defaultValue={ decodedDefaultExtraData }
|
||||||
|
escape='default'
|
||||||
label={
|
label={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='status.miningSettings.input.extradata.label'
|
id='status.miningSettings.input.extradata.label'
|
||||||
@ -89,12 +92,9 @@ export default class MiningSettings extends Component {
|
|||||||
defaultMessage='extra data for mined blocks'
|
defaultMessage='extra data for mined blocks'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
value={ extradata }
|
value={ decodedExtraData }
|
||||||
onSubmit={ this.onExtraDataChange }
|
onSubmit={ this.onExtraDataChange }
|
||||||
defaultValue={ defaultExtradata }
|
|
||||||
allowCopy
|
allowCopy
|
||||||
floatCopy
|
|
||||||
{ ...this._test('extra-data') }
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
@ -113,8 +113,6 @@ export default class MiningSettings extends Component {
|
|||||||
value={ toNiceNumber(minGasPrice) }
|
value={ toNiceNumber(minGasPrice) }
|
||||||
onSubmit={ this.onMinGasPriceChange }
|
onSubmit={ this.onMinGasPriceChange }
|
||||||
allowCopy={ minGasPrice.toString() }
|
allowCopy={ minGasPrice.toString() }
|
||||||
floatCopy
|
|
||||||
{ ...this._test('min-gas-price') }
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
@ -133,8 +131,6 @@ export default class MiningSettings extends Component {
|
|||||||
value={ toNiceNumber(gasFloorTarget) }
|
value={ toNiceNumber(gasFloorTarget) }
|
||||||
onSubmit={ this.onGasFloorTargetChange }
|
onSubmit={ this.onGasFloorTargetChange }
|
||||||
allowCopy={ gasFloorTarget.toString() }
|
allowCopy={ gasFloorTarget.toString() }
|
||||||
floatCopy
|
|
||||||
{ ...this._test('gas-floor-target') }
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -143,29 +139,36 @@ export default class MiningSettings extends Component {
|
|||||||
onMinGasPriceChange = (newVal) => {
|
onMinGasPriceChange = (newVal) => {
|
||||||
const { api } = this.context;
|
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 { api } = this.context;
|
||||||
const { nodeStatus } = this.props;
|
|
||||||
|
|
||||||
// In case of resetting to default we are just using raw bytes from defaultExtraData
|
api.parity
|
||||||
// When user sets new value we can safely send a string that will be converted to hex by formatter.
|
.setExtraData(value)
|
||||||
const val = isResetToDefault ? nodeStatus.defaultExtraData : newVal;
|
.then(() => this.updateMiningSettings());
|
||||||
|
|
||||||
api.parity.setExtraData(val);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onAuthorChange = (newVal) => {
|
onAuthorChange = (newVal) => {
|
||||||
const { api } = this.context;
|
const { api } = this.context;
|
||||||
|
|
||||||
api.parity.setAuthor(newVal);
|
api.parity
|
||||||
|
.setAuthor(newVal)
|
||||||
|
.then(() => this.updateMiningSettings());
|
||||||
};
|
};
|
||||||
|
|
||||||
onGasFloorTargetChange = (newVal) => {
|
onGasFloorTargetChange = (newVal) => {
|
||||||
const { api } = this.context;
|
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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// 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 moment from 'moment';
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { Container, ContainerTitle, Input } from '~/ui';
|
import { Container, ContainerTitle, Input } from '~/ui';
|
||||||
|
|
||||||
import MiningSettings from '../MiningSettings';
|
import MiningSettings from '../MiningSettings';
|
||||||
|
import StatusStore from './store';
|
||||||
|
|
||||||
import styles from './status.css';
|
import styles from './status.css';
|
||||||
|
|
||||||
export default class Status extends Component {
|
class Status extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
api: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
nodeStatus: PropTypes.object.isRequired,
|
blockNumber: PropTypes.object,
|
||||||
actions: PropTypes.object.isRequired
|
blockTimestamp: PropTypes.object,
|
||||||
|
netChain: PropTypes.string,
|
||||||
|
netPeers: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
statusStore = new StatusStore(this.context.api);
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
this.statusStore.startPolling();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
this.statusStore.stopPolling();
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { nodeStatus } = this.props;
|
const { blockNumber, blockTimestamp, netPeers } = this.props;
|
||||||
const { netPeers } = nodeStatus;
|
const { hashrate } = this.statusStore;
|
||||||
|
|
||||||
if (!netPeers || !nodeStatus.blockNumber) {
|
if (!netPeers || !blockNumber) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hashrate = bytes(nodeStatus.hashrate.toNumber()) || 0;
|
const hashrateValue = bytes(hashrate.toNumber()) || 0;
|
||||||
const peers = `${netPeers.active}/${netPeers.connected}/${netPeers.max}`;
|
const peers = `${netPeers.active}/${netPeers.connected}/${netPeers.max}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -56,11 +74,11 @@ export default class Status extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div { ...this._test('best-block') } className={ styles.blockInfo }>
|
<div className={ styles.blockInfo }>
|
||||||
#{ nodeStatus.blockNumber.toFormat() }
|
#{ blockNumber.toFormat() }
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.blockByline }>
|
<div className={ styles.blockByline }>
|
||||||
{ moment(nodeStatus.blockTimestamp).calendar() }
|
{ moment(blockTimestamp).calendar() }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={ `${styles.col12} ${styles.padBottom}` }>
|
<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 }
|
{ peers }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -85,23 +103,19 @@ export default class Status extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div { ...this._test('hashrate') } className={ styles.blockInfo }>
|
<div className={ styles.blockInfo }>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='status.status.hashrate'
|
id='status.status.hashrate'
|
||||||
defaultMessage='{hashrate} H/s'
|
defaultMessage='{hashrate} H/s'
|
||||||
values={ {
|
values={ {
|
||||||
hashrate
|
hashrate: hashrateValue
|
||||||
} }
|
} }
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.col4_5 }>
|
<div className={ styles.col4_5 }>
|
||||||
<MiningSettings
|
{ this.renderMiningSettings() }
|
||||||
{ ...this._test('mining') }
|
|
||||||
nodeStatus={ nodeStatus }
|
|
||||||
actions={ this.props.actions }
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.col4_5 }>
|
<div className={ styles.col4_5 }>
|
||||||
{ this.renderSettings() }
|
{ 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 () {
|
renderNodeName () {
|
||||||
const { nodeStatus } = this.props;
|
const { nodeName } = this.statusStore;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{ nodeStatus.nodeName || (
|
{ nodeName || (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='status.status.title.node'
|
id='status.status.title.node'
|
||||||
defaultMessage='Node'
|
defaultMessage='Node'
|
||||||
@ -128,9 +157,8 @@ export default class Status extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderSettings () {
|
renderSettings () {
|
||||||
const { nodeStatus } = this.props;
|
const { netChain } = this.props;
|
||||||
const { rpcSettings, netPeers, netPort = '' } = nodeStatus;
|
const { enode, rpcSettings, netPort = '' } = this.statusStore;
|
||||||
const peers = `${netPeers.active}/${netPeers.connected}/${netPeers.max}`;
|
|
||||||
|
|
||||||
if (!rpcSettings) {
|
if (!rpcSettings) {
|
||||||
return null;
|
return null;
|
||||||
@ -139,7 +167,7 @@ export default class Status extends Component {
|
|||||||
const rpcPort = rpcSettings.port || '';
|
const rpcPort = rpcSettings.port || '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div { ...this._test('settings') }>
|
<div>
|
||||||
<ContainerTitle
|
<ContainerTitle
|
||||||
title={
|
title={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
@ -157,8 +185,7 @@ export default class Status extends Component {
|
|||||||
defaultMessage='chain'
|
defaultMessage='chain'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
value={ nodeStatus.netChain }
|
value={ netChain }
|
||||||
{ ...this._test('chain') }
|
|
||||||
/>
|
/>
|
||||||
<div className={ styles.row }>
|
<div className={ styles.row }>
|
||||||
<div className={ styles.col6 }>
|
<div className={ styles.col6 }>
|
||||||
@ -167,12 +194,25 @@ export default class Status extends Component {
|
|||||||
readOnly
|
readOnly
|
||||||
label={
|
label={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='status.status.input.peers'
|
id='status.status.input.rpcEnabled'
|
||||||
defaultMessage='peers'
|
defaultMessage='rpc enabled'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
value={ peers }
|
value={
|
||||||
{ ...this._test('peers') }
|
rpcSettings.enabled
|
||||||
|
? (
|
||||||
|
<FormattedMessage
|
||||||
|
id='status.status.input.yes'
|
||||||
|
defaultMessage='yes'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='status.status.input.no'
|
||||||
|
defaultMessage='no'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.col6 }>
|
<div className={ styles.col6 }>
|
||||||
@ -186,37 +226,10 @@ export default class Status extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
value={ netPort.toString() }
|
value={ netPort.toString() }
|
||||||
{ ...this._test('network-port') }
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</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.row }>
|
||||||
<div className={ styles.col6 }>
|
<div className={ styles.col6 }>
|
||||||
<Input
|
<Input
|
||||||
@ -229,7 +242,6 @@ export default class Status extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
value={ rpcSettings.interface }
|
value={ rpcSettings.interface }
|
||||||
{ ...this._test('rpc-interface') }
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.col6 }>
|
<div className={ styles.col6 }>
|
||||||
@ -243,7 +255,6 @@ export default class Status extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
value={ rpcPort.toString() }
|
value={ rpcPort.toString() }
|
||||||
{ ...this._test('rpc-port') }
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -259,8 +270,7 @@ export default class Status extends Component {
|
|||||||
defaultMessage='enode'
|
defaultMessage='enode'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
value={ nodeStatus.enode }
|
value={ enode }
|
||||||
{ ...this._test('node-enode') }
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</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