diff --git a/dashboard/static/index.html b/dashboard/static/index.html
index de4c4c7..61f39bb 100644
--- a/dashboard/static/index.html
+++ b/dashboard/static/index.html
@@ -1615,6 +1615,7 @@
Ordo AI Stack Dashboard
+
+
+
+
+ Grafana — llama.cpp & GPU
+ Real-time performance. Requires the monitoring profile; opens full Grafana in a new tab.
+
+
+
+
+
+
@@ -3982,8 +3994,25 @@
Dashboard login
});
// ── End Compute Pressure ──────────────────────────────────
+ // Grafana is served as a sibling path on the same tailnet origin (/grafana/),
+ // behind the same SSO front door. kiosk mode hides Grafana's own chrome for a
+ // clean embed. Injected lazily so the iframe only loads when the tab is opened.
+ function loadGrafanaTab() {
+ const box = document.getElementById("grafana-embed");
+ const openLink = document.getElementById("grafana-open");
+ if (!box) return;
+ const base = location.origin + "/grafana/d/ordo-llm-gpu/ordo-llm-gpu";
+ if (openLink) openLink.href = base + "?refresh=10s";
+ if (box.querySelector("iframe")) return; // already loaded
+ const iframe = document.createElement("iframe");
+ iframe.src = base + "?kiosk&refresh=10s";
+ iframe.style.cssText = "width:100%;height:100%;border:0;";
+ iframe.setAttribute("title", "Grafana — llama.cpp & GPU metrics");
+ box.appendChild(iframe);
+ }
+
function activateTab(name) {
- const tabs = ["models", "gpu", "registry", "modelctl", "services", "mcp", "orchestration"];
+ const tabs = ["models", "gpu", "registry", "modelctl", "services", "mcp", "orchestration", "grafana"];
if (!tabs.includes(name)) name = "models";
document.querySelectorAll(".tab-btn").forEach(b => {
const on = b.dataset.tab === name;
@@ -4004,6 +4033,7 @@ Dashboard login
if (name === "orchestration" && typeof loadOrchestrationTab === "function") loadOrchestrationTab();
if (name !== "orchestration" && orchGpuTimer) { clearInterval(orchGpuTimer); orchGpuTimer = null; }
if (name === "modelctl" && typeof loadModelControl === "function") loadModelControl();
+ if (name === "grafana" && typeof loadGrafanaTab === "function") loadGrafanaTab();
}
document.querySelectorAll(".tab-btn").forEach(b => b.addEventListener("click", () => activateTab(b.dataset.tab)));
window.addEventListener("hashchange", () => activateTab(location.hash.replace("#", "")));