Ui 2 pubsub components (#6152)

* Remove Application.orig from merge

* Disable i18n extraction for development

* Retrieve blockNumber via pubsub

* Chain via pubsub

* StatusIndicator with health

* WIP

* WIP

* s/BlockStatus/BlockNumber/

* Adjust BlockNumber display

* Cleanup debug

* Fix statusbar indicator

* NetPeers component

* Add BlockTimestamp

* Export statics on observer

* Cleanup debug logs

* Update references
This commit is contained in:
Jaco Greeff
2017-07-26 16:54:47 +02:00
committed by GitHub
parent 09e40c2f0d
commit a068f72f08
41 changed files with 891 additions and 927 deletions

View File

@@ -68,10 +68,12 @@
height: .4em;
border-right: 0;
}
&.needsAttention {
height: .6em;
border-right: 0;
}
&.ok {
height: 1em;
}
@@ -80,9 +82,11 @@
&.bad > .bar.active {
background-color: #c00;
}
&.ok > .bar.active {
background-color: #080;
}
&.needsAttention > .bar.active {
background-color: #dc0;
}

View File

@@ -14,58 +14,86 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import ReactTooltip from 'react-tooltip';
import { observer } from 'mobx-react';
import Store from './store';
import styles from './statusIndicator.css';
const statuses = ['bad', 'needsAttention', 'ok'];
export default class StatusIndicator extends Component {
static propTypes = {
type: PropTypes.oneOf(['radial', 'signal']),
id: PropTypes.string.isRequired,
status: PropTypes.oneOf(statuses).isRequired,
title: PropTypes.arrayOf(PropTypes.node),
tooltipPlacement: PropTypes.oneOf(['left', 'top', 'bottom', 'right'])
};
function StatusIndicator ({ id, status, title = [], tooltipPlacement, type = 'signal' }, { api }) {
const store = Store.get(api);
const checkStatus = status || store.overall.status;
const message = title.length
? title
: store.overall.message;
static defaultProps = {
type: 'signal',
title: []
};
return (
<span className={ styles.status }>
<span
className={ `${styles[type]} ${styles[checkStatus]}` }
data-tip={ message.length }
data-for={ `status-${id}` }
data-place={ tooltipPlacement }
data-effect='solid'
>
{
type === 'signal'
? statuses.map((signal) => {
const index = statuses.indexOf(checkStatus);
const isActive = statuses.indexOf(signal) <= index;
render () {
const { id, status, title, type, tooltipPlacement } = this.props;
const tooltip = title.find(x => !x.isEmpty) ? (
<ReactTooltip id={ `status-${id}` }>
{ title.map(x => (<div key={ x }>{ x }</div>)) }
</ReactTooltip>
) : null;
return (
<span className={ styles.status }>
<span className={ `${styles[type]} ${styles[status]}` }
data-tip={ title.length }
data-for={ `status-${id}` }
data-place={ tooltipPlacement }
data-effect='solid'
>
{ type === 'signal' && statuses.map(this.renderBar) }
</span>
{tooltip}
return (
<span
key={ signal }
className={ `${styles.bar} ${styles[signal]} ${isActive ? styles.active : ''}` }
/>
);
})
: null
}
</span>
);
}
renderBar = (signal) => {
const idx = statuses.indexOf(this.props.status);
const isActive = statuses.indexOf(signal) <= idx;
const activeClass = isActive ? styles.active : '';
return (
<span key={ signal } className={ `${styles.bar} ${styles[signal]} ${activeClass}` } />
);
}
{
message.find((x) => !x.isEmpty)
? (
<ReactTooltip id={ `status-${id}` }>
{
message.map((x) => (
<div key={ x }>
{ x }
</div>)
)
}
</ReactTooltip>
)
: null
}
</span>
);
}
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;

View File

@@ -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 <http://www.gnu.org/licenses/>.
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;
}
}