From e808e6be1ef517c470bdd5c2d417182ffa96b13b Mon Sep 17 00:00:00 2001 From: Ricki Moore Date: Fri, 14 Jul 2023 11:59:12 +0200 Subject: [PATCH] Feat: Alert Management (#186) --- src/components/AlertCard/AlertCard.tsx | 11 ++- .../AlertFilterSettings.tsx | 53 +++++++++++ src/components/DiagnosticTable/AlertInfo.tsx | 88 ++++++++++++++----- src/components/DropDown/DropDown.tsx | 6 +- .../NetworkPeerSpeedometer.tsx | 27 ++++++ src/components/TopBar/BeaconMetric.tsx | 22 ++++- src/components/TopBar/ValidatorMetric.tsx | 18 ++++ src/constants/constants.ts | 8 ++ .../__tests__/useDeviceDiagnostics.spec.ts | 12 ++- .../__tests__/useDiagnosticAlerts.spec.ts | 68 -------------- src/hooks/__tests__/useValidatorCount.spec.ts | 4 +- src/hooks/useAtomCleanup.ts | 3 + src/hooks/useDeviceDiagnostics.ts | 21 ++++- src/hooks/useDiagnosticAlerts.ts | 88 +++++++++++-------- src/hooks/useDivDimensions.ts | 34 +++++++ src/hooks/useTrackLogs.ts | 55 +++++++++++- src/hooks/useValidatorCount.ts | 4 +- src/locales/translations/en-US.json | 11 +++ src/recoil/atoms.ts | 7 +- src/types/index.ts | 8 ++ src/utilities/sortAlerts.ts | 18 ++++ 21 files changed, 419 insertions(+), 147 deletions(-) create mode 100644 src/components/AlertFilterSettings/AlertFilterSettings.tsx delete mode 100644 src/hooks/__tests__/useDiagnosticAlerts.spec.ts create mode 100644 src/hooks/useDivDimensions.ts create mode 100644 src/utilities/sortAlerts.ts diff --git a/src/components/AlertCard/AlertCard.tsx b/src/components/AlertCard/AlertCard.tsx index c81b3bfa..bbcd9c43 100644 --- a/src/components/AlertCard/AlertCard.tsx +++ b/src/components/AlertCard/AlertCard.tsx @@ -1,14 +1,16 @@ import StatusBar, { StatusBarProps } from '../StatusBar/StatusBar' import Typography from '../Typography/Typography' import { FC } from 'react' + export interface AlertCardProps extends StatusBarProps { text: string subText: string + onClick?: () => void } -const AlertCard: FC = ({ text, subText, ...props }) => { +const AlertCard: FC = ({ text, subText, onClick, ...props }) => { return ( -
+
{text} @@ -16,7 +18,10 @@ const AlertCard: FC = ({ text, subText, ...props }) => { {subText}
- +
) } diff --git a/src/components/AlertFilterSettings/AlertFilterSettings.tsx b/src/components/AlertFilterSettings/AlertFilterSettings.tsx new file mode 100644 index 00000000..d137cfb0 --- /dev/null +++ b/src/components/AlertFilterSettings/AlertFilterSettings.tsx @@ -0,0 +1,53 @@ +import DropDown from '../DropDown/DropDown' +import { FC, useState } from 'react' +import useClickOutside from '../../hooks/useClickOutside' +import { StatusColor } from '../../types' +import { useTranslation } from 'react-i18next' + +export type FilterValue = StatusColor | 'all' + +export interface AlertFilterSettingsProps { + onChange: (value: FilterValue) => void + value: FilterValue +} + +const AlertFilterSettings: FC = ({ onChange, value }) => { + const { t } = useTranslation() + const [isOpen, toggle] = useState(false) + + const openDrop = () => toggle(true) + const closeDrop = () => toggle(false) + + const { ref } = useClickOutside(closeDrop) + + const selectOption = (value: FilterValue) => { + onChange(value) + closeDrop() + } + const filterOptions = [ + { text: t('alertMessages.all'), value: 'all' }, + { text: t('alertMessages.severe'), value: StatusColor.ERROR }, + { text: t('alertMessages.warning'), value: StatusColor.WARNING }, + { text: t('alertMessages.fair'), value: StatusColor.SUCCESS }, + ] + + return ( +
+ + + {filterOptions.map((option, index) => ( +
  • selectOption(option.value as FilterValue)} + > + {option.text} + {option.value === value && } +
  • + ))} +
    +
    + ) +} + +export default AlertFilterSettings diff --git a/src/components/DiagnosticTable/AlertInfo.tsx b/src/components/DiagnosticTable/AlertInfo.tsx index 5fa975c1..fb07b51b 100644 --- a/src/components/DiagnosticTable/AlertInfo.tsx +++ b/src/components/DiagnosticTable/AlertInfo.tsx @@ -2,39 +2,79 @@ import Typography from '../Typography/Typography' import AlertCard from '../AlertCard/AlertCard' import { useTranslation } from 'react-i18next' import useDiagnosticAlerts from '../../hooks/useDiagnosticAlerts' +import useDivDimensions from '../../hooks/useDivDimensions' +import { useEffect, useMemo, useState } from 'react' +import sortAlertMessagesBySeverity from '../../utilities/sortAlerts' +import { StatusColor } from '../../types' +import AlertFilterSettings, { FilterValue } from '../AlertFilterSettings/AlertFilterSettings' const AlertInfo = () => { const { t } = useTranslation() - const { natAlert, peerCountAlert } = useDiagnosticAlerts() + const { alerts, dismissAlert, resetDismissed } = useDiagnosticAlerts() + const { ref, dimensions } = useDivDimensions() + const [filter, setFilter] = useState('all') + + const setFilterValue = (value: FilterValue) => setFilter(value) + + const formattedAlerts = useMemo(() => { + let baseAlerts = alerts + + if (filter !== 'all') { + baseAlerts = baseAlerts.filter(({ severity }) => severity === filter) + } + + return sortAlertMessagesBySeverity(baseAlerts) + }, [alerts, filter]) + + const isFiller = formattedAlerts.length < 6 + + useEffect(() => { + const intervalId = setInterval(() => { + resetDismissed() + }, 60000) + + return () => clearInterval(intervalId) + }, []) + return ( -
    -
    +
    +
    {t('alertInfo.alerts')} - - {t('viewAll')} - +
    - {natAlert && ( - + {dimensions && ( +
    + {formattedAlerts.length > 0 && ( +
    + {formattedAlerts.map((alert) => { + const { severity, subText, message, id } = alert + const count = + severity === StatusColor.SUCCESS ? 1 : severity === StatusColor.WARNING ? 2 : 3 + return ( + dismissAlert(alert)} + subText={subText} + text={message} + /> + ) + })} +
    + )} + {isFiller && ( +
    + +
    + )} +
    )} - {peerCountAlert && ( - - )} -
    - -
    ) } diff --git a/src/components/DropDown/DropDown.tsx b/src/components/DropDown/DropDown.tsx index 41edbd3c..8e50080a 100644 --- a/src/components/DropDown/DropDown.tsx +++ b/src/components/DropDown/DropDown.tsx @@ -15,8 +15,6 @@ const DropDown: FC = ({ className = '', position = 'top-full left-0 z-50', }) => { - const isChildrenArray = Array.isArray(children) - return (