import React, { Component } from 'react' import './App.css' import Service from './Service.js' import ServicePlaceholder from './ServicePlaceholder.js' import DegradedNotice from './DegradedNotice.js' import StreamingClient from '../ws/client' import Status from './Status' import { log, objectFromEntries, strictFetch } from '../util.js' import { domain as DOMAIN } from '../config.json' export default class App extends Component { client = null state = { loading: true, error: null, metrics: null, incident: null, } async componentDidMount () { await this.loadMetrics() await this.loadIncident() this.setState({ loading: false }) if (this.state.error) { return } const endpoint = `${DOMAIN}/api/streaming` .replace('https', 'wss') .replace('http', 'ws') this.client = new StreamingClient(endpoint, this.state.metrics) this.client.connect() this.client.on('status', this.handleStatus.bind(this)) this.client.on('latency', this.handleLatency.bind(this)) this.client.on('incident_new', (incident) => { this.setState({ incident }) }) this.client.on('incident_update', (incident) => { this.setState({ incident }) }) this.client.on('incident_close', () => { this.setState({ incident: null }) }) } handleStatus (name, [, status]) { const { status: statuses } = this.state.metrics log('updating status on:', name) if (!(name in statuses)) { log(`failed to locate channel ${name} to update statuses`) return } if (statuses[name].status === status) { log(`ignoring stale status (${status}) for ${name}`) return } this.setState(({ metrics: old }, _props) => { const metrics = { ...old } metrics.status[name].status = status return { metrics } }) } handleLatency (name, data) { const { metrics } = this.state log('adding latency entry:', data) // latency entries come in newest to oldest, so remove the oldest entry const graph = metrics.graph[name].slice(0, metrics.graph[name].length - 1) // make new data come in first const newGraph = [data, ...graph] this.setState(({ metrics: old }, _props) => { const metrics = { ...old } metrics.graph[name] = newGraph const [, latency] = data metrics.status[name].latency = latency return { metrics } }) } async loadMetrics () { log('loading metrics') try { var resp = await strictFetch(`${DOMAIN}/api/status`) } catch (error) { this.setState({ error }) } this.setState({ metrics: await resp.json() }) } async loadIncident () { log('loading current incident') try { var resp = await strictFetch(`${DOMAIN}/api/incidents/current`) } catch (error) { this.setState({ error }) } this.setState({ incident: await resp.json() }) } render () { let metrics = null if (this.state.metrics) { const allServices = Object.entries(this.state.metrics.status) const graphs = this.state.metrics.graph const services = allServices.map(([name, info]) => ( )) const down = allServices.filter(([, { status }]) => !status) let notice = if (!this.state.incident && down.length > 0) { notice = down.length > 0 ? : null } metrics = (
{notice} {services}
) } return (

elstatus

{this.state.error ? (
Error: {this.state.error}
) : null} {this.state.loading && !this.state.error ? ( ) : metrics}
) } }