bar percent finish & responsive ui
parent
9a390c31fe
commit
499bdf5a88
|
|
@ -1,5 +1,10 @@
|
|||
import { MonitorState, MonitorTarget } from '@/uptime.types'
|
||||
import { getColor } from '@/util/color'
|
||||
import { Box, Tooltip } from '@mantine/core'
|
||||
import { useResizeObserver } from '@mantine/hooks'
|
||||
import { useLayoutEffect, useRef, useState } from 'react'
|
||||
const moment = require('moment')
|
||||
require('moment-precise-range-plugin')
|
||||
|
||||
export default function DetailBar({
|
||||
monitor,
|
||||
|
|
@ -8,29 +13,59 @@ export default function DetailBar({
|
|||
monitor: MonitorTarget
|
||||
state: MonitorState
|
||||
}) {
|
||||
// const day = new Date()
|
||||
// day.setHours(0, 0, 0, 0)
|
||||
// const dayStart = day.getTime()
|
||||
const [barRef, barRect] = useResizeObserver()
|
||||
|
||||
const overlapLen = (x1: number, x2: number, y1: number, y2: number) => {
|
||||
return Math.max(0, Math.min(x2, y2) - Math.max(x1, y1) + 1)
|
||||
return Math.max(0, Math.min(x2, y2) - Math.max(x1, y1))
|
||||
}
|
||||
|
||||
const uptimePercentBars = []
|
||||
|
||||
for (let i = 89; i > 0; i--) {
|
||||
let dayDownTime = 0
|
||||
let dayTotalTime = 0
|
||||
const currentTime = Math.round(Date.now() / 1000)
|
||||
const montiorStartTime = state.incident[monitor.id][0].start[0]
|
||||
|
||||
// if (state.incident[monitor.id][0].end)
|
||||
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
|
||||
|
||||
for (let incident of state.incident[monitor.id]) {
|
||||
const incidentStart = incident.start[0]
|
||||
const incidentEnd = incident.end ?? currentTime
|
||||
|
||||
dayDownTime += overlapLen(dayStart, dayEnd, incidentStart, incidentEnd)
|
||||
}
|
||||
|
||||
const dayPercent = (((dayMonitorTime - dayDownTime) / dayMonitorTime) * 100).toPrecision(4)
|
||||
|
||||
uptimePercentBars.push(
|
||||
<Tooltip key={i} label="Tooltip">
|
||||
<Tooltip
|
||||
multiline
|
||||
key={i}
|
||||
label={
|
||||
Number.isNaN(Number(dayPercent)) ? (
|
||||
'No Data'
|
||||
) : (
|
||||
<>
|
||||
<div>{dayPercent + '%'}</div>
|
||||
{dayDownTime > 0 && (
|
||||
<div>{`Down for ${moment.preciseDiff(moment(0), moment(dayDownTime * 1000))}`}</div>
|
||||
)}
|
||||
{/* TODO: lantency detail for each bar */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: '20px',
|
||||
width: '7px',
|
||||
background: 'green',
|
||||
background: getColor(dayPercent, false),
|
||||
borderRadius: '2px',
|
||||
marginLeft: '1px',
|
||||
marginRight: '1px',
|
||||
|
|
@ -50,17 +85,10 @@ export default function DetailBar({
|
|||
marginBottom: '5px',
|
||||
}}
|
||||
visibleFrom="540"
|
||||
ref={barRef}
|
||||
>
|
||||
{uptimePercentBars}
|
||||
{uptimePercentBars.slice(Math.floor(Math.max(9 * 90 - barRect.width, 0) / 9), 90)}
|
||||
</Box>
|
||||
|
||||
{/* <Box style={{ display: 'flex', flexWrap: 'nowrap', marginTop: '10px', marginBottom: '5px' }} visibleFrom='270' hiddenFrom='540'>
|
||||
{uptimePercentBars.slice(-60)}
|
||||
</Box>
|
||||
|
||||
<Box style={{ display: 'flex', flexWrap: 'nowrap', marginTop: '10px', marginBottom: '5px' }} hiddenFrom='270'>
|
||||
{uptimePercentBars.slice(-30)}
|
||||
</Box> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,19 +3,7 @@ import { MonitorState, MonitorTarget } from '@/uptime.types'
|
|||
import { IconAlertCircle, IconCircleCheck } from '@tabler/icons-react'
|
||||
import DetailChart from './DetailChart'
|
||||
import DetailBar from './DetailBar'
|
||||
|
||||
function getColor(percent: number | string, darker: boolean): string {
|
||||
percent = Number(percent)
|
||||
if (percent >= 99.9) {
|
||||
return darker ? '#059669' : '#3bd671'
|
||||
} else if (percent >= 99) {
|
||||
return darker ? '#3bd671' : '#9deab8'
|
||||
} else if (percent >= 95) {
|
||||
return '#f29030'
|
||||
} else {
|
||||
return '#df484a'
|
||||
}
|
||||
}
|
||||
import { getColor } from '@/util/color'
|
||||
|
||||
export default function MonitorDetail({
|
||||
monitor,
|
||||
|
|
@ -50,8 +38,6 @@ export default function MonitorDetail({
|
|||
downTime += (incident.end ?? Date.now() / 1000) - incident.start[0]
|
||||
}
|
||||
|
||||
console.log(totalTime)
|
||||
console.log(downTime)
|
||||
const uptimePercent = (((totalTime - downTime) / totalTime) * 100).toPrecision(4)
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@
|
|||
"@mantine/ds": "^7.1.3",
|
||||
"@mantine/hooks": "^7.1.3",
|
||||
"@tabler/icons-react": "^2.39.0",
|
||||
"@types/moment-precise-range-plugin": "^0.2.2",
|
||||
"chart.js": "^4.4.0",
|
||||
"chartjs-adapter-moment": "^1.0.1",
|
||||
"moment": "^2.29.4",
|
||||
"moment-precise-range-plugin": "^1.3.0",
|
||||
"next": "13.5.4",
|
||||
"react": "^18",
|
||||
"react-chartjs-2": "^5.2.0",
|
||||
|
|
@ -972,6 +974,14 @@
|
|||
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/moment-precise-range-plugin": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://mirrors.cloud.tencent.com/npm/@types/moment-precise-range-plugin/-/moment-precise-range-plugin-0.2.2.tgz",
|
||||
"integrity": "sha512-Iof7Z9Ej/LbeE2++cap0SaSpDzMen9hT/ced3BwPhyUl5PWAgxR7sDxx4i0hYTOYshaMqH8hjXD0+CVBBYhEpw==",
|
||||
"dependencies": {
|
||||
"moment": ">=2.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.8.4",
|
||||
"resolved": "https://mirrors.cloud.tencent.com/npm/@types/node/-/node-20.8.4.tgz",
|
||||
|
|
@ -3500,6 +3510,14 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/moment-precise-range-plugin": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://mirrors.cloud.tencent.com/npm/moment-precise-range-plugin/-/moment-precise-range-plugin-1.3.0.tgz",
|
||||
"integrity": "sha1-YKwHX9/RRon20QKvdR0XGoC0q2A=",
|
||||
"peerDependencies": {
|
||||
"moment": ">=2.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.1.2.tgz",
|
||||
|
|
@ -5728,6 +5746,14 @@
|
|||
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/moment-precise-range-plugin": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://mirrors.cloud.tencent.com/npm/@types/moment-precise-range-plugin/-/moment-precise-range-plugin-0.2.2.tgz",
|
||||
"integrity": "sha512-Iof7Z9Ej/LbeE2++cap0SaSpDzMen9hT/ced3BwPhyUl5PWAgxR7sDxx4i0hYTOYshaMqH8hjXD0+CVBBYhEpw==",
|
||||
"requires": {
|
||||
"moment": ">=2.14.0"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "20.8.4",
|
||||
"resolved": "https://mirrors.cloud.tencent.com/npm/@types/node/-/node-20.8.4.tgz",
|
||||
|
|
@ -7609,6 +7635,12 @@
|
|||
"resolved": "https://mirrors.cloud.tencent.com/npm/moment/-/moment-2.29.4.tgz",
|
||||
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
|
||||
},
|
||||
"moment-precise-range-plugin": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://mirrors.cloud.tencent.com/npm/moment-precise-range-plugin/-/moment-precise-range-plugin-1.3.0.tgz",
|
||||
"integrity": "sha1-YKwHX9/RRon20QKvdR0XGoC0q2A=",
|
||||
"requires": {}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.1.2.tgz",
|
||||
|
|
|
|||
|
|
@ -14,9 +14,11 @@
|
|||
"@mantine/ds": "^7.1.3",
|
||||
"@mantine/hooks": "^7.1.3",
|
||||
"@tabler/icons-react": "^2.39.0",
|
||||
"@types/moment-precise-range-plugin": "^0.2.2",
|
||||
"chart.js": "^4.4.0",
|
||||
"chartjs-adapter-moment": "^1.0.1",
|
||||
"moment": "^2.29.4",
|
||||
"moment-precise-range-plugin": "^1.3.0",
|
||||
"next": "13.5.4",
|
||||
"react": "^18",
|
||||
"react-chartjs-2": "^5.2.0",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
function getColor(percent: number | string, darker: boolean): string {
|
||||
percent = Number(percent)
|
||||
if (percent >= 99.9) {
|
||||
return darker ? '#059669' : '#3bd671'
|
||||
} else if (percent >= 99) {
|
||||
return darker ? '#3bd671' : '#9deab8'
|
||||
} else if (percent >= 95) {
|
||||
return '#f29030'
|
||||
} else if (Number.isNaN(percent)) {
|
||||
return 'gray'
|
||||
} else {
|
||||
return '#df484a'
|
||||
}
|
||||
}
|
||||
|
||||
export { getColor }
|
||||
Loading…
Reference in New Issue