feat: add maintenance alert
parent
5551bb554a
commit
be3aa8beda
|
|
@ -1,30 +1,33 @@
|
||||||
import { Center, Title } from '@mantine/core'
|
import { Maintenances } from '@/types/config'
|
||||||
import { IconCircleCheck, IconAlertCircle } from '@tabler/icons-react'
|
import { Alert, Card, Center, Container, List, ListItem, Text, Title } from '@mantine/core'
|
||||||
import { useEffect, useState } from 'react';
|
import { IconCircleCheck, IconAlertCircle, IconInfoCircle } from '@tabler/icons-react'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
function useWindowVisibility() {
|
function useWindowVisibility() {
|
||||||
const [isVisible, setIsVisible] = useState(true);
|
const [isVisible, setIsVisible] = useState(true)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleVisibilityChange = () => {
|
const handleVisibilityChange = () => {
|
||||||
console.log('visibility change', document.visibilityState);
|
console.log('visibility change', document.visibilityState)
|
||||||
setIsVisible(document.visibilityState === 'visible');
|
setIsVisible(document.visibilityState === 'visible')
|
||||||
};
|
}
|
||||||
|
|
||||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
document.addEventListener('visibilitychange', handleVisibilityChange)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
document.removeEventListener('visibilitychange', handleVisibilityChange)
|
||||||
};
|
}
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
return isVisible;
|
return isVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function OverallStatus({
|
export default function OverallStatus({
|
||||||
state,
|
state,
|
||||||
|
maintenances,
|
||||||
}: {
|
}: {
|
||||||
state: { overallUp: number; overallDown: number; lastUpdate: number }
|
state: { overallUp: number; overallDown: number; lastUpdate: number }
|
||||||
|
maintenances?: Maintenances[]
|
||||||
}) {
|
}) {
|
||||||
let statusString = ''
|
let statusString = ''
|
||||||
let icon = <IconAlertCircle style={{ width: 64, height: 64, color: '#b91c1c' }} />
|
let icon = <IconAlertCircle style={{ width: 64, height: 64, color: '#b91c1c' }} />
|
||||||
|
|
@ -36,12 +39,14 @@ export default function OverallStatus({
|
||||||
statusString = 'All systems operational'
|
statusString = 'All systems operational'
|
||||||
icon = <IconCircleCheck style={{ width: 64, height: 64, color: '#059669' }} />
|
icon = <IconCircleCheck style={{ width: 64, height: 64, color: '#059669' }} />
|
||||||
} else {
|
} else {
|
||||||
statusString = `Some systems not operational (${state.overallDown} out of ${state.overallUp + state.overallDown})`
|
statusString = `Some systems not operational (${state.overallDown} out of ${
|
||||||
|
state.overallUp + state.overallDown
|
||||||
|
})`
|
||||||
}
|
}
|
||||||
|
|
||||||
const [openTime] = useState(Math.round(Date.now() / 1000))
|
const [openTime] = useState(Math.round(Date.now() / 1000))
|
||||||
const [currentTime, setCurrentTime] = useState(Math.round(Date.now() / 1000))
|
const [currentTime, setCurrentTime] = useState(Math.round(Date.now() / 1000))
|
||||||
const isWindowVisible = useWindowVisibility();
|
const isWindowVisible = useWindowVisibility()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
|
|
@ -58,16 +63,61 @@ export default function OverallStatus({
|
||||||
return () => clearInterval(interval)
|
return () => clearInterval(interval)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// @TODO make dynamic
|
||||||
|
const showMaintenance = maintenances
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Center>{icon}</Center>
|
<Container size="md" mt="xl" style={{ width: '897px' }}>
|
||||||
<Title mt="sm" style={{ textAlign: 'center' }} order={1}>
|
<Center>{icon}</Center>
|
||||||
{statusString}
|
<Title mt="sm" style={{ textAlign: 'center' }} order={1}>
|
||||||
</Title>
|
{statusString}
|
||||||
<Title mt="sm" style={{ textAlign: 'center', color: '#70778c' }} order={5}>
|
</Title>
|
||||||
Last updated on:{' '}
|
<Title mt="sm" style={{ textAlign: 'center', color: '#70778c' }} order={5}>
|
||||||
{`${new Date(state.lastUpdate * 1000).toLocaleString()} (${currentTime - state.lastUpdate} sec ago)`}
|
Last updated on:{' '}
|
||||||
</Title>
|
{`${new Date(state.lastUpdate * 1000).toLocaleString()} (${
|
||||||
|
currentTime - state.lastUpdate
|
||||||
|
} sec ago)`}
|
||||||
|
</Title>
|
||||||
|
{showMaintenance &&
|
||||||
|
maintenances.map((maintenance, idx) => (
|
||||||
|
<Alert
|
||||||
|
key={idx}
|
||||||
|
icon={<IconInfoCircle />}
|
||||||
|
title={maintenance.title}
|
||||||
|
color={maintenance.color || 'primary'}
|
||||||
|
mt="md"
|
||||||
|
withCloseButton={false}
|
||||||
|
>
|
||||||
|
<Text>
|
||||||
|
{maintenance.start && (
|
||||||
|
<>
|
||||||
|
<b>From:</b> {maintenance.start.toLocaleString()}
|
||||||
|
<br />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{maintenance.end && (
|
||||||
|
<>
|
||||||
|
<b>To:</b> {maintenance.end.toLocaleString()}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
{maintenance.body && <Text mt="xs">{maintenance.body}</Text>}
|
||||||
|
{maintenance.monitors && maintenance.monitors.length > 0 && (
|
||||||
|
<>
|
||||||
|
<Text mt="xs">
|
||||||
|
<b>Affected components:</b>
|
||||||
|
</Text>
|
||||||
|
<List size="sm" withPadding>
|
||||||
|
{maintenance.monitors.map((comp, compIdx) => (
|
||||||
|
<List.Item key={compIdx}>{comp}</List.Item>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Alert>
|
||||||
|
))}
|
||||||
|
</Container>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue