Merge branch 'master' of gitlab.com:elixire/elstat

This commit is contained in:
Luna Mendes 2018-07-14 22:28:43 -03:00
commit 8d8f38b5a1
8 changed files with 204 additions and 5335 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,19 @@
{ {
"name": "elstatus", "name": "elstatus",
"version": "0.1.0", "version": "0.0.0",
"description": "react web application to summon lucifer",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.0-14", "@fortawesome/fontawesome-svg-core": "^1.2.0-14",
"@fortawesome/free-solid-svg-icons": "^5.1.0-11", "@fortawesome/free-solid-svg-icons": "^5.1.0-11",
"@fortawesome/react-fontawesome": "0.1.0-11", "@fortawesome/react-fontawesome": "0.1.0-11",
"@nivo/line": "^0.42.1",
"i": "^0.3.6",
"ms": "^2.1.1", "ms": "^2.1.1",
"npm": "^6.1.0",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^16.4.0", "react": "^16.4.0",
"react-dom": "^16.4.0", "react-dom": "^16.4.0",
"react-placeholder": "^3.0.1", "react-placeholder": "^3.0.1",
"react-scripts": "1.1.4" "react-scripts": "1.1.4",
"recharts": "^1.0.1"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",

View File

@ -77,8 +77,9 @@ export default class App extends Component {
this.subscribeToChannels(); this.subscribeToChannels();
}; };
this.websocket.onclose = () => { this.websocket.onclose = ({ code, reason }) => {
log(`ws closed; attempting to reconnect in ${this.reconnectionTime}ms`); log(`ws closed with code ${code} (reason: ${reason || '<none>'}); `
+ `attempting to reconnect in ${this.reconnectionTime}ms`);
setTimeout(() => this.connect(), this.reconnectionTime); setTimeout(() => this.connect(), this.reconnectionTime);
this.reconnectionTime *= 2; this.reconnectionTime *= 2;
}; };
@ -91,12 +92,11 @@ export default class App extends Component {
this.handlePacket(parsed); this.handlePacket(parsed);
}; };
this.websocket.onerror = (error) => { this.websocket.onerror = (event) => {
log('ws error:', error); log('ws error:', event);
}; };
} }
_send(payload) { _send(payload) {
this.websocket.send(JSON.stringify(payload)); this.websocket.send(JSON.stringify(payload));
} }
@ -140,7 +140,7 @@ export default class App extends Component {
</div> </div>
) : null} ) : null}
{this.state.loading ? ( {this.state.loading && !this.state.error ? (
<React.Fragment> <React.Fragment>
<ServicePlaceholder /> <ServicePlaceholder />
<ServicePlaceholder /> <ServicePlaceholder />

View File

@ -1,4 +1,22 @@
.graph-container { .graph-container {
width: 100%; width: 100%;
height: 10rem; }
.recharts-cartesian-axis-tick-value {
font-size: 0.85em;
}
.recharts-tooltip-wrapper .recharts-default-tooltip {
padding: 0 0.5em !important;
border-radius: 0.2rem;
font-size: 0.85em;
opacity: 0.85;
}
.recharts-default-tooltip li {
color: inherit !important;
}
.recharts-tooltip-item-value {
font-family: PragmataPro, Menlo, "DejaVu Sans Mono", monospace;
} }

View File

@ -1,71 +1,98 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ms from 'ms'; import ms from 'ms';
import { ResponsiveLine } from '@nivo/line'; import {
ResponsiveContainer,
AreaChart,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Area,
ReferenceLine,
} from 'recharts';
import './Graph.css'; import './Graph.css';
export default class Graph extends Component { export default class Graph extends Component {
static propTypes = {
data: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)).isRequired,
}
state = {
screenWidth: window.innerWidth,
}
componentDidMount() {
window.addEventListener('resize', this.handleScreenChange);
}
componentWillUnmount() {
window.removeEventListener('resize', this.handleScreenChange);
}
handleScreenChange = () => {
this.setState({
screenWidth: window.innerWidth,
});
}
processData() { processData() {
const { data: unprocessedData } = this.props; const { data } = this.props;
const data = unprocessedData.map(([timestamp, latency]) => ({ return data.map(([timestamp, latency]) => ({
x: timestamp, timestamp,
y: latency, latency,
})).reverse(); })).sort(({ timestamp: a }, { timestamp: b }) => a - b);
return [
{
id: 'latency',
color: 'hsl(220, 100%, 75%)',
data,
},
];
} }
isSmallScreen() { isSmallScreen() {
return window.innerWidth < 500; return this.state.screenWidth < 500;
} }
render() { render() {
return ( return (
<div className="graph-container"> <div className="graph-container">
<ResponsiveLine <ResponsiveContainer width="100%" height={175}>
data={this.processData()} <AreaChart
margin={{ top: 30, left: 70, bottom: 50 }} data={this.processData()}
maxY="auto" >
curve="monotoneX" <XAxis
dataKey="timestamp"
tooltipFormat={(d) => `${d}ms`} tickFormatter={(tick) => ms(Date.now() - tick)}
tickLine={false}
axisLeft={{ />
format: (d) => `${d}ms`, {this.isSmallScreen()
tickCount: 3, ? null
legend: 'latency', : <YAxis
legendPosition: 'center', dataKey="latency"
legendOffset: -55, tickLine={false}
tickSize: 0, tickFormatter={(tick) => `${tick}ms`}
}} />
}
axisBottom={{ <CartesianGrid strokeDasharray="1 1" />
format: (epoch) => { <Tooltip
const interval = this.isSmallScreen() ? 7 : 5; isAnimationActive={false}
const minutesAgo = Math.floor((Date.now() - epoch) / (1000 * 60)); formatter={(value) => `${value}ms`}
if (minutesAgo % interval !== 0 || minutesAgo === 0) { label="DAB"
return undefined; separator=": "
} labelFormatter={() => null}
/>
return ms(Date.now() - epoch); <ReferenceLine
}, y={1000}
tickSize: 0, label="1s"
legend: 'time ago', stroke="pink"
legendPosition: 'center', />
legendOffset: 40, <Area
}} type="monotone"
dataKey="latency"
enableDots={false} stroke="hsla(200, 100%, 55%, 1)"
enableArea fill="hsl(200, 100%, 85%)"
/> isAnimationActive={false}
/>
</AreaChart>
</ResponsiveContainer>
</div> </div>
); );
} }

View File

@ -16,6 +16,12 @@
color: hsl(0, 0%, 45%); color: hsl(0, 0%, 45%);
} }
@media (max-width: 500px) {
.service .latency {
font-size: 1rem;
}
}
.service .emoji { .service .emoji {
font-size: 2em; font-size: 2em;
margin-right: 0.5em; margin-right: 0.5em;

View File

@ -18,7 +18,7 @@ const Service = ({ graph, name, status, latency, description }) => (
<h2 className="title"> <h2 className="title">
{name} {latency ? ( {name} {latency ? (
<span className="latency"> <span className="latency">
{latency}ms {Math.round(latency)}ms
</span> </span>
) : null} ) : null}
</h2> </h2>
@ -26,7 +26,7 @@ const Service = ({ graph, name, status, latency, description }) => (
<p className="description"> <p className="description">
{description} {description}
</p> </p>
{graph ? <Graph width={500} height={175} data={graph} /> : null} {graph ? <Graph data={graph} /> : null}
</div> </div>
); );

View File

@ -38,7 +38,7 @@ const ServicePlaceholder = () => (
<ReactPlaceholder <ReactPlaceholder
type="rect" type="rect"
ready={false} ready={false}
style={{ width: '100%', height: '6rem', marginTop: '1rem' }} style={{ width: '100%', height: '175px', marginTop: '1rem' }}
showLoadingAnimation showLoadingAnimation
> >
{' '} {' '}