feat: grouping

pull/97/head
lyc8503 2025-03-26 00:33:24 +08:00
parent 074fabfe05
commit 8c818017c1
3 changed files with 90 additions and 12 deletions

View File

@ -52,7 +52,7 @@ Please refer to [Wiki](https://github.com/lyc8503/UptimeFlare/wiki)
- [x] ~~Self-host Dockerfile~~
- [x] Incident history
- [ ] Improve `checkLocationWorkerRoute` and fix possible `proxy failed`
- [ ] Groups
- [x] Groups
- [x] Remove old incidents
- [ ] Known issue: `fetch` doesn't support non-standard port
- [ ] Update wiki and add docs for dev

View File

@ -1,8 +1,85 @@
import { MonitorState, MonitorTarget } from '@/uptime.types'
import { Card, Center } from '@mantine/core'
import { Accordion, Card, Center, Text } from '@mantine/core'
import MonitorDetail from './MonitorDetail'
import { pageConfig } from '@/uptime.config';
function countDownCount(state: MonitorState, ids: string[]) {
let downCount = 0
for (let id of ids) {
if (state.incident[id] === undefined || state.incident[id].length === 0) {
continue
}
if (state.incident[id].slice(-1)[0].end === undefined) {
downCount++
}
}
return downCount
}
function getStatusTextColor(state: MonitorState, ids: string[]) {
let downCount = countDownCount(state, ids)
if (downCount === 0) {
return '#059669'
} else if (downCount === ids.length) {
return '#df484a'
} else {
return '#f29030'
}
}
export default function MonitorList({ monitors, state }: { monitors: MonitorTarget[]; state: MonitorState }) {
// @ts-ignore
let group: any = pageConfig.group
let groupedMonitor = group && Object.keys(group).length > 0
let content
if (groupedMonitor) {
// Grouped monitors
content = (
<Accordion multiple defaultValue={Object.keys(group)} variant='contained'>
{
Object.keys(group).map(groupName => (
<Accordion.Item key={groupName} value={groupName}>
<Accordion.Control>
<div style={{ display: 'flex', justifyContent: 'space-between', width: '100%', alignItems: 'center' }}>
<div>{groupName}</div>
<Text fw={500} style={{ display: 'inline', paddingRight: '5px', color: getStatusTextColor(state, group[groupName])}}>
{group[groupName].length - countDownCount(state, group[groupName])}
/{group[groupName].length} Operational
</Text>
</div>
</Accordion.Control>
<Accordion.Panel>
{
monitors
.filter(monitor => group[groupName].includes(monitor.id))
.sort((a, b) => group[groupName].indexOf(a.id) - group[groupName].indexOf(b.id))
.map(monitor => (
<div key={monitor.id}>
<Card.Section ml="xs" mr="xs">
<MonitorDetail monitor={monitor} state={state} />
</Card.Section>
</div>
))
}
</Accordion.Panel>
</Accordion.Item>
))
}
</Accordion>
)
} else {
// Ungrouped monitors
content = monitors.map((monitor) => (
<div key={monitor.id}>
<Card.Section ml="xs" mr="xs">
<MonitorDetail monitor={monitor} state={state} />
</Card.Section>
</div>
))
}
export default function MonitorList({ monitors, state }: { monitors: any; state: MonitorState }) {
return (
<Center>
<Card
@ -12,16 +89,10 @@ export default function MonitorList({ monitors, state }: { monitors: any; state:
ml="xl"
mr="xl"
mt="xl"
withBorder
style={{ width: '865px' }}
withBorder={!groupedMonitor}
style={{ width: groupedMonitor ? '897px' : '865px' }}
>
{monitors.map((monitor: MonitorTarget) => (
<div key={monitor.id}>
<Card.Section ml="xs" mr="xs">
<MonitorDetail monitor={monitor} state={state} />
</Card.Section>
</div>
))}
{content}
</Card>
</Center>
)

View File

@ -7,6 +7,13 @@ const pageConfig = {
{ link: 'https://blog.lyc8503.net/', label: 'Blog' },
{ link: 'mailto:me@lyc8503.net', label: 'Email Me', highlight: true },
],
// [OPTIONAL] Group your monitors
// If not specified, all monitors will be shown in a single list
// If specified, monitors will be grouped and ordered, not-listed monitors will be invisble (but still monitored)
group: {
"🌐 Public (example group name)": ['foo_monitor', 'bar_monitor', 'more monitor ids...'],
"🔐 Private": ['test_tcp_monitor'],
},
}
const workerConfig = {