feat: allow public monitor route without login and add monitor page

This commit is contained in:
zhi
2026-03-11 11:59:56 +00:00
parent d3562582b4
commit bc1714281c
4 changed files with 149 additions and 16 deletions

113
src/pages/MonitorPage.tsx Normal file
View File

@@ -0,0 +1,113 @@
import { useEffect, useState } from 'react'
import api from '@/services/api'
interface ProviderRow {
account_id: number
provider: string
label: string
usage_pct: number | null
status: string
error?: string | null
fetched_at?: string | null
reset_at?: string | null
}
interface ServerRow {
server_id: number
identifier: string
display_name: string
online: boolean
openclaw_version?: string | null
cpu_pct?: number | null
mem_pct?: number | null
disk_pct?: number | null
swap_pct?: number | null
agents: Array<{ id?: string; name?: string; status?: string }>
last_seen_at?: string | null
}
interface OverviewData {
issues: {
total_issues: number
new_issues_24h: number
processed_issues_24h: number
computed_at: string
}
providers: ProviderRow[]
servers: ServerRow[]
generated_at: string
}
export default function MonitorPage() {
const [data, setData] = useState<OverviewData | null>(null)
const [loading, setLoading] = useState(true)
const load = async () => {
try {
const res = await api.get<OverviewData>('/monitor/public/overview')
setData(res.data)
} finally {
setLoading(false)
}
}
useEffect(() => {
load()
const t = setInterval(load, 30000)
return () => clearInterval(t)
}, [])
if (loading) return <div className='loading'>Monitor loading...</div>
if (!data) return <div className='loading'>Monitor load failed</div>
return (
<div>
<h2>📡 Monitor</h2>
<section>
<h3>Issue 24</h3>
<ul>
<li> Issue{data.issues.total_issues}</li>
<li>24{data.issues.new_issues_24h}</li>
<li>24resolved/closed{data.issues.processed_issues_24h}</li>
</ul>
</section>
<section>
<h3>Provider Usage</h3>
{data.providers.length === 0 ? <p> provider </p> : (
<ul>
{data.providers.map((p) => (
<li key={p.account_id}>
<strong>{p.provider}</strong> / {p.label} · status: {p.status}
{p.usage_pct !== null ? : ''}
{p.reset_at ? : ''}
{p.error ? : ''}
</li>
))}
</ul>
)}
</section>
<section>
<h3></h3>
{data.servers.length === 0 ? <p></p> : (
<div>
{data.servers.map((s) => (
<div key={s.server_id} style={{ marginBottom: 12, padding: 12, border: '1px solid #ddd', borderRadius: 8 }}>
<div>
<strong>{s.display_name}</strong> ({s.identifier}) · {s.online ? '🟢 在线' : '🔴 离线'}
</div>
<div>
CPU: {s.cpu_pct ?? '-'}% · MEM: {s.mem_pct ?? '-'}% · DISK: {s.disk_pct ?? '-'}% · SWAP: {s.swap_pct ?? '-'}%
</div>
<div>OpenClaw: {s.openclaw_version || '-'}</div>
<div>Agents: {s.agents?.length || 0}</div>
</div>
))}
</div>
)}
</section>
</div>
)
}