From 59c9ebf82b98b2b7ae429f878218343571ba2628 Mon Sep 17 00:00:00 2001 From: lyc8503 Date: Sun, 22 Oct 2023 19:13:49 +0800 Subject: [PATCH] chart move to component & uptime bar --- components/DetailChart.tsx | 79 +++++++++++++++++++++++ components/MonitorDetail.tsx | 121 ++++++++++++++--------------------- 2 files changed, 127 insertions(+), 73 deletions(-) create mode 100644 components/DetailChart.tsx diff --git a/components/DetailChart.tsx b/components/DetailChart.tsx new file mode 100644 index 0000000..8b712cb --- /dev/null +++ b/components/DetailChart.tsx @@ -0,0 +1,79 @@ +import { Line } from "react-chartjs-2" +import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip as ChartTooltip, Legend, TimeScale } from 'chart.js' +import 'chartjs-adapter-moment' +import { MonitorState, MonitorTarget } from "@/uptime.types" + +ChartJS.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + ChartTooltip, + Legend, + TimeScale +) + + +export default function DetailChart({ monitor, state }: { monitor: MonitorTarget, state: MonitorState }) { + + const latencyData = state.latency[monitor.id].recent.map((point) => ({ x: point.time * 1000, y: point.ping, loc: point.loc })) + + let data = { + datasets: [ + { + data: latencyData, + borderColor: 'rgb(112, 119, 140)', + borderWidth: 2, + radius: 0, + cubicInterpolationMode: 'monotone' as const, + tension: 0.4 + } + ] + } + + let options = { + responsive: true, + maintainAspectRatio: false, + interaction: { + mode: 'index' as const, + intersect: false, + }, + plugins: { + tooltip: { + callbacks: { + label: (item: any) => { + if (item.parsed.y) { + return `${item.parsed.y}ms (${item.raw.loc})` + } + } + } + }, + legend: { + display: false + }, + title: { + display: true, + text: 'Response times(ms)', + align: 'start' as const + }, + }, + scales: { + x: { + type: 'time' as const, + ticks: { + source: 'auto' as const, + maxRotation: 0, + autoSkip: true + } + } + } + } + + return ( +
+ +
+ ) +} + diff --git a/components/MonitorDetail.tsx b/components/MonitorDetail.tsx index 4ce876a..1a63792 100644 --- a/components/MonitorDetail.tsx +++ b/components/MonitorDetail.tsx @@ -1,21 +1,21 @@ -import { Line } from "react-chartjs-2" -import { Text } from "@mantine/core" -import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend, TimeScale } from 'chart.js' +import { Text, Tooltip } from "@mantine/core" import { MonitorState, MonitorTarget } from "@/uptime.types"; -import 'chartjs-adapter-moment' import { IconAlertCircle, IconCircleCheck } from "@tabler/icons-react"; +import DetailChart from "./DetailChart"; -ChartJS.register( - CategoryScale, - LinearScale, - PointElement, - LineElement, - Title, - Tooltip, - Legend, - TimeScale -) +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' + } +} export default function MonitorDetail({ monitor, state }: { monitor: MonitorTarget, state: MonitorState }) { @@ -27,75 +27,50 @@ export default function MonitorDetail({ monitor, state }: { monitor: MonitorTarg ) - const statusIcon = (state.incident[monitor.id].slice(-1)[0] ?? { end: 'dummy' }).end === undefined ? : + const statusIcon = state.incident[monitor.id].slice(-1)[0].end === undefined ? : - const latencyData = state.latency[monitor.id].recent.map((point) => ({ x: point.time * 1000, y: point.ping, loc: point.loc })) + let totalTime = Date.now() / 1000 - state.incident[monitor.id][0].start[0] + let downTime = 0 + for (let incident of state.incident[monitor.id]) { + downTime += (incident.end ?? (Date.now() / 1000)) - incident.start[0] + } - let data = { - datasets: [ - { - data: latencyData, - borderColor: 'rgb(112, 119, 140)', - borderWidth: 2, - radius: 0, - cubicInterpolationMode: 'monotone' as const, - tension: 0.4 - } - ] - } - - let options = { - responsive: true, - maintainAspectRatio: false, - interaction: { - mode: 'index' as const, - intersect: false, - }, - plugins: { - tooltip: { - callbacks: { - label: (item: any) => { - if (item.parsed.y) { - return `${item.parsed.y}ms (${item.raw.loc})` - } - } - } - }, - legend: { - display: false - }, - title: { - display: true, - text: 'Response times(ms)', - align: 'start' as const - }, - }, - scales: { - x: { - type: 'time' as const, - ticks: { - source: 'auto' as const, - maxRotation: 0, - autoSkip: true - } - } - } - } + console.log(totalTime) + console.log(downTime) + const uptimePercent = ((totalTime - downTime) / totalTime * 100).toPrecision(4) const uptimePercentBars = [] + + // const day = new Date() + // day.setHours(0, 0, 0, 0) + // const dayStart = day.getTime() + for (let i = 0; i < 90; i++) { - uptimePercentBars.push(
) + + let dayDownTime = 0 + let dayTotalTime = 0 + + if (state.incident[monitor.id][0].end) + + uptimePercentBars.push( + +
+ + ) } return ( <> - {statusIcon} {monitor.name} - {/*
- {uptimePercentBars} -
*/} -
- +
+ {statusIcon} {monitor.name} + Overall: {uptimePercent}%
+ +
+ {uptimePercentBars} +
+ + ) } \ No newline at end of file