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 }),
+ {}
+ )
+}