diff --git a/priv/frontend/src/components/App.js b/priv/frontend/src/components/App.js index 7428b9a..6f5dffa 100644 --- a/priv/frontend/src/components/App.js +++ b/priv/frontend/src/components/App.js @@ -3,8 +3,9 @@ import React, { Component } from 'react' import './App.css' import Service from './Service.js' import ServicePlaceholder from './ServicePlaceholder.js' +import DegradedNotice from './DegradedNotice.js' import OP from '../ws/op.js' -import { log } from '../util.js' +import { log, objectFromEntries } from '../util.js' import { domain as DOMAIN } from '../config.json' export default class App extends Component { @@ -153,20 +154,31 @@ export default class App extends Component { } render () { - const metrics = !this.state.metrics ? null : ( -
- {Object.entries(this.state.metrics.status) - .map(([name, info]) => ( - - )) - } -
- ) + 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]) => ( + + )) + + let notice = null + const down = allServices.filter(([, { status }]) => !status) + + if (down.length !== 0) { + // a service is down :( + notice = + } + + metrics = ( +
+ {notice} + {services} +
+ ) + } return (
diff --git a/priv/frontend/src/components/DegradedNotice.css b/priv/frontend/src/components/DegradedNotice.css new file mode 100644 index 0000000..b9268cd --- /dev/null +++ b/priv/frontend/src/components/DegradedNotice.css @@ -0,0 +1,17 @@ +.degraded-notice { + border-radius: 0.25rem; + padding: 1rem; + margin: 1rem 0; + border: solid 1px hsla(0, 100%, 80%, 1); + background: hsla(0, 100%, 90%, 1); +} + +.degraded-notice header { + font-size: 1.35rem; + font-weight: 700; + margin-bottom: 0.5em; +} + +.degraded-notice p { + margin-bottom: 0; +} diff --git a/priv/frontend/src/components/DegradedNotice.js b/priv/frontend/src/components/DegradedNotice.js new file mode 100644 index 0000000..d83777c --- /dev/null +++ b/priv/frontend/src/components/DegradedNotice.js @@ -0,0 +1,25 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import './DegradedNotice.css' + +const DegradedNotice = ({ services }) => { + const keys = Object.keys(services) + const serviceNames = keys.join(', ') + const plural = keys.length === 1 ? '' : 's' + + return ( +
+
{keys.length} service{plural} are unreachable
+

+ elstat is having trouble contacting {serviceNames}. +

+
+ ) +} + +DegradedNotice.propTypes = { + services: PropTypes.object.isRequired, +} + +export default DegradedNotice diff --git a/priv/frontend/src/util.js b/priv/frontend/src/util.js index 213298a..fc9bec2 100644 --- a/priv/frontend/src/util.js +++ b/priv/frontend/src/util.js @@ -6,3 +6,10 @@ export function log (...args) { ...args, ) } + +export function objectFromEntries (entries) { + return entries.reduce( + (object, [key, value]) => ({ ...object, [key]: value }), + {} + ) +}