diff --git a/components/MaintenanceAlert.tsx b/components/MaintenanceAlert.tsx index 40f9d20..e4c1882 100644 --- a/components/MaintenanceAlert.tsx +++ b/components/MaintenanceAlert.tsx @@ -5,15 +5,21 @@ import { MaintenanceConfig, MonitorTarget } from '@/types/config' export default function MaintenanceAlert({ maintenance, style, + upcoming = false, }: { maintenance: Omit & { monitors?: MonitorTarget[] } style?: React.CSSProperties + upcoming?: boolean }) { return ( } - title={maintenance.title || 'Scheduled Maintenance'} - color={maintenance.color || 'yellow'} + title={ + upcoming + ? `Upcoming Maintenance: ${maintenance.title || 'Scheduled Maintenance'}` + : maintenance.title || 'Scheduled Maintenance' + } + color={upcoming ? 'gray' : maintenance.color || '#f29030'} withCloseButton={false} style={{ position: 'relative', margin: '16px auto 0 auto', ...style }} > @@ -29,13 +35,27 @@ export default function MaintenanceAlert({ borderRadius: 6, }} > - From: {new Date(maintenance.start).toLocaleString()} -
- To:{' '} - {maintenance.end ? new Date(maintenance.end).toLocaleString() : 'Until further notice'} + {upcoming ? ( + <> + Scheduled for: {new Date(maintenance.start).toLocaleString()} +
+ Expected end:{' '} + {maintenance.end ? new Date(maintenance.end).toLocaleString() : 'Until further notice'} + + ) : ( + <> + From: {new Date(maintenance.start).toLocaleString()} +
+ To:{' '} + {maintenance.end ? new Date(maintenance.end).toLocaleString() : 'Until further notice'} + + )} - {maintenance.body} + {/* Maintenance description */} + {maintenance.body} + + {/* Affected components */} {maintenance.monitors && maintenance.monitors.length > 0 && ( <> diff --git a/components/OverallStatus.tsx b/components/OverallStatus.tsx index 3c42ed5..8abca70 100644 --- a/components/OverallStatus.tsx +++ b/components/OverallStatus.tsx @@ -1,6 +1,6 @@ import { MaintenanceConfig, MonitorTarget } from '@/types/config' -import { Center, Container, Title } from '@mantine/core' -import { IconCircleCheck, IconAlertCircle } from '@tabler/icons-react' +import { Center, Container, Title, Collapse, Button, Box } from '@mantine/core' +import { IconCircleCheck, IconAlertCircle, IconPlus, IconMinus } from '@tabler/icons-react' import { useEffect, useState } from 'react' import MaintenanceAlert from './MaintenanceAlert' import { pageConfig } from '@/uptime.config' @@ -58,15 +58,26 @@ export default function OverallStatus({ }) const now = new Date() - let filteredMaintenances: (Omit & { monitors?: MonitorTarget[] })[] = - maintenances - .filter((m) => now >= new Date(m.start) && (!m.end || now <= new Date(m.end))) - .map((maintenance) => ({ - ...maintenance, - monitors: maintenance.monitors?.map( - (monitorId) => monitors.find((mon) => monitorId === mon.id)! - ), - })) + const activeMaintenances = maintenances + .filter((m) => now >= new Date(m.start) && (!m.end || now <= new Date(m.end))) + .map((maintenance) => ({ + ...maintenance, + monitors: maintenance.monitors?.map( + (monitorId) => monitors.find((mon) => monitorId === mon.id)! + ), + })) + + const upcomingMaintenances = maintenances + .filter((m) => now < new Date(m.start)) + .map((maintenance) => ({ + ...maintenance, + monitors: maintenance.monitors?.map( + (monitorId) => monitors.find((mon) => monitorId === mon.id)! + ), + })) + + const [activeOpen, setActiveOpen] = useState(true) + const [upcomingOpen, setUpcomingOpen] = useState(false) return ( @@ -81,13 +92,52 @@ export default function OverallStatus({ } sec ago)`} - {filteredMaintenances.map((maintenance, idx) => ( - - ))} + {/* Active Maintenance */} + {activeMaintenances.length > 0 && ( + <> + + + Ongoing Maintenance + + + + + {activeMaintenances.map((maintenance, idx) => ( + + ))} + + + )} + + {/* Upcoming Maintenance */} + {upcomingMaintenances.length > 0 && ( + <> + + + Upcoming Maintenance + + + + + {upcomingMaintenances.map((maintenance, idx) => ( + + ))} + + + )} ) }