diff --git a/js/components/services/ServiceStatusRow.js b/js/components/services/ServiceStatusRow.js new file mode 100644 index 000000000..976cf7c86 --- /dev/null +++ b/js/components/services/ServiceStatusRow.js @@ -0,0 +1,58 @@ +import { TableCell, TableRow, makeStyles, styled } from "@material-ui/core"; +import React, { memo, useEffect, useRef, useState } from "react"; +import { StatusLight } from "./StatusLight"; + +const useStyles = makeStyles(theme => ({ + cell: { + color: theme.palette.primary.contrastText + } +})); + +export const ServiceStatusRow = memo(({ service }) => { + + const classes = useStyles(); + const interval = useRef(null); + const [uptime, setUptime] = useState(0); + + const StyledTableRow = styled(TableRow)(({ theme }) => ({ + // hide last border + '&:last-child td, &:last-child th': { + border: 0 + } + })); + + useEffect(() => { + if (service.timestamp) { + interval.current = setInterval(() => { + setUptime(Date.now() - service.timestamp); + }, 1000); + } + + return () => { + if (interval) { + clearInterval(interval.current); + } + } + }, [service, interval]); + + const getServiceDowntime = () => { + if (uptime) { + let minutes = Math.floor(uptime / (1000 * 60)); + let seconds = Math.floor(uptime / (1000) % 60); + if (minutes) { + return `${minutes} m ${seconds} s`; + } else { + return `${seconds} s`; + } + } else { + return ''; + } + } + + return + + {service.state} + {service.name} + {getServiceDowntime()} + ; +}); \ No newline at end of file diff --git a/js/components/services/ServicesStatus.js b/js/components/services/ServicesStatus.js index 5a47c4ab3..197ef3774 100644 --- a/js/components/services/ServicesStatus.js +++ b/js/components/services/ServicesStatus.js @@ -1,19 +1,11 @@ -import { Grid, Table, TableBody, TableCell, TableRow, Tooltip, makeStyles, styled } from "@material-ui/core"; +import { Grid, Table, TableBody, Tooltip, styled } from "@material-ui/core"; import React, { memo } from "react"; import { ServiceStatus } from "./ServiceStatus"; -import { StatusLight } from "./StatusLight"; import { tooltipClasses } from "@mui/material"; - -const useStyles = makeStyles(theme => ({ - cell: { - color: theme.palette.primary.contrastText - } -})); +import { ServiceStatusRow } from "./ServiceStatusRow"; export const ServicesStatus = memo(({ services }) => { - const classes = useStyles(); - const NoMaxWidthTooltip = styled(({ className, ...props }) => ( ))({ @@ -22,19 +14,8 @@ export const ServicesStatus = memo(({ services }) => { } }); - const StyledTableRow = styled(TableRow)(({ theme }) => ({ - // hide last border - '&:last-child td, &:last-child th': { - border: 0 - } - })); - return - {services.map((service) => - - {service.state} - {service.name} - )} + {services.map((service) => )} }> {services.map((service) => diff --git a/js/components/services/ServicesStatusWrapper.js b/js/components/services/ServicesStatusWrapper.js index ae5b627af..52fad2f6d 100644 --- a/js/components/services/ServicesStatusWrapper.js +++ b/js/components/services/ServicesStatusWrapper.js @@ -3,23 +3,39 @@ import React, { memo, useCallback, useContext, useEffect, useState } from "react import { ServicesStatus } from "./ServicesStatus"; import { getServicesStatus } from "./api/api"; import { ToastContext } from "../toast"; +import { SERVICE_STATUSES } from "./constants"; export const ServicesStatusWrapper = memo(() => { const [services, setServices] = useState([]); - const { toastError, toastInfo } = useContext(ToastContext); + const { toastError } = useContext(ToastContext); const checkServices = useCallback((previous, current) => { if (previous.length > 0) { - const changedServices = current.filter(newService => { + // update timestamps for services + current.forEach(newService => { const currentService = previous.find(previousService => previousService.id === newService.id); + // remember previous value + newService.timestamp = currentService.timestamp; if (currentService && currentService.state !== newService.state) { - return true; + if (![SERVICE_STATUSES.OK, SERVICE_STATUSES.DEGRADED].includes(newService.state)) { + newService.timestamp = Date.now(); + } else { + // clear timestamp + newService.timestamp = null; + } + } + }); + } else { + // initial set + current.forEach(service => { + if (![SERVICE_STATUSES.OK, SERVICE_STATUSES.DEGRADED].includes(service.state)) { + service.timestamp = Date.now(); + } else { + service.timestamp = null; } - return false; }); - changedServices.forEach(service => toastInfo(`Status of ${service.name} changed to ${service.state}`)); } - }, [toastInfo]); + }, []); const fetchServicesStatus = useCallback(async () => { const temp = await getServicesStatus(); @@ -29,7 +45,7 @@ export const ServicesStatusWrapper = memo(() => { if (!(prevState.length === 1 && prevState[0]?.id === 'services')) { toastError('Status of services is not available'); } - return [{ id: 'services', name: 'Status of services', state: 'NOT_AVAILABLE' }]; + return [{ id: 'services', name: 'Status of services', state: 'NOT_AVAILABLE', timestamp: Date.now() }]; }); } else { setServices((prevState) => { diff --git a/js/components/services/StatusLight.js b/js/components/services/StatusLight.js index c70a48507..3ba936b68 100644 --- a/js/components/services/StatusLight.js +++ b/js/components/services/StatusLight.js @@ -1,5 +1,6 @@ import { makeStyles } from "@material-ui/core"; import React, { memo } from "react"; +import { SERVICE_STATUSES, SERVICE_STATUS_COLORS } from "./constants"; const useStyles = makeStyles(theme => ({ circle: { @@ -8,17 +9,6 @@ const useStyles = makeStyles(theme => ({ } })); -export const SERVICE_STATUSES = { - OK: 'OK', - DEGRADED: 'DEGRADED' -} - -export const SERVICE_STATUS_COLORS = { - OK: 'green', - DEGRADED: 'orange', - OTHER: 'red' -} - export const StatusLight = memo(({ service }) => { const getColor = (status) => { switch (status) { diff --git a/js/components/services/constants.js b/js/components/services/constants.js new file mode 100644 index 000000000..17cbc8b80 --- /dev/null +++ b/js/components/services/constants.js @@ -0,0 +1,10 @@ +export const SERVICE_STATUSES = { + OK: 'OK', + DEGRADED: 'DEGRADED' +} + +export const SERVICE_STATUS_COLORS = { + OK: 'green', + DEGRADED: 'orange', + OTHER: 'red' +} \ No newline at end of file diff --git a/js/components/services/index.js b/js/components/services/index.js index 039373908..8c29f48d4 100644 --- a/js/components/services/index.js +++ b/js/components/services/index.js @@ -2,3 +2,4 @@ export * from './ServicesStatus'; export * from './ServicesStatusWrapper'; export * from './ServiceStatus'; export * from './api/api'; +export * from './constants';