Backend (nvcurve/): - hal/fans.py, hal/limits.py, hal/gpu.py: replace conditional pynvml imports with the established 'pynvml: Any = _pynvml_import' pattern (fixes ~50 'possibly unbound' errors); type the result dicts; guard query_interface() results; explicit uuid/pci-bus parsing (int, hex convention documented); modernize Optional[T] -> T | None - cli.py: fix 'curve_state' possibly-unbound and snap_path None handling in cmd_setup; wrap unchecked int()/open()/makedirs() calls in try/except with clean CLI errors; add module logger for silent except-pass blocks; raise ... from exc; fix unused loop vars and set-comprehension - hal/snapshot.py: filepath: str | None; wrap all file ops; sorted imports; remove unused CT_POINTS import - daemon.py: extract 0o666 to _SOCKET_MODE constant (intentional for /run sockets) with nosemgrep - server.py: nosemgrep for Python 3.7-compat false positive (project requires >= 3.12); log previously-swallowed exception - profiles/native.py, profiles/apply.py: wrap file ops and int(k) profile-key parsing; sorted imports; modernize typing Frontend (frontend/src): - Add .js extensions to all relative imports (standard TS-ESM; Vite resolves .js -> .ts) - React.FormEvent (deprecated in React 19 types) -> React.SubmitEvent - catch (e: any) -> catch (e: unknown) + instanceof Error narrowing - React-hooks: move ref writes from render into effects; convert viewport reset to render-phase state adjustment; split selectPoint(index, multi) into selectPoint + togglePoint (no flag argument); remove non-null assertion - Static inline styles -> Tailwind classes (dynamic positioning/cursor styles kept) - Remove non-standard 'container' option from scrollIntoView (browsers ignore unknown options) which had orphaned a @ts-expect-error - Object.fromEntries for Map -> Record conversion Tooling: - .gitignore: ignore .codegraph/ local tool data Verified: tsc --noEmit, vite production build, python imports, and full LSP scan (0 errors/warnings in both projects).
60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
import { GaugeCard } from "./GaugeCard.js";
|
|
import { fmt } from "../../utils/units.js";
|
|
import type { MonitoringSample } from "../../types.js";
|
|
|
|
interface Props {
|
|
monitor: MonitoringSample | null;
|
|
history: MonitoringSample[];
|
|
}
|
|
|
|
function pluck<K extends keyof MonitoringSample>(
|
|
history: MonitoringSample[],
|
|
key: K,
|
|
): number[] {
|
|
return history.map((s) => (s[key] as number | null) ?? 0);
|
|
}
|
|
|
|
export function PerformanceMonitor({ monitor, history }: Props) {
|
|
const memUsed = monitor?.mem_used_mib ?? null;
|
|
const memTotal = monitor?.mem_total_mib ?? null;
|
|
const memLabel =
|
|
memUsed != null && memTotal != null
|
|
? `${memUsed.toFixed(0)} / ${memTotal.toFixed(0)} MiB`
|
|
: "—";
|
|
|
|
return (
|
|
<div className="flex flex-col gap-2 w-full h-full">
|
|
<div className="bg-zinc-900 rounded-lg p-3 flex flex-col gap-2 h-full">
|
|
<div className="flex items-center justify-between pb-2 border-b border-zinc-800">
|
|
<span className="text-xs text-zinc-500 uppercase tracking-wider font-semibold">
|
|
Live Monitor
|
|
</span>
|
|
</div>
|
|
<div className="flex flex-col gap-2 mt-1">
|
|
<GaugeCard
|
|
label="Mem Clock"
|
|
value={fmt.mhz(monitor?.mem_clock_mhz)}
|
|
history={pluck(history, "mem_clock_mhz")}
|
|
color="#67e8f9"
|
|
max={20000}
|
|
/>
|
|
<GaugeCard
|
|
label="Power Draw"
|
|
value={fmt.watts(monitor?.power_w)}
|
|
history={pluck(history, "power_w")}
|
|
color="#f472b6"
|
|
max={600}
|
|
/>
|
|
<GaugeCard
|
|
label="VRAM Used"
|
|
value={memLabel}
|
|
history={pluck(history, "mem_used_mib")}
|
|
color="#a78bfa"
|
|
max={memTotal ?? 32768}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|