feat: implement web mode for process detail fetching and management, enhance server routing for SPA
This commit is contained in:
@@ -5,6 +5,13 @@ import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'
|
||||
import { Progress } from '@/components/ui/progress'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
// Detect if running inside Wails desktop or as a standalone web app
|
||||
const isWeb = !(window as any).__wails_ipc_active &&
|
||||
typeof (window as any)['go'] === 'undefined'
|
||||
|
||||
// Base URL for web mode: same origin as the page
|
||||
const apiBase = `${window.location.protocol}//${window.location.host}`
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -188,8 +195,9 @@ function ProcessDetailPanel({
|
||||
|
||||
const load = useCallback(async () => {
|
||||
try {
|
||||
// Use low-level Wails IPC — binding will be regenerated automatically
|
||||
const d = await (window as any)['go']['main']['App']['GetProcessDetail'](pid) as ProcessDetail
|
||||
const d: ProcessDetail = isWeb
|
||||
? await fetch(`${apiBase}/api/process/${pid}`).then(r => { if (!r.ok) throw new Error(); return r.json() })
|
||||
: await (window as any)['go']['main']['App']['GetProcessDetail'](pid) as ProcessDetail
|
||||
setDetail(d)
|
||||
} catch {
|
||||
setDetail(null)
|
||||
@@ -208,7 +216,12 @@ function ProcessDetailPanel({
|
||||
setKilling(true)
|
||||
setKillError(null)
|
||||
try {
|
||||
await (window as any)['go']['main']['App']['KillProcess'](pid, force)
|
||||
if (isWeb) {
|
||||
const res = await fetch(`${apiBase}/api/process/${pid}/kill${force ? '?force=true' : ''}`, { method: 'POST' })
|
||||
if (!res.ok) throw new Error(await res.text())
|
||||
} else {
|
||||
await (window as any)['go']['main']['App']['KillProcess'](pid, force)
|
||||
}
|
||||
// stop refreshing — process is gone
|
||||
if (intervalRef.current) clearInterval(intervalRef.current)
|
||||
onClose()
|
||||
@@ -231,10 +244,18 @@ function ProcessDetailPanel({
|
||||
lastManNameRef.current = detail.name
|
||||
setManPageLoading(true)
|
||||
setManPage(null)
|
||||
;(window as any)['go']['main']['App']['GetManPage'](detail.name)
|
||||
.then((text: string) => { setManPage(text || null) })
|
||||
.catch(() => setManPage(null))
|
||||
.finally(() => setManPageLoading(false))
|
||||
if (isWeb) {
|
||||
fetch(`${apiBase}/api/man/${encodeURIComponent(detail.name)}`)
|
||||
.then(r => r.ok ? r.text() : Promise.reject())
|
||||
.then(text => setManPage(text || null))
|
||||
.catch(() => setManPage(null))
|
||||
.finally(() => setManPageLoading(false))
|
||||
} else {
|
||||
;(window as any)['go']['main']['App']['GetManPage'](detail.name)
|
||||
.then((text: string) => { setManPage(text || null) })
|
||||
.catch(() => setManPage(null))
|
||||
.finally(() => setManPageLoading(false))
|
||||
}
|
||||
}, [detail?.name])
|
||||
|
||||
return (
|
||||
@@ -541,6 +562,15 @@ export default function App() {
|
||||
const [pageSize, setPageSize] = useState(20)
|
||||
|
||||
useEffect(() => {
|
||||
if (isWeb) {
|
||||
// Web mode: connect to SSE stream
|
||||
const es = new EventSource(`${apiBase}/api/metrics/stream`)
|
||||
es.onmessage = (e) => {
|
||||
try { setMetrics(JSON.parse(e.data) as Metrics) } catch {}
|
||||
}
|
||||
return () => es.close()
|
||||
}
|
||||
// Wails desktop mode: listen to pushed events
|
||||
const handler = (m: Metrics) => setMetrics(m)
|
||||
EventsOn('metrics', handler)
|
||||
return () => EventsOff('metrics')
|
||||
|
||||
Reference in New Issue
Block a user