almost done: more and more css
parent
4fba030932
commit
7b85b89325
|
|
@ -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 (
|
||||
<>
|
||||
<Text>{monitor.name}</Text>
|
||||
<Text>No data available, please make sure you have deployed your workers with latest config and check your worker status!</Text>
|
||||
</>
|
||||
)
|
||||
|
||||
const statusIcon = (state.incident[monitor.id].slice(-1)[0] ?? { end: 'dummy' }).end === undefined ? <IconAlertCircle style={{ width: '1em', height: '1em', color: '#b91c1c' }} /> : <IconCircleCheck style={{ width: '1em', height: '1em', color: '#059669' }} />
|
||||
|
||||
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 (
|
||||
<>
|
||||
<Text mt='sm' style={{ display: 'flex', alignItems: 'center' }}>{statusIcon} {monitor.name}</Text>
|
||||
<div style={{ height: '150px' }}>
|
||||
<Line options={options} data={data} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -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
|
|||
<Card shadow="sm" padding="lg" radius="md" ml="xl" mr="xl" mt="xl" withBorder style={{ width: '800px' }}>
|
||||
{config.monitors.map((monitor: MonitorTarget) => (
|
||||
<div key={monitor.id}>
|
||||
<Card.Section>
|
||||
<Text>{monitor.name}</Text>
|
||||
<Line options={options} data={data} />
|
||||
<Card.Section ml="xs" mr="xs">
|
||||
<MonitorDetail monitor={monitor} state={state} />
|
||||
</Card.Section>
|
||||
<Divider />
|
||||
</div>
|
||||
))}
|
||||
</Card>
|
||||
</Center>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 } }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
Loading…
Reference in New Issue