feat: add Dashboard tab with live GPU overview

Add a new Dashboard tab as the default/first tab (Dashboard - Curve -
Performance - Fans) showing a full GPU overview.

Backend:
- New hal/dashboard.py: one-shot static GPU info via NVML (VBIOS, CUDA
  cores, compute capability, bus width, BAR1/CPU-accessible VRAM,
  Resizable BAR, PCIe max, max clocks, power limits, temp thresholds,
  persistence mode, fan count, serial, board part number, UUID).
  ROP count and VRAM type are best-effort from a per-model table since
  NVML does not expose them.
- New /api/dashboard endpoint.
- MonitoringSample gains live throttle_reasons (+label), PCIe link
  width/generation (downclocks when idle, so read per poll), and VRAM
  temp (from the MEMORY thermal sensor, if exposed).

Frontend:
- New Dashboard component: critical top row (throttling, voltage,
  GPU/VRAM temps), full live-monitor grid with sparklines, and a static
  GPU-information grid. Unavailable fields are omitted.
- useDashboard hook + DashboardInfo type + api.client dashboard().

Also: restrict CORS to localhost origins (end-anchored), make
_int_key_deltas fail closed on bad keys, and clean up lint blockers in
server.py/monitoring.py.
This commit is contained in:
ARIA committed 2026-09-02 16:56:47 +02:00
1 parent 3c55263250
commit da507d55bb
11 files changed
+907 -72

No files matched your search

+47
View File
@@ -0,0 +1,47 @@
import { useEffect, useState } from "react";
import { api } from "../api/client";
import { useCurveStore } from "../store/curveStore";
import type { DashboardInfo } from "../types";
interface DashboardState {
gpuIndex: number;
data: DashboardInfo | null;
done: boolean;
}
/**
* Fetch static GPU info for the Dashboard tab.
* Re-fetches when the selected GPU changes.
*/
export function useDashboard() {
const { selectedGpuIndex } = useCurveStore();
const [state, setState] = useState<DashboardState>({
gpuIndex: -1,
data: null,
done: false,
});
useEffect(() => {
let cancelled = false;
api
.dashboard(selectedGpuIndex)
.then((data) => {
if (!cancelled)
setState({ gpuIndex: selectedGpuIndex, data, done: true });
})
.catch((err) => {
console.error("Failed to load dashboard info:", err);
if (!cancelled)
setState({ gpuIndex: selectedGpuIndex, data: null, done: true });
});
return () => {
cancelled = true;
};
}, [selectedGpuIndex]);
const isCurrent = state.gpuIndex === selectedGpuIndex;
return {
dashboard: isCurrent ? state.data : null,
loading: !isCurrent || !state.done,
};
}