feat: add Wails runtime library and initial application setup
- Created package.json for Wails JavaScript runtime library. - Added TypeScript definitions for runtime functions. - Implemented runtime.js with event handling and logging functions. - Initialized Go module with dependencies for Wails and other libraries. - Added main.go for application entry point and asset embedding. - Configured wails.json for application settings and build commands.
This commit is contained in:
107
frontend/src/App.tsx
Normal file
107
frontend/src/App.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { EventsOn, EventsOff } from '../wailsjs/runtime/runtime'
|
||||
|
||||
type ProcessInfo = {
|
||||
pid: number
|
||||
name: string
|
||||
cpu: number
|
||||
mem: number
|
||||
}
|
||||
|
||||
type Metrics = {
|
||||
cpu_percent: number
|
||||
total_mem: number
|
||||
free_mem: number
|
||||
processes: ProcessInfo[]
|
||||
timestamp: number
|
||||
gpu_name?: string
|
||||
gpu_total_mem?: number
|
||||
gpu_used_mem?: number
|
||||
gpu_util_percent?: number
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const [metrics, setMetrics] = useState<Metrics | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const handler = (m: Metrics) => setMetrics(m)
|
||||
EventsOn('metrics', handler)
|
||||
return () => EventsOff('metrics')
|
||||
}, [])
|
||||
|
||||
// No simulator: real metrics only
|
||||
|
||||
return (
|
||||
<div className="app bg-black min-h-screen text-neon">
|
||||
<header className="p-6 flex items-center justify-between">
|
||||
<h1 className="text-3xl font-extrabold tracking-tight">sysmon</h1>
|
||||
<div className="text-sm opacity-80">Realtime system monitor</div>
|
||||
</header>
|
||||
|
||||
<main className="p-6 grid grid-cols-3 gap-6">
|
||||
<section className="col-span-1 bg-[#071422] p-4 rounded-lg border border-[#2b2d42]/40">
|
||||
<h2 className="text-lg font-semibold mb-2">Overview</h2>
|
||||
{metrics ? (
|
||||
<div>
|
||||
<div>CPU: {metrics.cpu_percent.toFixed(1)}%</div>
|
||||
<div>Memory: {((metrics.total_mem - metrics.free_mem) / (1024 * 1024)).toFixed(0)} MB used</div>
|
||||
<div>Memory free: {(metrics.free_mem / (1024 * 1024)).toFixed(0)} MB</div>
|
||||
{metrics.processes && metrics.processes.length > 0 && (
|
||||
<div>
|
||||
Top memory: {
|
||||
(() => {
|
||||
const top = [...metrics.processes].sort((a, b) => b.mem - a.mem)[0]
|
||||
return `${top.name} (${(top.mem / 1024 / 1024).toFixed(1)} MB)`
|
||||
})()
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
<div>Last: {new Date(metrics.timestamp).toLocaleTimeString()}</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>Waiting for metrics…</div>
|
||||
)}
|
||||
</section>
|
||||
|
||||
<section className="col-span-1 bg-[#071422] p-4 rounded-lg border border-[#2b2d42]/40">
|
||||
<h2 className="text-lg font-semibold mb-2">GPU</h2>
|
||||
{metrics ? (
|
||||
<div>
|
||||
<div>Name: {metrics.gpu_name || 'N/A'}</div>
|
||||
<div>GPU Memory: {metrics.gpu_used_mem ? (metrics.gpu_used_mem / 1024 / 1024).toFixed(0) + ' MB used / ' + (metrics.gpu_total_mem! / 1024 / 1024).toFixed(0) + ' MB' : 'N/A'}</div>
|
||||
<div>Util: {metrics.gpu_util_percent ? metrics.gpu_util_percent.toFixed(1) + '%' : 'N/A'}</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>Waiting for GPU…</div>
|
||||
)}
|
||||
</section>
|
||||
|
||||
<section className="col-span-2 bg-[#071422] p-4 rounded-lg border border-[#2b2d42]/40">
|
||||
<h2 className="text-lg font-semibold mb-2">Top processes</h2>
|
||||
<div className="overflow-auto max-h-[60vh]">
|
||||
<table className="w-full table-auto">
|
||||
<thead>
|
||||
<tr className="text-left text-sm opacity-80">
|
||||
<th>PID</th>
|
||||
<th>Name</th>
|
||||
<th>CPU</th>
|
||||
<th>Mem</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{metrics?.processes.map((p) => (
|
||||
<tr key={p.pid} className="odd:bg-black/20">
|
||||
<td>{p.pid}</td>
|
||||
<td>{p.name}</td>
|
||||
<td>{p.cpu.toFixed(1)}%</td>
|
||||
<td>{(p.mem / 1024 / 1024).toFixed(1)} MB</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
10
frontend/src/main.tsx
Normal file
10
frontend/src/main.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import React from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import App from './App'
|
||||
import './styles.css'
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
)
|
||||
15
frontend/src/styles.css
Normal file
15
frontend/src/styles.css
Normal file
@@ -0,0 +1,15 @@
|
||||
:root{
|
||||
--neon: #39ff14;
|
||||
}
|
||||
|
||||
body{font-family: Inter, ui-sans-serif, system-ui; background:#000; color:#e6eef0}
|
||||
.text-neon{color:var(--neon)}
|
||||
|
||||
/* Minimal layout for dev without Tailwind */
|
||||
.app{min-height:100vh}
|
||||
header{padding:1.5rem; display:flex; align-items:center; justify-content:space-between}
|
||||
main{padding:1.5rem; display:grid; grid-template-columns:1fr 2fr; gap:1.5rem}
|
||||
section{background:#071422; padding:1rem; border-radius:0.5rem; border:1px solid rgba(43,45,66,0.4)}
|
||||
table{width:100%; border-collapse:collapse}
|
||||
thead tr{opacity:0.85; font-size:0.9rem}
|
||||
tbody tr:nth-child(odd){background:rgba(0,0,0,0.08)}
|
||||
21
frontend/src/wails-runtime.ts
Normal file
21
frontend/src/wails-runtime.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
type Handler = (m: any) => void
|
||||
|
||||
export function EventsOn(event: string, handler: Handler) {
|
||||
const wrap = (e: CustomEvent) => handler(e.detail)
|
||||
// store reference so it can be removed
|
||||
;(handler as any).__wrap = wrap
|
||||
window.addEventListener(event, wrap as EventListener)
|
||||
}
|
||||
|
||||
export function EventsOff(event: string, handler: Handler) {
|
||||
const wrap = (handler as any).__wrap
|
||||
if (wrap) {
|
||||
window.removeEventListener(event, wrap as EventListener)
|
||||
delete (handler as any).__wrap
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to simulate events from dev environment
|
||||
export function Emit(event: string, payload: any) {
|
||||
window.dispatchEvent(new CustomEvent(event, { detail: payload }))
|
||||
}
|
||||
Reference in New Issue
Block a user