header responsive update, fix worker tcp read
parent
7e694fd9b7
commit
4817fef547
|
|
@ -1,5 +1,6 @@
|
||||||
import { MonitorState, MonitorTarget } from "@/uptime.types";
|
import { MonitorState, MonitorTarget } from "@/uptime.types";
|
||||||
import { Tooltip } from "@mantine/core";
|
import { Box, Tooltip } from "@mantine/core";
|
||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
|
||||||
|
|
||||||
export default function DetailBar({ monitor, state }: { monitor: MonitorTarget, state: MonitorState }) {
|
export default function DetailBar({ monitor, state }: { monitor: MonitorTarget, state: MonitorState }) {
|
||||||
|
|
@ -22,14 +23,24 @@ export default function DetailBar({ monitor, state }: { monitor: MonitorTarget,
|
||||||
|
|
||||||
uptimePercentBars.push(
|
uptimePercentBars.push(
|
||||||
<Tooltip key={i} label="Tooltip">
|
<Tooltip key={i} label="Tooltip">
|
||||||
<div style={{ height: '20px', width: '0.8%', background: 'green', borderRadius: '2px', marginLeft: '0.155%', marginRight: '0.155%' }}/>
|
<div style={{ height: '20px', width: '7px', background: 'green', borderRadius: '2px', marginLeft: '1px', marginRight: '1px' }}/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', flexWrap: 'nowrap', marginTop: '10px', marginBottom: '5px' }}>
|
<>
|
||||||
{uptimePercentBars}
|
<Box style={{ display: 'flex', flexWrap: 'nowrap', marginTop: '10px', marginBottom: '5px' }} visibleFrom='540'>
|
||||||
</div>
|
{uptimePercentBars}
|
||||||
|
</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> */}
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1,31 +1,23 @@
|
||||||
import { useState } from 'react';
|
|
||||||
import { Container, Group, Text } from '@mantine/core';
|
import { Container, Group, Text } from '@mantine/core';
|
||||||
import classes from '@/styles/Header.module.css';
|
import classes from '@/styles/Header.module.css';
|
||||||
|
import config from '@/uptime.config';
|
||||||
|
|
||||||
const links = [
|
|
||||||
{ link: '/about', label: 'Features' },
|
|
||||||
{ link: '/pricing', label: 'Pricing' },
|
|
||||||
{ link: '/learn', label: 'Learn' },
|
|
||||||
{ link: '/community', label: 'Community' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
const [active, setActive] = useState(links[0].link);
|
|
||||||
|
|
||||||
const items = links.map((link) => (
|
const linkToElement = (link: { label: string; link: string; highlight?: boolean; }) => {
|
||||||
<a
|
return (
|
||||||
key={link.label}
|
<a
|
||||||
href={link.link}
|
key={link.label}
|
||||||
className={classes.link}
|
href={link.link}
|
||||||
data-active={active === link.link || undefined}
|
target='_blank'
|
||||||
onClick={(event) => {
|
className={classes.link}
|
||||||
event.preventDefault();
|
data-active={link.highlight}
|
||||||
setActive(link.link);
|
>
|
||||||
}}
|
{link.label}
|
||||||
>
|
</a>
|
||||||
{link.label}
|
)
|
||||||
</a>
|
}
|
||||||
));
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className={classes.header}>
|
<header className={classes.header}>
|
||||||
|
|
@ -36,9 +28,15 @@ export default function Header() {
|
||||||
<Text size='xl' span fw={700} variant="gradient" gradient={{ from: 'blue', to: 'cyan', deg: 90 }}>UptimeFlare</Text>
|
<Text size='xl' span fw={700} variant="gradient" gradient={{ from: 'blue', to: 'cyan', deg: 90 }}>UptimeFlare</Text>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<Group gap={5}>
|
|
||||||
{items}
|
<Group gap={5} visibleFrom='sm'>
|
||||||
|
{config.page.links.map(linkToElement)}
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
<Group gap={5} hiddenFrom='sm'>
|
||||||
|
{config.page.links.filter(link => link.highlight).map(linkToElement)}
|
||||||
|
</Group>
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export default function MonitorDetail({ monitor, state }: { monitor: MonitorTarg
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
const statusIcon = state.incident[monitor.id].slice(-1)[0].end === undefined ? <IconAlertCircle style={{ width: '1em', height: '1em', color: '#b91c1c' }} /> : <IconCircleCheck style={{ width: '1em', height: '1em', color: '#059669' }} />
|
const statusIcon = state.incident[monitor.id].slice(-1)[0].end === undefined ? <IconAlertCircle style={{ width: '1.25em', height: '1.25em', color: '#b91c1c' }} /> : <IconCircleCheck style={{ width: '1.25em', height: '1.25em', color: '#059669' }} />
|
||||||
|
|
||||||
let totalTime = Date.now() / 1000 - state.incident[monitor.id][0].start[0]
|
let totalTime = Date.now() / 1000 - state.incident[monitor.id][0].start[0]
|
||||||
let downTime = 0
|
let downTime = 0
|
||||||
|
|
@ -42,7 +42,7 @@ export default function MonitorDetail({ monitor, state }: { monitor: MonitorTarg
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||||
<Text mt='sm' style={{ display: 'inline-flex', alignItems: 'center' }}>{statusIcon} {monitor.name}</Text>
|
<Text mt='sm' fw={700} style={{ display: 'inline-flex', alignItems: 'center' }}>{statusIcon} {monitor.name}</Text>
|
||||||
<Text mt='sm' fw={700} style={{ display: 'inline', color: getColor(uptimePercent, true) }}>Overall: {uptimePercent}%</Text>
|
<Text mt='sm' fw={700} style={{ display: 'inline', color: getColor(uptimePercent, true) }}>Overall: {uptimePercent}%</Text>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ export default function MonitorList({ config, state }: { config: any, state: Mon
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Center>
|
<Center>
|
||||||
<Card shadow="sm" padding="lg" radius="md" ml="xl" mr="xl" mt="xl" withBorder style={{ width: '800px' }}>
|
<Card shadow="sm" padding="lg" radius="md" ml="xl" mr="xl" mt="xl" withBorder style={{ width: '865px' }}>
|
||||||
{config.monitors.map((monitor: MonitorTarget) => (
|
{config.monitors.map((monitor: MonitorTarget) => (
|
||||||
<div key={monitor.id}>
|
<div key={monitor.id}>
|
||||||
<Card.Section ml="xs" mr="xs">
|
<Card.Section ml="xs" mr="xs">
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import config from '@/uptime.config'
|
||||||
import OverallStatus from '@/components/OverallStatus'
|
import OverallStatus from '@/components/OverallStatus'
|
||||||
import Header from '@/components/Header'
|
import Header from '@/components/Header'
|
||||||
import MonitorList from '@/components/MonitorList'
|
import MonitorList from '@/components/MonitorList'
|
||||||
import { Center, Text } from '@mantine/core'
|
import { Center, Divider, Text } from '@mantine/core'
|
||||||
|
|
||||||
export const runtime = 'experimental-edge'
|
export const runtime = 'experimental-edge'
|
||||||
const inter = Inter({ subsets: ['latin'] })
|
const inter = Inter({ subsets: ['latin'] })
|
||||||
|
|
@ -39,6 +39,14 @@ export default function Home({ state }: { state: MonitorState }) {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<Divider mt='lg' />
|
||||||
|
<Center>
|
||||||
|
<Text size='xs' mt='xs' mb='xs'>
|
||||||
|
Open-source monitoring and status page powered by <a href='https://github.com/lyc8503/UptimeFlare' target='_blank'>Uptimeflare</a> and <a href='https://www.cloudflare.com/' target='_blank'>Cloudflare</a>, made with ❤ by <a href='https://github.com/lyc8503' target='_blank'>lyc8503</a>.
|
||||||
|
</Text>
|
||||||
|
</Center>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,12 @@ const config = {
|
||||||
dateLocale: "zh-CN",
|
dateLocale: "zh-CN",
|
||||||
timezone: "Asia/Shanghai",
|
timezone: "Asia/Shanghai",
|
||||||
page: {
|
page: {
|
||||||
title: "lyc8503's Status Page"
|
title: "lyc8503's Status Page",
|
||||||
|
links: [
|
||||||
|
{ link: 'https://github.com/lyc8503', label: 'GitHub' },
|
||||||
|
{ link: 'https://blog.lyc8503.site/', label: 'Blog' },
|
||||||
|
{ link: 'mailto:me@lyc8503.site', label: 'Email Me', highlight: true }
|
||||||
|
]
|
||||||
},
|
},
|
||||||
callback: async (statusChangeMsg: string) => {
|
callback: async (statusChangeMsg: string) => {
|
||||||
await fetch('https://server.lyc8503.site/wepush?key=wepushkey&msg=' + statusChangeMsg)
|
await fetch('https://server.lyc8503.site/wepush?key=wepushkey&msg=' + statusChangeMsg)
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,11 @@ async function getStatus(monitor: MonitorTarget): Promise<{ ping: number; up: bo
|
||||||
|
|
||||||
// Write "PING\n"
|
// Write "PING\n"
|
||||||
const socket = connect({ hostname: hostname, port: Number(port) })
|
const socket = connect({ hostname: hostname, port: Number(port) })
|
||||||
const reader = socket.readable.getReader()
|
|
||||||
const writer = socket.writable.getWriter()
|
const writer = socket.writable.getWriter()
|
||||||
await writer.write(new TextEncoder().encode("PING\n"))
|
await writer.write(new TextEncoder().encode("PING\n"))
|
||||||
await reader.read() // This now works as a workaround for https://github.com/cloudflare/workerd/issues/1305
|
// Can't do this: await socket.close()
|
||||||
await socket.close()
|
|
||||||
|
|
||||||
// TODO: should throw an error here but it doesn't?
|
// https://github.com/cloudflare/workerd/issues/1305
|
||||||
await socket.closed
|
await socket.closed
|
||||||
|
|
||||||
console.log(`${monitor.name} connected to ${monitor.target}`)
|
console.log(`${monitor.name} connected to ${monitor.target}`)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue