diff --git a/js/src/redux/actions.js b/js/src/redux/actions.js index 6dee602d8..bf356535c 100644 --- a/js/src/redux/actions.js +++ b/js/src/redux/actions.js @@ -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 }; diff --git a/js/src/redux/middleware.js b/js/src/redux/middleware.js index 02e40afc1..9cc413dc0 100644 --- a/js/src/redux/middleware.js +++ b/js/src/redux/middleware.js @@ -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); } diff --git a/js/src/redux/providers/status.js b/js/src/redux/providers/status.js index 8aa17a0be..0fa354d1a 100644 --- a/js/src/redux/providers/status.js +++ b/js/src/redux/providers/status.js @@ -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(); - }); } } diff --git a/js/src/redux/providers/statusActions.js b/js/src/redux/providers/statusActions.js index a7b64b94e..df18053e1 100644 --- a/js/src/redux/providers/statusActions.js +++ b/js/src/redux/providers/statusActions.js @@ -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 - }; -} diff --git a/js/src/redux/providers/statusReducer.js b/js/src/redux/providers/statusReducer.js index 1189f51c6..6f509735e 100644 --- a/js/src/redux/providers/statusReducer.js +++ b/js/src/redux/providers/statusReducer.js @@ -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); diff --git a/js/src/ui/Form/AddressSelect/addressSelect.css b/js/src/ui/Form/AddressSelect/addressSelect.css index 84afbd15a..5b7ced748 100644 --- a/js/src/ui/Form/AddressSelect/addressSelect.css +++ b/js/src/ui/Form/AddressSelect/addressSelect.css @@ -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 { diff --git a/js/src/ui/Form/AddressSelect/addressSelect.js b/js/src/ui/Form/AddressSelect/addressSelect.js index 511ab930f..e7c210eba 100644 --- a/js/src/ui/Form/AddressSelect/addressSelect.js +++ b/js/src/ui/Form/AddressSelect/addressSelect.js @@ -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 ( -
+
{ input } { content }
@@ -151,8 +142,37 @@ class AddressSelect extends Component { } return ( -
- { input } +
+ { this.renderCopyButton() } +
+ { input } +
+
+ ); + } + + renderCopyButton () { + const { allowCopy, value } = this.props; + + if (!allowCopy) { + return null; + } + + const text = typeof allowCopy === 'string' + ? allowCopy + : value.toString(); + + return ( +
+
); } diff --git a/js/src/ui/Form/Input/input.js b/js/src/ui/Form/Input/input.js index bf57c8e8d..98acad855 100644 --- a/js/src/ui/Form/Input/input.js +++ b/js/src/ui/Form/Input/input.js @@ -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; } diff --git a/js/src/views/Status/actions/localstorage.js b/js/src/views/RpcCalls/actions/localstorage.js similarity index 95% rename from js/src/views/Status/actions/localstorage.js rename to js/src/views/RpcCalls/actions/localstorage.js index 372da633e..258159105 100644 --- a/js/src/views/Status/actions/localstorage.js +++ b/js/src/views/RpcCalls/actions/localstorage.js @@ -16,5 +16,4 @@ import { createAction } from 'redux-actions'; -export const error = createAction('error'); export const syncRpcStateFromLocalStorage = createAction('sync rpcStateFromLocalStorage'); diff --git a/js/src/views/Status/actions/logger.js b/js/src/views/RpcCalls/actions/logger.js similarity index 100% rename from js/src/views/Status/actions/logger.js rename to js/src/views/RpcCalls/actions/logger.js diff --git a/js/src/views/Status/actions/rpc.js b/js/src/views/RpcCalls/actions/rpc.js similarity index 100% rename from js/src/views/Status/actions/rpc.js rename to js/src/views/RpcCalls/actions/rpc.js diff --git a/js/src/views/Status/components/AutoComplete/AutoComplete.js b/js/src/views/RpcCalls/components/AutoComplete/AutoComplete.js similarity index 100% rename from js/src/views/Status/components/AutoComplete/AutoComplete.js rename to js/src/views/RpcCalls/components/AutoComplete/AutoComplete.js diff --git a/js/src/views/Status/components/AutoComplete/AutoComplete.spec.js b/js/src/views/RpcCalls/components/AutoComplete/AutoComplete.spec.js similarity index 100% rename from js/src/views/Status/components/AutoComplete/AutoComplete.spec.js rename to js/src/views/RpcCalls/components/AutoComplete/AutoComplete.spec.js diff --git a/js/src/views/Status/components/AutoComplete/index.js b/js/src/views/RpcCalls/components/AutoComplete/index.js similarity index 100% rename from js/src/views/Status/components/AutoComplete/index.js rename to js/src/views/RpcCalls/components/AutoComplete/index.js diff --git a/js/src/views/Status/components/Box/Box.js b/js/src/views/RpcCalls/components/Box/Box.js similarity index 100% rename from js/src/views/Status/components/Box/Box.js rename to js/src/views/RpcCalls/components/Box/Box.js diff --git a/js/src/views/Status/components/Box/Box.spec.js b/js/src/views/RpcCalls/components/Box/Box.spec.js similarity index 100% rename from js/src/views/Status/components/Box/Box.spec.js rename to js/src/views/RpcCalls/components/Box/Box.spec.js diff --git a/js/src/views/Status/components/Box/index.js b/js/src/views/RpcCalls/components/Box/index.js similarity index 100% rename from js/src/views/Status/components/Box/index.js rename to js/src/views/RpcCalls/components/Box/index.js diff --git a/js/src/views/Status/components/Call/Call.css b/js/src/views/RpcCalls/components/Call/Call.css similarity index 100% rename from js/src/views/Status/components/Call/Call.css rename to js/src/views/RpcCalls/components/Call/Call.css diff --git a/js/src/views/Status/components/Call/Call.js b/js/src/views/RpcCalls/components/Call/Call.js similarity index 100% rename from js/src/views/Status/components/Call/Call.js rename to js/src/views/RpcCalls/components/Call/Call.js diff --git a/js/src/views/Status/components/Call/Call.spec.js b/js/src/views/RpcCalls/components/Call/Call.spec.js similarity index 100% rename from js/src/views/Status/components/Call/Call.spec.js rename to js/src/views/RpcCalls/components/Call/Call.spec.js diff --git a/js/src/views/Status/components/Call/index.js b/js/src/views/RpcCalls/components/Call/index.js similarity index 100% rename from js/src/views/Status/components/Call/index.js rename to js/src/views/RpcCalls/components/Call/index.js diff --git a/js/src/views/Status/components/Calls/Calls.css b/js/src/views/RpcCalls/components/Calls/Calls.css similarity index 100% rename from js/src/views/Status/components/Calls/Calls.css rename to js/src/views/RpcCalls/components/Calls/Calls.css diff --git a/js/src/views/Status/components/Calls/Calls.js b/js/src/views/RpcCalls/components/Calls/Calls.js similarity index 100% rename from js/src/views/Status/components/Calls/Calls.js rename to js/src/views/RpcCalls/components/Calls/Calls.js diff --git a/js/src/views/Status/components/Calls/Calls.spec.js b/js/src/views/RpcCalls/components/Calls/Calls.spec.js similarity index 100% rename from js/src/views/Status/components/Calls/Calls.spec.js rename to js/src/views/RpcCalls/components/Calls/Calls.spec.js diff --git a/js/src/views/Status/components/Calls/index.js b/js/src/views/RpcCalls/components/Calls/index.js similarity index 100% rename from js/src/views/Status/components/Calls/index.js rename to js/src/views/RpcCalls/components/Calls/index.js diff --git a/js/src/views/Status/components/CallsToolbar/CallsToolbar.css b/js/src/views/RpcCalls/components/CallsToolbar/CallsToolbar.css similarity index 100% rename from js/src/views/Status/components/CallsToolbar/CallsToolbar.css rename to js/src/views/RpcCalls/components/CallsToolbar/CallsToolbar.css diff --git a/js/src/views/Status/components/CallsToolbar/CallsToolbar.js b/js/src/views/RpcCalls/components/CallsToolbar/CallsToolbar.js similarity index 100% rename from js/src/views/Status/components/CallsToolbar/CallsToolbar.js rename to js/src/views/RpcCalls/components/CallsToolbar/CallsToolbar.js diff --git a/js/src/views/Status/components/CallsToolbar/CallsToolbar.spec.js b/js/src/views/RpcCalls/components/CallsToolbar/CallsToolbar.spec.js similarity index 100% rename from js/src/views/Status/components/CallsToolbar/CallsToolbar.spec.js rename to js/src/views/RpcCalls/components/CallsToolbar/CallsToolbar.spec.js diff --git a/js/src/views/Status/components/CallsToolbar/index.js b/js/src/views/RpcCalls/components/CallsToolbar/index.js similarity index 100% rename from js/src/views/Status/components/CallsToolbar/index.js rename to js/src/views/RpcCalls/components/CallsToolbar/index.js diff --git a/js/src/views/Status/components/EditableValue/EditableValue.css b/js/src/views/RpcCalls/components/EditableValue/EditableValue.css similarity index 100% rename from js/src/views/Status/components/EditableValue/EditableValue.css rename to js/src/views/RpcCalls/components/EditableValue/EditableValue.css diff --git a/js/src/views/Status/components/EditableValue/EditableValue.js b/js/src/views/RpcCalls/components/EditableValue/EditableValue.js similarity index 100% rename from js/src/views/Status/components/EditableValue/EditableValue.js rename to js/src/views/RpcCalls/components/EditableValue/EditableValue.js diff --git a/js/src/views/Status/components/EditableValue/index.js b/js/src/views/RpcCalls/components/EditableValue/index.js similarity index 100% rename from js/src/views/Status/components/EditableValue/index.js rename to js/src/views/RpcCalls/components/EditableValue/index.js diff --git a/js/src/views/Status/components/JsonEditor/JsonEditor.css b/js/src/views/RpcCalls/components/JsonEditor/JsonEditor.css similarity index 100% rename from js/src/views/Status/components/JsonEditor/JsonEditor.css rename to js/src/views/RpcCalls/components/JsonEditor/JsonEditor.css diff --git a/js/src/views/Status/components/JsonEditor/JsonEditor.js b/js/src/views/RpcCalls/components/JsonEditor/JsonEditor.js similarity index 100% rename from js/src/views/Status/components/JsonEditor/JsonEditor.js rename to js/src/views/RpcCalls/components/JsonEditor/JsonEditor.js diff --git a/js/src/views/Status/components/JsonEditor/index.js b/js/src/views/RpcCalls/components/JsonEditor/index.js similarity index 100% rename from js/src/views/Status/components/JsonEditor/index.js rename to js/src/views/RpcCalls/components/JsonEditor/index.js diff --git a/js/src/views/Status/components/Markdown/Markdown.css b/js/src/views/RpcCalls/components/Markdown/Markdown.css similarity index 100% rename from js/src/views/Status/components/Markdown/Markdown.css rename to js/src/views/RpcCalls/components/Markdown/Markdown.css diff --git a/js/src/views/Status/components/Markdown/Markdown.js b/js/src/views/RpcCalls/components/Markdown/Markdown.js similarity index 100% rename from js/src/views/Status/components/Markdown/Markdown.js rename to js/src/views/RpcCalls/components/Markdown/Markdown.js diff --git a/js/src/views/Status/components/Markdown/index.js b/js/src/views/RpcCalls/components/Markdown/index.js similarity index 100% rename from js/src/views/Status/components/Markdown/index.js rename to js/src/views/RpcCalls/components/Markdown/index.js diff --git a/js/src/views/Status/components/Response/Response.css b/js/src/views/RpcCalls/components/Response/Response.css similarity index 100% rename from js/src/views/Status/components/Response/Response.css rename to js/src/views/RpcCalls/components/Response/Response.css diff --git a/js/src/views/Status/components/Response/Response.js b/js/src/views/RpcCalls/components/Response/Response.js similarity index 100% rename from js/src/views/Status/components/Response/Response.js rename to js/src/views/RpcCalls/components/Response/Response.js diff --git a/js/src/views/Status/components/Response/Response.spec.js b/js/src/views/RpcCalls/components/Response/Response.spec.js similarity index 100% rename from js/src/views/Status/components/Response/Response.spec.js rename to js/src/views/RpcCalls/components/Response/Response.spec.js diff --git a/js/src/views/Status/components/Response/index.js b/js/src/views/RpcCalls/components/Response/index.js similarity index 100% rename from js/src/views/Status/components/Response/index.js rename to js/src/views/RpcCalls/components/Response/index.js diff --git a/js/src/views/Status/components/RpcCalls/RpcCalls.css b/js/src/views/RpcCalls/components/RpcCalls/RpcCalls.css similarity index 100% rename from js/src/views/Status/components/RpcCalls/RpcCalls.css rename to js/src/views/RpcCalls/components/RpcCalls/RpcCalls.css diff --git a/js/src/views/Status/components/RpcCalls/RpcCalls.js b/js/src/views/RpcCalls/components/RpcCalls/RpcCalls.js similarity index 100% rename from js/src/views/Status/components/RpcCalls/RpcCalls.js rename to js/src/views/RpcCalls/components/RpcCalls/RpcCalls.js diff --git a/js/src/views/Status/components/RpcCalls/index.js b/js/src/views/RpcCalls/components/RpcCalls/index.js similarity index 100% rename from js/src/views/Status/components/RpcCalls/index.js rename to js/src/views/RpcCalls/components/RpcCalls/index.js diff --git a/js/src/views/Status/components/RpcDocs/RpcDocs.css b/js/src/views/RpcCalls/components/RpcDocs/RpcDocs.css similarity index 100% rename from js/src/views/Status/components/RpcDocs/RpcDocs.css rename to js/src/views/RpcCalls/components/RpcDocs/RpcDocs.css diff --git a/js/src/views/Status/components/RpcDocs/RpcDocs.js b/js/src/views/RpcCalls/components/RpcDocs/RpcDocs.js similarity index 100% rename from js/src/views/Status/components/RpcDocs/RpcDocs.js rename to js/src/views/RpcCalls/components/RpcDocs/RpcDocs.js diff --git a/js/src/views/Status/components/RpcDocs/index.js b/js/src/views/RpcCalls/components/RpcDocs/index.js similarity index 100% rename from js/src/views/Status/components/RpcDocs/index.js rename to js/src/views/RpcCalls/components/RpcDocs/index.js diff --git a/js/src/views/Status/components/RpcNav/RpcNav.css b/js/src/views/RpcCalls/components/RpcNav/RpcNav.css similarity index 100% rename from js/src/views/Status/components/RpcNav/RpcNav.css rename to js/src/views/RpcCalls/components/RpcNav/RpcNav.css diff --git a/js/src/views/Status/components/RpcNav/RpcNav.js b/js/src/views/RpcCalls/components/RpcNav/RpcNav.js similarity index 100% rename from js/src/views/Status/components/RpcNav/RpcNav.js rename to js/src/views/RpcCalls/components/RpcNav/RpcNav.js diff --git a/js/src/views/Status/components/RpcNav/index.js b/js/src/views/RpcCalls/components/RpcNav/index.js similarity index 100% rename from js/src/views/Status/components/RpcNav/index.js rename to js/src/views/RpcCalls/components/RpcNav/index.js diff --git a/js/src/views/Status/components/ScrollTopButton/ScrollTopButton.css b/js/src/views/RpcCalls/components/ScrollTopButton/ScrollTopButton.css similarity index 100% rename from js/src/views/Status/components/ScrollTopButton/ScrollTopButton.css rename to js/src/views/RpcCalls/components/ScrollTopButton/ScrollTopButton.css diff --git a/js/src/views/Status/components/ScrollTopButton/ScrollTopButton.js b/js/src/views/RpcCalls/components/ScrollTopButton/ScrollTopButton.js similarity index 100% rename from js/src/views/Status/components/ScrollTopButton/ScrollTopButton.js rename to js/src/views/RpcCalls/components/ScrollTopButton/ScrollTopButton.js diff --git a/js/src/views/Status/components/ScrollTopButton/index.js b/js/src/views/RpcCalls/components/ScrollTopButton/index.js similarity index 100% rename from js/src/views/Status/components/ScrollTopButton/index.js rename to js/src/views/RpcCalls/components/ScrollTopButton/index.js diff --git a/js/src/views/Status/components/ScrollTopButton/util.js b/js/src/views/RpcCalls/components/ScrollTopButton/util.js similarity index 100% rename from js/src/views/Status/components/ScrollTopButton/util.js rename to js/src/views/RpcCalls/components/ScrollTopButton/util.js diff --git a/js/src/views/Status/constants/index.js b/js/src/views/RpcCalls/constants/index.js similarity index 100% rename from js/src/views/Status/constants/index.js rename to js/src/views/RpcCalls/constants/index.js diff --git a/js/src/views/Status/containers/RpcPage/RpcPage.js b/js/src/views/RpcCalls/containers/RpcPage/RpcPage.js similarity index 100% rename from js/src/views/Status/containers/RpcPage/RpcPage.js rename to js/src/views/RpcCalls/containers/RpcPage/RpcPage.js diff --git a/js/src/views/Status/containers/RpcPage/index.js b/js/src/views/RpcCalls/containers/RpcPage/index.js similarity index 100% rename from js/src/views/Status/containers/RpcPage/index.js rename to js/src/views/RpcCalls/containers/RpcPage/index.js diff --git a/js/src/views/Status/data/rpc.json b/js/src/views/RpcCalls/data/rpc.json similarity index 100% rename from js/src/views/Status/data/rpc.json rename to js/src/views/RpcCalls/data/rpc.json diff --git a/js/src/views/Status/middleware/index.js b/js/src/views/RpcCalls/middleware/index.js similarity index 100% rename from js/src/views/Status/middleware/index.js rename to js/src/views/RpcCalls/middleware/index.js diff --git a/js/src/views/Status/middleware/localstorage.js b/js/src/views/RpcCalls/middleware/localstorage.js similarity index 100% rename from js/src/views/Status/middleware/localstorage.js rename to js/src/views/RpcCalls/middleware/localstorage.js diff --git a/js/src/views/Status/middleware/localstorage.spec.js b/js/src/views/RpcCalls/middleware/localstorage.spec.js similarity index 100% rename from js/src/views/Status/middleware/localstorage.spec.js rename to js/src/views/RpcCalls/middleware/localstorage.spec.js diff --git a/js/src/views/Status/actions/app.js b/js/src/views/RpcCalls/reducers/index.js similarity index 87% rename from js/src/views/Status/actions/app.js rename to js/src/views/RpcCalls/reducers/index.js index 9c91101d9..4f57dd311 100644 --- a/js/src/views/Status/actions/app.js +++ b/js/src/views/RpcCalls/reducers/index.js @@ -14,6 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import { createAction } from 'redux-actions'; +import rpc from './rpc'; +import logger from './logger'; -export const initAppAction = createAction('init app'); +export { + rpc, + logger +}; diff --git a/js/src/views/Status/reducers/logger.js b/js/src/views/RpcCalls/reducers/logger.js similarity index 100% rename from js/src/views/Status/reducers/logger.js rename to js/src/views/RpcCalls/reducers/logger.js diff --git a/js/src/views/Status/reducers/rpc.js b/js/src/views/RpcCalls/reducers/rpc.js similarity index 100% rename from js/src/views/Status/reducers/rpc.js rename to js/src/views/RpcCalls/reducers/rpc.js diff --git a/js/src/views/Status/util/error.js b/js/src/views/RpcCalls/util/error.js similarity index 100% rename from js/src/views/Status/util/error.js rename to js/src/views/RpcCalls/util/error.js diff --git a/js/src/views/Status/util/error.spec.js b/js/src/views/RpcCalls/util/error.spec.js similarity index 100% rename from js/src/views/Status/util/error.spec.js rename to js/src/views/RpcCalls/util/error.spec.js diff --git a/js/src/views/Status/util/index.js b/js/src/views/RpcCalls/util/index.js similarity index 100% rename from js/src/views/Status/util/index.js rename to js/src/views/RpcCalls/util/index.js diff --git a/js/src/views/Status/util/index.spec.js b/js/src/views/RpcCalls/util/index.spec.js similarity index 100% rename from js/src/views/Status/util/index.spec.js rename to js/src/views/RpcCalls/util/index.spec.js diff --git a/js/src/views/Status/util/react.js b/js/src/views/RpcCalls/util/react.js similarity index 100% rename from js/src/views/Status/util/react.js rename to js/src/views/RpcCalls/util/react.js diff --git a/js/src/views/Status/util/rpc-md.js b/js/src/views/RpcCalls/util/rpc-md.js similarity index 100% rename from js/src/views/Status/util/rpc-md.js rename to js/src/views/RpcCalls/util/rpc-md.js diff --git a/js/src/views/Status/components/Debug/debug.css b/js/src/views/Status/Debug/debug.css similarity index 98% rename from js/src/views/Status/components/Debug/debug.css rename to js/src/views/Status/Debug/debug.css index 833ce4fdb..70e929a59 100644 --- a/js/src/views/Status/components/Debug/debug.css +++ b/js/src/views/Status/Debug/debug.css @@ -43,6 +43,7 @@ .log { font-family: monospace; + font-size: 0.9em; white-space: pre-line; word-wrap: break-word; color: #aaa; diff --git a/js/src/views/Status/components/Debug/debug.js b/js/src/views/Status/Debug/debug.js similarity index 63% rename from js/src/views/Status/components/Debug/debug.js rename to js/src/views/Status/Debug/debug.js index ed423572f..a0b91a3f2 100644 --- a/js/src/views/Status/components/Debug/debug.js +++ b/js/src/views/Status/Debug/debug.js @@ -14,30 +14,30 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +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 ( { this.renderActions() }

- { devLogsLevels || '-' } + { logsLevels || '-' }

{ 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 ( -

- { log } -

- ); - } - return (

- { logDate[1] } - { logDate[2] } + [{ log.date.toLocaleString() }] + { log.log }

); }); @@ -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 ? : ; @@ -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(); + }; } diff --git a/js/src/views/Status/components/Debug/index.js b/js/src/views/Status/Debug/index.js similarity index 100% rename from js/src/views/Status/components/Debug/index.js rename to js/src/views/Status/Debug/index.js diff --git a/js/src/views/Status/Debug/store.js b/js/src/views/Status/Debug/store.js new file mode 100644 index 000000000..22466b7f9 --- /dev/null +++ b/js/src/views/Status/Debug/store.js @@ -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 . + +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(); + }); + } +} diff --git a/js/src/views/Status/components/MiningSettings/decodeExtraData.js b/js/src/views/Status/MiningSettings/decodeExtraData.js similarity index 100% rename from js/src/views/Status/components/MiningSettings/decodeExtraData.js rename to js/src/views/Status/MiningSettings/decodeExtraData.js diff --git a/js/src/views/Status/components/MiningSettings/decodeExtraData.spec.js b/js/src/views/Status/MiningSettings/decodeExtraData.spec.js similarity index 100% rename from js/src/views/Status/components/MiningSettings/decodeExtraData.spec.js rename to js/src/views/Status/MiningSettings/decodeExtraData.spec.js diff --git a/js/src/views/Status/components/MiningSettings/index.js b/js/src/views/Status/MiningSettings/index.js similarity index 100% rename from js/src/views/Status/components/MiningSettings/index.js rename to js/src/views/Status/MiningSettings/index.js diff --git a/js/src/views/Status/components/MiningSettings/miningSettings.js b/js/src/views/Status/MiningSettings/miningSettings.js similarity index 76% rename from js/src/views/Status/components/MiningSettings/miningSettings.js rename to js/src/views/Status/MiningSettings/miningSettings.js index 6e51b891a..32209cd24 100644 --- a/js/src/views/Status/components/MiningSettings/miningSettings.js +++ b/js/src/views/Status/MiningSettings/miningSettings.js @@ -14,11 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +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 { /> } /> - } + param='address' value={ coinbase } - onSubmit={ this.onAuthorChange } + onChange={ this.onAuthorChange } allowCopy - floatCopy - { ...this._test('author') } /> } - value={ extradata } + value={ decodedExtraData } onSubmit={ this.onExtraDataChange } - defaultValue={ defaultExtradata } allowCopy - floatCopy - { ...this._test('extra-data') } />
); @@ -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(); + } } diff --git a/js/src/views/Status/components/MiningSettings/numberFromString.js b/js/src/views/Status/MiningSettings/numberFromString.js similarity index 100% rename from js/src/views/Status/components/MiningSettings/numberFromString.js rename to js/src/views/Status/MiningSettings/numberFromString.js diff --git a/js/src/views/Status/components/MiningSettings/numberFromString.spec.js b/js/src/views/Status/MiningSettings/numberFromString.spec.js similarity index 100% rename from js/src/views/Status/components/MiningSettings/numberFromString.spec.js rename to js/src/views/Status/MiningSettings/numberFromString.spec.js diff --git a/js/src/views/Status/containers/StatusPage/index.js b/js/src/views/Status/Peers/index.js similarity index 95% rename from js/src/views/Status/containers/StatusPage/index.js rename to js/src/views/Status/Peers/index.js index 403c5f08b..a223af63c 100644 --- a/js/src/views/Status/containers/StatusPage/index.js +++ b/js/src/views/Status/Peers/index.js @@ -14,4 +14,4 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -export default from './statusPage'; +export default from './peers'; diff --git a/js/src/views/Status/Peers/peers.css b/js/src/views/Status/Peers/peers.css new file mode 100644 index 000000000..854d91cb0 --- /dev/null +++ b/js/src/views/Status/Peers/peers.css @@ -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 . +*/ + +.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; + } +} diff --git a/js/src/views/Status/Peers/peers.js b/js/src/views/Status/Peers/peers.js new file mode 100644 index 000000000..43fcbff30 --- /dev/null +++ b/js/src/views/Status/Peers/peers.js @@ -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 . + +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 ( + + + } + /> +
+ + + + + + + + + + + + + { this.renderPeers(peers) } + +
+ + + + + + + + + + + + +
+
+
+ ); + } + + renderPeers (peers) { + return peers.map((peer, index) => this.renderPeer(peer, index)); + } + + renderPeer (peer, index) { + const { caps, id, name, network, protocols } = peer; + + return ( + + + { index + 1 } + + + + + + { network.remoteAddress } + + + { name } + + + { + protocols.eth + ? + : null + } + + + { + protocols.eth && protocols.eth.difficulty.gt(0) + ? protocols.eth.difficulty.toExponential(16) + : null + } + + + { + caps && caps.length > 0 + ? caps.join(' - ') + : null + } + + + ); + } +} + +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); diff --git a/js/src/views/Status/components/Status/index.js b/js/src/views/Status/Status/index.js similarity index 100% rename from js/src/views/Status/components/Status/index.js rename to js/src/views/Status/Status/index.js diff --git a/js/src/views/Status/components/Status/status.css b/js/src/views/Status/Status/status.css similarity index 100% rename from js/src/views/Status/components/Status/status.css rename to js/src/views/Status/Status/status.css diff --git a/js/src/views/Status/components/Status/status.js b/js/src/views/Status/Status/status.js similarity index 68% rename from js/src/views/Status/components/Status/status.js rename to js/src/views/Status/Status/status.js index efb0c80f7..3961f0aeb 100644 --- a/js/src/views/Status/components/Status/status.js +++ b/js/src/views/Status/Status/status.js @@ -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 { /> } /> -
- #{ nodeStatus.blockNumber.toFormat() } +
+ #{ blockNumber.toFormat() }
- { moment(nodeStatus.blockTimestamp).calendar() } + { moment(blockTimestamp).calendar() }
@@ -72,7 +90,7 @@ export default class Status extends Component { /> } /> -
+
{ peers }
@@ -85,23 +103,19 @@ export default class Status extends Component { /> } /> -
+
- + { this.renderMiningSettings() }
{ this.renderSettings() } @@ -112,12 +126,27 @@ export default class Status extends Component { ); } + renderMiningSettings () { + const { coinbase, defaultExtraData, extraData, gasFloorTarget, minGasPrice } = this.statusStore; + + return ( + + ); + } + renderNodeName () { - const { nodeStatus } = this.props; + const { nodeName } = this.statusStore; return ( - { nodeStatus.nodeName || ( + { nodeName || ( +
} - value={ nodeStatus.netChain } - { ...this._test('chain') } + value={ netChain } />
@@ -167,12 +194,25 @@ export default class Status extends Component { readOnly label={ } - value={ peers } - { ...this._test('peers') } + value={ + rpcSettings.enabled + ? ( + + ) + : ( + + ) + } />
@@ -186,37 +226,10 @@ export default class Status extends Component { /> } value={ netPort.toString() } - { ...this._test('network-port') } />
- - } - value={ - rpcSettings.enabled - ? ( - - ) - : ( - - ) - } - { ...this._test('rpc-enabled') } - />
} value={ rpcSettings.interface } - { ...this._test('rpc-interface') } />
@@ -243,7 +255,6 @@ export default class Status extends Component { /> } value={ rpcPort.toString() } - { ...this._test('rpc-port') } />
@@ -259,8 +270,7 @@ export default class Status extends Component { defaultMessage='enode' /> } - value={ nodeStatus.enode } - { ...this._test('node-enode') } + value={ enode } />
@@ -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); diff --git a/js/src/views/Status/Status/store.js b/js/src/views/Status/Status/store.js new file mode 100644 index 000000000..22fe20070 --- /dev/null +++ b/js/src/views/Status/Status/store.js @@ -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 . + +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(); + }; +} diff --git a/js/src/views/Status/actions/clipboard.js b/js/src/views/Status/actions/clipboard.js deleted file mode 100644 index c58f1ef52..000000000 --- a/js/src/views/Status/actions/clipboard.js +++ /dev/null @@ -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 . - -import { createAction } from 'redux-actions'; - -import { identity } from '../util'; -import { withError } from '~/redux/util'; - -export const copyToClipboard = createAction('copy toClipboard', identity, withError(identity)); diff --git a/js/src/views/Status/actions/debug.js b/js/src/views/Status/actions/debug.js deleted file mode 100644 index b1ace8e63..000000000 --- a/js/src/views/Status/actions/debug.js +++ /dev/null @@ -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 . - -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'); diff --git a/js/src/views/Status/actions/mining.js b/js/src/views/Status/actions/mining.js deleted file mode 100644 index 5a1ff11c7..000000000 --- a/js/src/views/Status/actions/mining.js +++ /dev/null @@ -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 . - -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'); diff --git a/js/src/views/Status/actions/modify-mining.js b/js/src/views/Status/actions/modify-mining.js deleted file mode 100644 index e61ce4586..000000000 --- a/js/src/views/Status/actions/modify-mining.js +++ /dev/null @@ -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 . - -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'); diff --git a/js/src/views/Status/actions/status.js b/js/src/views/Status/actions/status.js deleted file mode 100644 index 38261e84f..000000000 --- a/js/src/views/Status/actions/status.js +++ /dev/null @@ -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 . - -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'); diff --git a/js/src/views/Status/containers/StatusPage/statusPage.js b/js/src/views/Status/containers/StatusPage/statusPage.js deleted file mode 100644 index 704a27684..000000000 --- a/js/src/views/Status/containers/StatusPage/statusPage.js +++ /dev/null @@ -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 . - -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 ( -
- - -
- ); - } -} - -function mapStateToProps (state) { - return state; -} - -function mapDispatchToProps (dispatch) { - return { - actions: bindActionCreators({ - clearStatusLogs, - toggleStatusLogs, - toggleStatusRefresh - }, dispatch) - }; -} - -export default connect( - mapStateToProps, - mapDispatchToProps -)(StatusPage); diff --git a/js/src/views/Status/reducers/debug.js b/js/src/views/Status/reducers/debug.js deleted file mode 100644 index ead2db49c..000000000 --- a/js/src/views/Status/reducers/debug.js +++ /dev/null @@ -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 . - -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); diff --git a/js/src/views/Status/reducers/index.js b/js/src/views/Status/reducers/index.js deleted file mode 100644 index 7e749694c..000000000 --- a/js/src/views/Status/reducers/index.js +++ /dev/null @@ -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 . - -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 -}; diff --git a/js/src/views/Status/reducers/mining.js b/js/src/views/Status/reducers/mining.js deleted file mode 100644 index 7a7b17dc4..000000000 --- a/js/src/views/Status/reducers/mining.js +++ /dev/null @@ -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 . - -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); diff --git a/js/src/views/Status/reducers/settings.js b/js/src/views/Status/reducers/settings.js deleted file mode 100644 index 80f2ec36f..000000000 --- a/js/src/views/Status/reducers/settings.js +++ /dev/null @@ -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 . - -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); diff --git a/js/src/views/Status/reducers/status.js b/js/src/views/Status/reducers/status.js deleted file mode 100644 index fdce3bd29..000000000 --- a/js/src/views/Status/reducers/status.js +++ /dev/null @@ -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 . - -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 - }; -} diff --git a/js/src/views/Status/containers/StatusPage/statusPage.css b/js/src/views/Status/status.css similarity index 100% rename from js/src/views/Status/containers/StatusPage/statusPage.css rename to js/src/views/Status/status.css diff --git a/js/src/views/Status/status.js b/js/src/views/Status/status.js index 68621fe9b..0f4c0fce6 100644 --- a/js/src/views/Status/status.js +++ b/js/src/views/Status/status.js @@ -14,26 +14,30 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import React, { Component } from 'react'; +import React from 'react'; import { FormattedMessage } from 'react-intl'; import { Page } from '~/ui'; -import StatusPage from './containers/StatusPage'; +import Debug from './Debug'; +import Peers from './Peers'; +import Status from './Status'; -export default class Status extends Component { - render () { - return ( - - } - > - - - ); - } -} +import styles from './status.css'; + +export default () => ( + + } + > +
+ + + +
+
+);