second version
This commit is contained in:
63
frontend/src/pages/Logs.tsx
Normal file
63
frontend/src/pages/Logs.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
|
||||
type LogRecord = {
|
||||
ts?: string
|
||||
level?: string
|
||||
logger?: string
|
||||
msg?: string
|
||||
}
|
||||
|
||||
export function Logs() {
|
||||
const [lines, setLines] = useState<LogRecord[]>([])
|
||||
const bottomRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
|
||||
const ws = new WebSocket(`${proto}//${window.location.host}/ws/logs`)
|
||||
ws.onmessage = (ev) => {
|
||||
try {
|
||||
const rec = JSON.parse(ev.data as string) as LogRecord
|
||||
setLines((prev) => {
|
||||
const next = [...prev, rec]
|
||||
return next.length > 500 ? next.slice(-500) : next
|
||||
})
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
return () => ws.close()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
bottomRef.current?.scrollIntoView({ behavior: 'smooth' })
|
||||
}, [lines.length])
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-slate-950 p-4 text-slate-100 md:p-8">
|
||||
<div className="mx-auto max-w-5xl">
|
||||
<h1 className="text-xl font-bold text-white">Logy EMS</h1>
|
||||
<p className="mt-1 text-sm text-slate-500">Stream z backendu (WebSocket)</p>
|
||||
<pre className="mt-6 max-h-[calc(100vh-8rem)] overflow-auto rounded-xl border border-slate-800 bg-slate-900/80 p-4 font-mono text-xs leading-relaxed">
|
||||
{lines.map((r, i) => (
|
||||
<div
|
||||
key={`${i}-${r.ts}-${r.msg}`}
|
||||
className={
|
||||
r.level === 'ERROR'
|
||||
? 'text-red-300'
|
||||
: r.level === 'WARNING'
|
||||
? 'text-amber-200'
|
||||
: 'text-slate-300'
|
||||
}
|
||||
>
|
||||
<span className="text-slate-600">{r.ts ?? '—'} </span>
|
||||
<span className="text-slate-500">[{r.level ?? '?'}] </span>
|
||||
<span className="text-slate-500">{r.logger ?? ''}: </span>
|
||||
{r.msg ?? ''}
|
||||
</div>
|
||||
))}
|
||||
<div ref={bottomRef} />
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user