import { MonitorState, MonitorTarget } from '@/uptime.types' import { getColor } from '@/util/color' import { Box, Tooltip, Modal } from '@mantine/core' import { useResizeObserver } from '@mantine/hooks' import { useState } from 'react' const moment = require('moment') require('moment-precise-range-plugin') export default function DetailBar({ monitor, state, }: { monitor: MonitorTarget state: MonitorState }) { const [barRef, barRect] = useResizeObserver() const [modalOpened, setModalOpened] = useState(false) const [modalTitle, setModalTitle] = useState('') const [modelContent, setModelContent] = useState(
) const overlapLen = (x1: number, x2: number, y1: number, y2: number) => { return Math.max(0, Math.min(x2, y2) - Math.max(x1, y1)) } const uptimePercentBars = [] const currentTime = Math.round(Date.now() / 1000) const montiorStartTime = state.incident[monitor.id][0].start[0] const todayStart = new Date() todayStart.setHours(0, 0, 0, 0) for (let i = 89; i >= 0; i--) { const dayStart = Math.round(todayStart.getTime() / 1000) - i * 86400 const dayEnd = dayStart + 86400 const dayMonitorTime = overlapLen(dayStart, dayEnd, montiorStartTime, currentTime) let dayDownTime = 0 let incidentReasons: string[] = [] for (let incident of state.incident[monitor.id]) { const incidentStart = incident.start[0] const incidentEnd = incident.end ?? currentTime const overlap = overlapLen(dayStart, dayEnd, incidentStart, incidentEnd) dayDownTime += overlap // Incident history for the day if (overlap > 0) { for (let i = 0; i < incident.error.length; i++) { let partStart = incident.start[i] let partEnd = i === incident.error.length - 1 ? incident.end ?? currentTime : incident.start[i + 1] partStart = Math.max(partStart, dayStart) partEnd = Math.min(partEnd, dayEnd) if (overlapLen(dayStart, dayEnd, partStart, partEnd) > 0) { const startStr = new Date(partStart * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', }) const endStr = new Date(partEnd * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', }) incidentReasons.push(`[${startStr}-${endStr}] ${incident.error[i]}`) } } } } const dayPercent = (((dayMonitorTime - dayDownTime) / dayMonitorTime) * 100).toPrecision(4) uptimePercentBars.push(
{dayPercent + '% at ' + new Date(dayStart * 1000).toLocaleDateString()}
{dayDownTime > 0 && (
{`Down for ${moment.preciseDiff( moment(0), moment(dayDownTime * 1000) )} (click for detail)`}
)} ) } >
{ if (dayDownTime > 0) { setModalTitle( `🚨 ${monitor.name} incidents at ${new Date(dayStart * 1000).toLocaleDateString()}` ) setModelContent( <> {incidentReasons.map((reason, index) => (
{reason}
))} ) setModalOpened(true) } }} /> ) } return ( <> setModalOpened(false)} title={modalTitle} size={'40em'} > {modelContent} {uptimePercentBars.slice(Math.floor(Math.max(9 * 90 - barRect.width, 0) / 9), 90)} ) }