diff --git a/components/MonitorDetail.tsx b/components/MonitorDetail.tsx index e69de29..0b21c06 100644 --- a/components/MonitorDetail.tsx +++ b/components/MonitorDetail.tsx @@ -0,0 +1,93 @@ + +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 { MonitorState, MonitorTarget } from "@/uptime.types"; +import 'chartjs-adapter-moment' +import { IconAlertCircle, IconCircleCheck } from "@tabler/icons-react"; + +ChartJS.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend, + TimeScale +) + + +export default function MonitorDetail({ monitor, state }: { monitor: MonitorTarget, state: MonitorState }) { + + if (!state.latency[monitor.id]) return ( + <> + {monitor.name} + No data available, please make sure you have deployed your workers with latest config and check your worker status! + + ) + + const statusIcon = (state.incident[monitor.id].slice(-1)[0] ?? { end: 'dummy' }).end === undefined ? : + + 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 ( + <> + {statusIcon} {monitor.name} +
+ +
+ + ) +} \ No newline at end of file diff --git a/components/MonitorList.tsx b/components/MonitorList.tsx index e4c3edd..dd16a00 100644 --- a/components/MonitorList.tsx +++ b/components/MonitorList.tsx @@ -1,50 +1,6 @@ import { MonitorState, MonitorTarget } from "@/uptime.types"; -import { Card, Center, Divider, Text } from "@mantine/core"; -import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend } from 'chart.js'; -import { Line } from "react-chartjs-2"; - -ChartJS.register( - CategoryScale, - LinearScale, - PointElement, - LineElement, - Title, - Tooltip, - Legend -); - - -export const options = { - responsive: true, - interaction: { - mode: 'index' as const, - intersect: false, - }, - plugins: { - legend: { - position: 'top' as const, - }, - title: { - display: true, - text: 'Response times', - align: 'start' as const - }, - }, -}; - -const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; - -export const data = { - labels, - datasets: [ - { - data: labels.map(() => Math.round(Math.random() * 1000)), - borderColor: 'rgb(255, 99, 132)', - backgroundColor: 'rgba(255, 99, 132, 0.5)', - } - ], -}; - +import { Card, Center, Divider } from "@mantine/core"; +import MonitorDetail from "./MonitorDetail"; export default function MonitorList({ config, state }: { config: any, state: MonitorState }) { @@ -53,15 +9,14 @@ export default function MonitorList({ config, state }: { config: any, state: Mon {config.monitors.map((monitor: MonitorTarget) => (
- - {monitor.name} - + +
))}
- ); + ) } diff --git a/package-lock.json b/package-lock.json index db8556f..b523866 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,8 @@ "@mantine/hooks": "^7.1.3", "@tabler/icons-react": "^2.39.0", "chart.js": "^4.4.0", + "chartjs-adapter-moment": "^1.0.1", + "moment": "^2.29.4", "next": "13.5.4", "react": "^18", "react-chartjs-2": "^5.2.0", @@ -1552,6 +1554,15 @@ "pnpm": ">=7" } }, + "node_modules/chartjs-adapter-moment": { + "version": "1.0.1", + "resolved": "https://mirrors.cloud.tencent.com/npm/chartjs-adapter-moment/-/chartjs-adapter-moment-1.0.1.tgz", + "integrity": "sha512-Uz+nTX/GxocuqXpGylxK19YG4R3OSVf8326D+HwSTsNw1LgzyIGRo+Qujwro1wy6X+soNSnfj5t2vZ+r6EaDmA==", + "peerDependencies": { + "chart.js": ">=3.0.0", + "moment": "^2.10.2" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://mirrors.cloud.tencent.com/npm/chokidar/-/chokidar-3.5.3.tgz", @@ -3480,6 +3491,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://mirrors.cloud.tencent.com/npm/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.1.2.tgz", @@ -6112,6 +6131,12 @@ "@kurkle/color": "^0.3.0" } }, + "chartjs-adapter-moment": { + "version": "1.0.1", + "resolved": "https://mirrors.cloud.tencent.com/npm/chartjs-adapter-moment/-/chartjs-adapter-moment-1.0.1.tgz", + "integrity": "sha512-Uz+nTX/GxocuqXpGylxK19YG4R3OSVf8326D+HwSTsNw1LgzyIGRo+Qujwro1wy6X+soNSnfj5t2vZ+r6EaDmA==", + "requires": {} + }, "chokidar": { "version": "3.5.3", "resolved": "https://mirrors.cloud.tencent.com/npm/chokidar/-/chokidar-3.5.3.tgz", @@ -7563,6 +7588,11 @@ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true }, + "moment": { + "version": "2.29.4", + "resolved": "https://mirrors.cloud.tencent.com/npm/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + }, "ms": { "version": "2.1.2", "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.1.2.tgz", diff --git a/package.json b/package.json index e4b6969..e7b109e 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,8 @@ "@mantine/hooks": "^7.1.3", "@tabler/icons-react": "^2.39.0", "chart.js": "^4.4.0", + "chartjs-adapter-moment": "^1.0.1", + "moment": "^2.29.4", "next": "13.5.4", "react": "^18", "react-chartjs-2": "^5.2.0", diff --git a/pages/index.tsx b/pages/index.tsx index d6e3262..95afc44 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -35,6 +35,6 @@ export default function Home({ state }: { state: MonitorState }) { export async function getServerSideProps() { const { UPTIMEFLARE_STATE } = process.env as unknown as { UPTIMEFLARE_STATE: KVNamespace } const state = await UPTIMEFLARE_STATE.get('state', 'json') as unknown as MonitorState - + return { props: { state } } } diff --git a/uptime.config.ts b/uptime.config.ts index ad5f279..0ef7021 100644 --- a/uptime.config.ts +++ b/uptime.config.ts @@ -28,12 +28,33 @@ const config = { method: 'GET', target: 'https://cloudflare.com', expectedCode: [200], - timeout: 5, + timeout: 10000, headers: { "User-Agent": "Uptimeflare" }, body: undefined }, + { + id: 'blog', + name: 'My Blog', + method: 'GET', + target: 'https://blog.lyc8503.site', + timeout: 10000 + }, + { + id: 'pan', + name: 'My Fileshare', + method: 'GET', + target: 'https://pan.lyc8503.site', + timeout: 10000 + }, + { + id: 'server', + name: 'My Aliyun Server', + method: 'GET', + target: 'https://server.lyc8503.site', + timeout: 10000 + }, { id: 'broken-test', name: 'Ping 1.1.1.1',