@@ -279,24 +256,3 @@ class Node extends Component {
);
}
}
-
-function mapStateToProps (state) {
- const {
- blockNumber,
- blockTimestamp,
- netChain,
- netPeers
- } = state.nodeStatus;
-
- return {
- blockNumber,
- blockTimestamp,
- netChain,
- netPeers
- };
-}
-
-export default connect(
- mapStateToProps,
- null
-)(Node);
diff --git a/js/packages/dapp-status/Node/store.js b/js/packages/dapp-status/Node/store.js
index 22fe20070..44d6a5fd9 100644
--- a/js/packages/dapp-status/Node/store.js
+++ b/js/packages/dapp-status/Node/store.js
@@ -15,7 +15,11 @@
// along with Parity. If not, see .
import BigNumber from 'bignumber.js';
-import { action, observable, transaction } from 'mobx';
+import { action, computed, observable, transaction } from 'mobx';
+
+import { NetChain } from '@parity/ui';
+
+console.log('NetChain', NetChain, NetChain.Store);
export default class StatusStore {
@observable defaultExtraData = '';
@@ -35,6 +39,13 @@ export default class StatusStore {
constructor (api) {
this.api = api;
+ this.chainStore = NetChain.Store.get(api);
+
+ this.startPolling();
+ }
+
+ @computed get netChain () {
+ return this.chainStore.netChain;
}
@action setLongStatus ({ defaultExtraData, enode, netPort, rpcSettings }) {
diff --git a/js/packages/dapp-status/status.js b/js/packages/dapp-status/status.js
index cf37ef043..8c3b001f7 100644
--- a/js/packages/dapp-status/status.js
+++ b/js/packages/dapp-status/status.js
@@ -26,6 +26,8 @@ import Peers from './Peers';
import styles from './status.css';
+console.log('Node', Node);
+
export default function Status () {
return (
{
- const status = { netPeers, syncing, health };
-
- health.overall = this._overallStatus(health);
- health.peers = health.peers || {};
- health.sync = health.sync || {};
- health.time = health.time || {};
+ .then(([ syncing, netPeers ]) => {
+ const status = { netPeers, syncing };
if (!isEqual(status, this._status)) {
this._store.dispatch(statusCollection(status));
@@ -234,43 +224,6 @@ export default class Status {
});
}
- _overallStatus = (health) => {
- const all = [health.peers, health.sync, health.time].filter(x => x);
- const statuses = all.map(x => x.status);
- const bad = statuses.find(x => x === STATUS_BAD);
- const needsAttention = statuses.find(x => x === STATUS_WARN);
- const message = all.map(x => x.message).filter(x => x);
-
- if (all.length) {
- return {
- status: bad || needsAttention || STATUS_OK,
- message
- };
- }
-
- return {
- status: STATUS_BAD,
- message: ['Unable to fetch node health.']
- };
- }
-
- _fetchHealth = () => {
- // Support Parity-Extension.
- const uiUrl = this._api.transport.uiUrlWithProtocol || '';
-
- return fetch(`${uiUrl}/api/health`)
- .then((response) => {
- if (!response.ok) {
- return {};
- }
-
- return response.json();
- })
- .catch(() => {
- return {};
- });
- }
-
/**
* The data fetched here should not change
* unless Parity is restarted. They are thus
diff --git a/js/packages/ui/BlockNumber/blockNumber.css b/js/packages/ui/BlockNumber/blockNumber.css
new file mode 100644
index 000000000..4cf6aaf4a
--- /dev/null
+++ b/js/packages/ui/BlockNumber/blockNumber.css
@@ -0,0 +1,21 @@
+/* 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 .
+*/
+
+.blockNumber,
+.syncStatus {
+ display: inline-block;
+}
diff --git a/js/packages/ui/BlockStatus/blockStatus.js b/js/packages/ui/BlockNumber/blockNumber.js
similarity index 59%
rename from js/packages/ui/BlockStatus/blockStatus.js
rename to js/packages/ui/BlockNumber/blockNumber.js
index 9df0c6961..f2b17dc6b 100644
--- a/js/packages/ui/BlockStatus/blockStatus.js
+++ b/js/packages/ui/BlockNumber/blockNumber.js
@@ -15,39 +15,37 @@
// along with Parity. If not, see .
import React from 'react';
-import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
-import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+import { observer } from 'mobx-react';
-import styles from './blockStatus.css';
+import Store from './store';
-function BlockStatus ({ blockNumber, syncing }) {
- if (!blockNumber) {
+import styles from './blockNumber.css';
+
+function BlockNumber ({ className, message }, { api }) {
+ const store = Store.get(api);
+
+ if (!store.blockNumber) {
return null;
}
- if (!syncing) {
+ if (!store.syncing) {
return (
-
-
+
+ { store.blockNumber.toFormat() }{ message }
);
}
- if (syncing.warpChunksAmount && syncing.warpChunksProcessed && !syncing.warpChunksAmount.eq(syncing.warpChunksProcessed)) {
+ if (store.syncing.warpChunksAmount && store.syncing.warpChunksProcessed && !store.syncing.warpChunksAmount.eq(store.syncing.warpChunksProcessed)) {
return (
@@ -57,23 +55,23 @@ function BlockStatus ({ blockNumber, syncing }) {
let syncStatus = null;
let warpStatus = null;
- if (syncing.currentBlock && syncing.highestBlock) {
+ if (store.syncing.currentBlock && store.syncing.highestBlock) {
syncStatus = (
);
}
- if (syncing.blockGap) {
- const [first, last] = syncing.blockGap;
+ if (store.syncing.blockGap) {
+ const [first, last] = store.syncing.blockGap;
warpStatus = (
@@ -96,24 +94,17 @@ function BlockStatus ({ blockNumber, syncing }) {
);
}
-BlockStatus.propTypes = {
- blockNumber: PropTypes.object,
- syncing: PropTypes.oneOfType([
- PropTypes.bool,
- PropTypes.object
- ])
+BlockNumber.propTypes = {
+ className: PropTypes.string,
+ message: PropTypes.node
};
-function mapStateToProps (state) {
- const { blockNumber, syncing } = state.nodeStatus;
+BlockNumber.contextTypes = {
+ api: PropTypes.object.isRequired
+};
- return {
- blockNumber,
- syncing
- };
-}
+const ObserverComponent = observer(BlockNumber);
-export default connect(
- mapStateToProps,
- null
-)(BlockStatus);
+ObserverComponent.Store = Store;
+
+export default ObserverComponent;
diff --git a/js/packages/ui/BlockStatus/index.js b/js/packages/ui/BlockNumber/index.js
similarity index 95%
rename from js/packages/ui/BlockStatus/index.js
rename to js/packages/ui/BlockNumber/index.js
index 904ad512d..f44b433b5 100644
--- a/js/packages/ui/BlockStatus/index.js
+++ b/js/packages/ui/BlockNumber/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 './blockStatus';
+export default from './blockNumber';
diff --git a/js/packages/ui/BlockNumber/store.js b/js/packages/ui/BlockNumber/store.js
new file mode 100644
index 000000000..a3dd6bfbd
--- /dev/null
+++ b/js/packages/ui/BlockNumber/store.js
@@ -0,0 +1,79 @@
+// 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 } from 'mobx';
+
+export default class Store {
+ @observable blockNumber = null;
+ @observable blockTimestamp = null;
+ @observable syncing = null;
+
+ constructor (api) {
+ this._api = api;
+ this._api.on('connected', this.setupSubscriptions, this);
+
+ // Connected and/or events NOT available
+ if (this._api.isConnected) {
+ this.setupSubscriptions();
+ }
+ }
+
+ setupSubscriptions = () => {
+ this._api.pubsub.eth.syncing((error, syncing) => {
+ if (!error) {
+ this.setSyncing(syncing);
+ }
+ });
+
+ this._api.pubsub.eth.blockNumber((error, blockNumber) => {
+ if (!error) {
+ this.setBlockNumber(blockNumber);
+ }
+
+ this._api.parity
+ .getBlockHeaderByNumber(blockNumber)
+ .then((block) => {
+ if (!block) {
+ return;
+ }
+
+ this.setBlockTimestamp(block.timestamp);
+ });
+ });
+ }
+
+ @action setBlockNumber = (blockNumber) => {
+ this.blockNumber = blockNumber;
+ }
+
+ @action setBlockTimestamp = (blockTimestamp) => {
+ this.blockTimestamp = blockTimestamp;
+ }
+
+ @action setSyncing = (syncing) => {
+ this.syncing = syncing;
+ }
+
+ static instance = null;
+
+ static get (api) {
+ if (!Store.instance) {
+ Store.instance = new Store(api);
+ }
+
+ return Store.instance;
+ }
+}
diff --git a/js/packages/ui/BlockStatus/blockStatus.spec.js b/js/packages/ui/BlockStatus/blockStatus.spec.js
deleted file mode 100644
index 277c286c5..000000000
--- a/js/packages/ui/BlockStatus/blockStatus.spec.js
+++ /dev/null
@@ -1,94 +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 BigNumber from 'bignumber.js';
-import { shallow } from 'enzyme';
-import React from 'react';
-import sinon from 'sinon';
-
-import BlockStatus from './';
-
-let component;
-
-function createRedux (syncing = false, blockNumber = new BigNumber(123)) {
- return {
- dispatch: sinon.stub(),
- subscribe: sinon.stub(),
- getState: () => {
- return {
- nodeStatus: {
- blockNumber,
- syncing
- }
- };
- }
- };
-}
-
-function render (reduxStore = createRedux(), props) {
- component = shallow(
- ,
- { context: { store: reduxStore } }
- ).find('BlockStatus').shallow();
-
- return component;
-}
-
-describe('ui/BlockStatus', () => {
- it('renders defaults', () => {
- expect(render()).to.be.ok;
- });
-
- it('renders null with no blockNumber', () => {
- expect(render(createRedux(false, null)).find('div')).to.have.length(0);
- });
-
- it('renders only the best block when syncing === false', () => {
- const messages = render().find('FormattedMessage');
-
- expect(messages).to.have.length(1);
- expect(messages).to.have.id('ui.blockStatus.bestBlock');
- });
-
- it('renders only the warp restore status when restoring', () => {
- const messages = render(createRedux({
- warpChunksAmount: new BigNumber(100),
- warpChunksProcessed: new BigNumber(5)
- })).find('FormattedMessage');
-
- expect(messages).to.have.length(1);
- expect(messages).to.have.id('ui.blockStatus.warpRestore');
- });
-
- it('renders the current/highest when syncing', () => {
- const messages = render(createRedux({
- currentBlock: new BigNumber(123),
- highestBlock: new BigNumber(456)
- })).find('FormattedMessage');
-
- expect(messages).to.have.length(1);
- expect(messages).to.have.id('ui.blockStatus.syncStatus');
- });
-
- it('renders warp blockGap when catching up', () => {
- const messages = render(createRedux({
- blockGap: [new BigNumber(123), new BigNumber(456)]
- })).find('FormattedMessage');
-
- expect(messages).to.have.length(1);
- expect(messages).to.have.id('ui.blockStatus.warpStatus');
- });
-});
diff --git a/js/packages/ui/BlockTimestamp/blockTimestamp.css b/js/packages/ui/BlockTimestamp/blockTimestamp.css
new file mode 100644
index 000000000..84a3f7354
--- /dev/null
+++ b/js/packages/ui/BlockTimestamp/blockTimestamp.css
@@ -0,0 +1,20 @@
+/* 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 .
+*/
+
+.blockTimestamp {
+ display: inline-block;
+}
diff --git a/js/packages/ui/BlockTimestamp/blockTimestamp.js b/js/packages/ui/BlockTimestamp/blockTimestamp.js
new file mode 100644
index 000000000..d63467f72
--- /dev/null
+++ b/js/packages/ui/BlockTimestamp/blockTimestamp.js
@@ -0,0 +1,52 @@
+// 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 from 'react';
+import PropTypes from 'prop-types';
+import { observer } from 'mobx-react';
+import moment from 'moment';
+
+import Store from '../BlockNumber/store';
+
+import styles from './blockTimestamp.css';
+
+function BlockTimestamp ({ className }, { api }) {
+ const store = Store.get(api);
+
+ if (!store.blockTimestamp) {
+ return null;
+ }
+
+ return (
+
+ { moment(store.blockTimestamp).calendar() }
+
+ );
+}
+
+BlockTimestamp.propTypes = {
+ className: PropTypes.string
+};
+
+BlockTimestamp.contextTypes = {
+ api: PropTypes.object.isRequired
+};
+
+const ObserverComponent = observer(BlockTimestamp);
+
+ObserverComponent.Store = Store;
+
+export default ObserverComponent;
diff --git a/js/packages/ui/BlockTimestamp/index.js b/js/packages/ui/BlockTimestamp/index.js
new file mode 100644
index 000000000..0a14293ad
--- /dev/null
+++ b/js/packages/ui/BlockTimestamp/index.js
@@ -0,0 +1,17 @@
+// Copyright 2015-2017 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+export default from './blockTimestamp';
diff --git a/js/packages/ui/ClientVersion/clientVersion.css b/js/packages/ui/ClientVersion/clientVersion.css
new file mode 100644
index 000000000..3a9d1c224
--- /dev/null
+++ b/js/packages/ui/ClientVersion/clientVersion.css
@@ -0,0 +1,20 @@
+/* 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 .
+*/
+
+.clientVersion {
+ display: inline-block;
+}
diff --git a/js/packages/ui/ClientVersion/clientVersion.js b/js/packages/ui/ClientVersion/clientVersion.js
new file mode 100644
index 000000000..c40d3135f
--- /dev/null
+++ b/js/packages/ui/ClientVersion/clientVersion.js
@@ -0,0 +1,52 @@
+// 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 from 'react';
+import PropTypes from 'prop-types';
+import { observer } from 'mobx-react';
+
+import Store from './store';
+
+import styles from './clientVersion.css';
+
+function ClientVersion ({ className }, { api }) {
+ const store = Store.get(api);
+
+ if (!store.clientVersion) {
+ return null;
+ }
+
+ const [ clientName, , versionString, , ] = store.clientVersion.split('/');
+ const [ versionNumber, versionType, , versionDate ] = (versionString || '').split('-');
+
+ return (
+
+ );
+}
+
+ClientVersion.propTypes = {
+ className: PropTypes.string
+};
+
+ClientVersion.contextTypes = {
+ api: PropTypes.object.isRequired
+};
+
+ClientVersion.Store = Store;
+
+export default observer(ClientVersion);
diff --git a/js/packages/ui/ClientVersion/index.js b/js/packages/ui/ClientVersion/index.js
new file mode 100644
index 000000000..8003639fa
--- /dev/null
+++ b/js/packages/ui/ClientVersion/index.js
@@ -0,0 +1,17 @@
+// Copyright 2015-2017 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+export default from './clientVersion';
diff --git a/js/packages/ui/ClientVersion/store.js b/js/packages/ui/ClientVersion/store.js
new file mode 100644
index 000000000..3d2044c59
--- /dev/null
+++ b/js/packages/ui/ClientVersion/store.js
@@ -0,0 +1,50 @@
+// 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 } from 'mobx';
+
+export default class Store {
+ @observable clientVersion = '';
+
+ constructor (api) {
+ this._api = api;
+ this._api.on('connected', this.setupSubscriptions, this);
+
+ if (this._api.isConnected) {
+ this.setupSubscriptions();
+ }
+ }
+
+ setupSubscriptions = () => {
+ this._api.web3
+ .clientVersion()
+ .then(this.setClientVersion);
+ }
+
+ @action setClientVersion = (clientVersion) => {
+ this.clientVersion = clientVersion;
+ }
+
+ static instance = null;
+
+ static get (api) {
+ if (!Store.instance) {
+ Store.instance = new Store(api);
+ }
+
+ return Store.instance;
+ }
+}
diff --git a/js/packages/ui/CurrencySymbol/currencySymbol.js b/js/packages/ui/CurrencySymbol/currencySymbol.js
index 8698d070c..7fc4d7739 100644
--- a/js/packages/ui/CurrencySymbol/currencySymbol.js
+++ b/js/packages/ui/CurrencySymbol/currencySymbol.js
@@ -14,53 +14,45 @@
// 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 PropTypes from 'prop-types';
-import { connect } from 'react-redux';
+import { observer } from 'mobx-react';
+
+import Store from '../NetChain/store';
const SYMBOL_ETC = 'ETC';
const SYMBOL_ETH = 'ETH';
const SYMBOL_EXP = 'EXP';
-export class CurrencySymbol extends Component {
- static propTypes = {
- className: PropTypes.string,
- netChain: PropTypes.string.isRequired
- }
+function renderSymbol (netChain) {
+ switch (netChain) {
+ case 'classic':
+ return SYMBOL_ETC;
- render () {
- const { className } = this.props;
+ case 'expanse':
+ return SYMBOL_EXP;
- return (
- { this.renderSymbol() }
- );
- }
-
- renderSymbol () {
- const { netChain } = this.props;
-
- switch (netChain) {
- case 'classic':
- return SYMBOL_ETC;
-
- case 'expanse':
- return SYMBOL_EXP;
-
- default:
- return SYMBOL_ETH;
- }
+ default:
+ return SYMBOL_ETH;
}
}
-function mapStateToProps (state) {
- const { netChain } = state.nodeStatus;
+function CurrencySymbol ({ className }, { api }) {
+ const store = Store.get(api);
- return {
- netChain
- };
+ return (
+
+ { renderSymbol(store.netChain) }
+
+ );
}
-export default connect(
- mapStateToProps,
- null
-)(CurrencySymbol);
+CurrencySymbol.propTypes = {
+ className: PropTypes.string
+};
+
+CurrencySymbol.contextTypes = {
+ api: PropTypes.object.isRequired
+};
+
+export default observer(CurrencySymbol);
diff --git a/js/packages/ui/CurrencySymbol/currencySymbol.spec.js b/js/packages/ui/CurrencySymbol/currencySymbol.spec.js
deleted file mode 100644
index e705b5edc..000000000
--- a/js/packages/ui/CurrencySymbol/currencySymbol.spec.js
+++ /dev/null
@@ -1,99 +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 { shallow } from 'enzyme';
-import React from 'react';
-import sinon from 'sinon';
-
-import CurrencySymbol from './';
-
-let component;
-let store;
-
-function createRedux (netChain = 'ropsten') {
- store = {
- dispatch: sinon.stub(),
- subscribe: sinon.stub(),
- getState: () => {
- return {
- nodeStatus: {
- netChain
- }
- };
- }
- };
-
- return store;
-}
-
-function render (netChain, props = {}) {
- component = shallow(
- ,
- {
- context: {
- store: createRedux(netChain)
- }
- }
- ).find('CurrencySymbol').shallow();
-
- return component;
-}
-
-describe('ui/CurrencySymbol', () => {
- it('renders defaults', () => {
- expect(render()).to.be.ok;
- });
-
- it('passes the className as provided', () => {
- expect(render('ropsten', { className: 'test' }).find('span').hasClass('test')).to.be.true;
- });
-
- describe('currencies', () => {
- it('renders ETH as default', () => {
- expect(render().text()).equal('ETH');
- });
-
- it('renders ETC for classic', () => {
- expect(render('classic').text()).equal('ETC');
- });
-
- it('renders EXP for expanse', () => {
- expect(render('expanse').text()).equal('EXP');
- });
-
- it('renders ETH as default', () => {
- expect(render('somethingElse').text()).equal('ETH');
- });
- });
-
- describe('renderSymbol', () => {
- it('render defaults', () => {
- expect(render().instance().renderSymbol()).to.be.ok;
- });
-
- it('render ETH as default', () => {
- expect(render().instance().renderSymbol()).equal('ETH');
- });
-
- it('render ETC', () => {
- expect(render('classic').instance().renderSymbol()).equal('ETC');
- });
-
- it('render EXP', () => {
- expect(render('expanse').instance().renderSymbol()).equal('EXP');
- });
- });
-});
diff --git a/js/packages/ui/NetChain/index.js b/js/packages/ui/NetChain/index.js
new file mode 100644
index 000000000..31b62d1db
--- /dev/null
+++ b/js/packages/ui/NetChain/index.js
@@ -0,0 +1,17 @@
+// Copyright 2015-2017 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+export default from './netChain';
diff --git a/js/packages/ui/NetChain/netChain.css b/js/packages/ui/NetChain/netChain.css
new file mode 100644
index 000000000..8bca8f20c
--- /dev/null
+++ b/js/packages/ui/NetChain/netChain.css
@@ -0,0 +1,34 @@
+/* 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 .
+*/
+
+$networkLiveColor: rgb(0, 136, 0);
+$networkTestColor: rgb(136, 0, 0);
+
+.chain {
+ border-radius: 0.4em;
+ line-height: 1.2;
+ padding: 0.25em 0.5em;
+ text-transform: uppercase;
+
+ &.live {
+ background: $networkLiveColor;
+ }
+
+ &.test {
+ background: $networkTestColor;
+ }
+}
diff --git a/js/packages/ui/NetChain/netChain.js b/js/packages/ui/NetChain/netChain.js
new file mode 100644
index 000000000..7e1bc715a
--- /dev/null
+++ b/js/packages/ui/NetChain/netChain.js
@@ -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 .
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import { observer } from 'mobx-react';
+
+import Store from './store';
+
+import styles from './netChain.css';
+
+function NetChain ({ className }, { api }) {
+ const store = Store.get(api);
+
+ return (
+
+ { store.netChain }
+
+ );
+}
+
+NetChain.propTypes = {
+ className: PropTypes.string
+};
+
+NetChain.contextTypes = {
+ api: PropTypes.object.isRequired
+};
+
+const ObserverComponent = observer(NetChain);
+
+ObserverComponent.Store = Store;
+
+export default ObserverComponent;
diff --git a/js/src/Status/store.js b/js/packages/ui/NetChain/store.js
similarity index 76%
rename from js/src/Status/store.js
rename to js/packages/ui/NetChain/store.js
index b81862442..9f3318e35 100644
--- a/js/src/Status/store.js
+++ b/js/packages/ui/NetChain/store.js
@@ -19,9 +19,7 @@ import { action, computed, observable } from 'mobx';
import { isTestnet } from '@parity/shared/util/testnet';
export default class Store {
- @observable clientVersion = '';
@observable netChain = '';
- @observable netPeers = {};
@observable netVersion = 1;
constructor (api) {
@@ -38,39 +36,21 @@ export default class Store {
if (!error) {
this.setNetChain(netChain);
}
+
+ this._api.net
+ .version()
+ .then(this.setNetVersion);
});
-
- this._api.pubsub.parity.netPeers((error, netPeers) => {
- if (!error) {
- this.setNetPeers(netPeers);
- }
- });
-
- this._api.net
- .version()
- .then(this.setNetVersion);
-
- this._api.web3
- .clientVersion()
- .then(this.setClientVersion);
}
@computed get isTest () {
return isTestnet(this.netVersion);
}
- @action setClientVersion = (clientVersion) => {
- this.clientVersion = clientVersion;
- }
-
@action setNetChain = (netChain) => {
this.netChain = netChain;
}
- @action setNetPeers = (netPeers) => {
- this.netPeers = netPeers;
- }
-
@action setNetVersion = (netVersion) => {
this.netVersion = netVersion;
}
diff --git a/js/packages/ui/NetPeers/index.js b/js/packages/ui/NetPeers/index.js
new file mode 100644
index 000000000..6111a2f93
--- /dev/null
+++ b/js/packages/ui/NetPeers/index.js
@@ -0,0 +1,17 @@
+// Copyright 2015-2017 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+export default from './netPeers';
diff --git a/js/packages/ui/BlockStatus/blockStatus.css b/js/packages/ui/NetPeers/netPeers.css
similarity index 95%
rename from js/packages/ui/BlockStatus/blockStatus.css
rename to js/packages/ui/NetPeers/netPeers.css
index d5e8a655d..aa5b47699 100644
--- a/js/packages/ui/BlockStatus/blockStatus.css
+++ b/js/packages/ui/NetPeers/netPeers.css
@@ -15,8 +15,6 @@
/* along with Parity. If not, see .
*/
-.blockNumber {
-}
-
-.syncStatus {
+.peers {
+ display: inline-block;
}
diff --git a/js/packages/ui/NetPeers/netPeers.js b/js/packages/ui/NetPeers/netPeers.js
new file mode 100644
index 000000000..ca81a575c
--- /dev/null
+++ b/js/packages/ui/NetPeers/netPeers.js
@@ -0,0 +1,54 @@
+// 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 from 'react';
+import PropTypes from 'prop-types';
+import { observer } from 'mobx-react';
+
+import Store from './store';
+
+import styles from './netPeers.css';
+
+function NetPeers ({ className, message }, { api }) {
+ const store = Store.get(api);
+
+ if (!store.netPeers) {
+ return null;
+ }
+
+ const { max, connected } = store.netPeers;
+
+ return (
+
)
+ )
+ }
+
+ )
+ : null
+ }
+
+ );
}
+
+StatusIndicator.propTypes = {
+ type: PropTypes.oneOf([
+ 'radial', 'signal'
+ ]),
+ id: PropTypes.string.isRequired,
+ status: PropTypes.oneOf(statuses),
+ title: PropTypes.arrayOf(PropTypes.node),
+ tooltipPlacement: PropTypes.oneOf([
+ 'left', 'top', 'bottom', 'right'
+ ])
+};
+
+StatusIndicator.contextTypes = {
+ api: PropTypes.object.isRequired
+};
+
+const ObserverComponent = observer(StatusIndicator);
+
+ObserverComponent.Store = Store;
+
+export default ObserverComponent;
diff --git a/js/packages/ui/StatusIndicator/store.js b/js/packages/ui/StatusIndicator/store.js
new file mode 100644
index 000000000..c32e68c3d
--- /dev/null
+++ b/js/packages/ui/StatusIndicator/store.js
@@ -0,0 +1,106 @@
+// 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, computed, observable } from 'mobx';
+
+const STATUS_OK = 'ok';
+const STATUS_WARN = 'needsAttention';
+const STATUS_BAD = 'bad';
+const EMPTY_OVERALL = { message: [], status: STATUS_BAD };
+
+export default class Store {
+ @observable _health = null;
+
+ constructor (api) {
+ this._api = api;
+
+ setInterval(this.fetchHealth, 2500);
+ }
+
+ @computed get health () {
+ return this._health
+ ? this._health
+ : {};
+ }
+
+ @computed get overall () {
+ return this._health
+ ? this._health.overall
+ : EMPTY_OVERALL;
+ }
+
+ fetchHealth = () => {
+ // Support Parity-Extension.
+ const uiUrl = this._api.transport.uiUrlWithProtocol || '';
+
+ return fetch(`${uiUrl}/api/health`)
+ .then((response) => {
+ if (!response.ok) {
+ return null;
+ }
+
+ return response.json();
+ })
+ .catch(() => {
+ return null;
+ })
+ .then(this.setHealth);
+ }
+
+ _overallStatus = (health) => {
+ const all = [health.peers, health.sync, health.time].filter(x => x);
+ const statuses = all.map(x => x.status);
+ const bad = statuses.find(x => x === STATUS_BAD);
+ const needsAttention = statuses.find(x => x === STATUS_WARN);
+ const message = all.map(x => x.message).filter(x => x);
+
+ if (all.length) {
+ return {
+ status: bad || needsAttention || STATUS_OK,
+ message
+ };
+ }
+
+ return {
+ status: STATUS_BAD,
+ message: ['Unable to fetch node health.']
+ };
+ }
+
+ @action setHealth = (health) => {
+ if (!health) {
+ this._health = null;
+ return;
+ }
+
+ health.peers = health.peers || {};
+ health.sync = health.sync || {};
+ health.time = health.time || {};
+ health.overall = this._overallStatus(health);
+
+ this._health = health;
+ }
+
+ static instance = null;
+
+ static get (api) {
+ if (!Store.instance) {
+ Store.instance = new Store(api);
+ }
+
+ return Store.instance;
+ }
+}
diff --git a/js/packages/ui/index.js b/js/packages/ui/index.js
index de8b2d03e..54ec9f521 100644
--- a/js/packages/ui/index.js
+++ b/js/packages/ui/index.js
@@ -20,9 +20,11 @@ export AccountCard from './AccountCard';
export Actionbar, { Export as ActionbarExport, Import as ActionbarImport, Search as ActionbarSearch, Sort as ActionbarSort } from './Actionbar';
export Badge from './Badge';
export Balance from './Balance';
-export BlockStatus from './BlockStatus';
+export BlockNumber from './BlockNumber';
+export BlockTimestamp from './BlockTimestamp';
export Button from './Button';
export Certifications from './Certifications';
+export ClientVersion from './ClientVersion';
export ConfirmDialog from './ConfirmDialog';
export Container, { Title as ContainerTitle } from './Container';
export ContextProvider from './ContextProvider';
@@ -46,6 +48,8 @@ export Loading from './Loading';
export MethodDecoding from './MethodDecoding';
export { Busy as BusyStep, Completed as CompletedStep } from './Modal';
export ModalBox from './ModalBox';
+export NetChain from './NetChain';
+export NetPeers from './NetPeers';
export Page from './Page';
export Popup from './Popup';
export Portal from './Portal';
diff --git a/js/src/Application.orig/Status/status.js b/js/src/Application.orig/Status/status.js
deleted file mode 100644
index ae112170e..000000000
--- a/js/src/Application.orig/Status/status.js
+++ /dev/null
@@ -1,155 +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 } from 'react';
-import PropTypes from 'prop-types';
-import { FormattedMessage } from 'react-intl';
-import { connect } from 'react-redux';
-
-import { BlockStatus, StatusIndicator } from '@parity/ui';
-
-import styles from './status.css';
-
-class Status extends Component {
- static propTypes = {
- clientVersion: PropTypes.string,
- isTest: PropTypes.bool,
- netChain: PropTypes.string,
- netPeers: PropTypes.object,
- health: PropTypes.object,
- upgradeStore: PropTypes.object.isRequired
- }
-
- render () {
- const { clientVersion, isTest, netChain, netPeers, health } = this.props;
-
- return (
-
- );
- }
-}
-
-function mapStateToProps (state) {
- const { clientVersion, health, netPeers, netChain, isTest } = state.nodeStatus;
-
- return {
- clientVersion,
- health,
- netPeers,
- netChain,
- isTest
- };
-}
-
-export default connect(
- mapStateToProps,
- null
-)(Status);
diff --git a/js/src/Application.orig/TabBar/tabBar.css b/js/src/Application.orig/TabBar/tabBar.css
deleted file mode 100644
index fa8478f8b..000000000
--- a/js/src/Application.orig/TabBar/tabBar.css
+++ /dev/null
@@ -1,100 +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 .
-*/
-
-.toolbar {
- background: none !important;
- height: 72px !important;
- position: relative;
-}
-
-.tabs {
- width: 100%;
- position: relative;
- display: flex;
-
- & > * {
- flex: 1;
- }
-}
-
-.tabLink {
- display: flex;
-
- > * {
- flex: 1;
- }
-
- &:hover {
- background: rgba(0, 0, 0, 0.4) !important;
- }
-
- &.tabactive, &.tabactive:hover {
- background: rgba(0, 0, 0, 0.25) !important;
- border-radius: 4px 4px 0 0;
-
- * {
- color: white !important;
- }
- }
-}
-
-.tabLink,
-.settings,
-.first,
-.last {
- background: rgba(0, 0, 0, 0.5) !important; /* rgba(0, 0, 0, 0.25) !important; */
-}
-
-.tabbarTooltip {
- left: 3em;
- top: 4em;
-}
-
-.label {
- position: relative;
-}
-
-.labelBubble {
- position: absolute;
- top: -12px;
- right: -12px;
-}
-
-.first,
-.last {
- margin: 0;
- padding: 36px 12px;
- white-space: nowrap;
-}
-
-.indicatorTab {
- font-size: 1.5rem;
- flex: 0;
-}
-
-.indicator {
- padding: 20px 12px 0;
- opacity: 0.8;
-}
-
-.first {
- margin-left: -24px;
-}
-
-.last {
- margin-right: -24px;
-}
diff --git a/js/src/Application.orig/TabBar/tabBar.js b/js/src/Application.orig/TabBar/tabBar.js
deleted file mode 100644
index 6caeb0c8a..000000000
--- a/js/src/Application.orig/TabBar/tabBar.js
+++ /dev/null
@@ -1,153 +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 } from 'react';
-import PropTypes from 'prop-types';
-import { FormattedMessage } from 'react-intl';
-import { connect } from 'react-redux';
-import { Link } from 'react-router';
-import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
-import { isEqual } from 'lodash';
-
-import { Tooltip, StatusIndicator } from '@parity/ui';
-
-import Tab from './Tab';
-import styles from './tabBar.css';
-
-class TabBar extends Component {
- static contextTypes = {
- router: PropTypes.object.isRequired
- };
-
- static propTypes = {
- pending: PropTypes.array,
- health: PropTypes.object.isRequired,
- views: PropTypes.array.isRequired
- };
-
- static defaultProps = {
- pending: []
- };
-
- render () {
- const { health } = this.props;
-
- return (
-
-
-
-
-