Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion dashboard/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1615,6 +1615,7 @@ <h1>Ordo AI Stack Dashboard</h1>
<button class="tab-btn" data-tab="services" role="tab">⚡ Services</button>
<button class="tab-btn" data-tab="mcp" role="tab">🧩 MCP</button>
<button class="tab-btn" data-tab="orchestration" role="tab">🛠️ Orchestration</button>
<button class="tab-btn" data-tab="grafana" role="tab">📊 Grafana</button>
</nav>
</div>
<div class="header-actions">
Expand Down Expand Up @@ -1960,6 +1961,17 @@ <h2>Orchestration</h2>

</div>


<div class="tab-panel" data-tab="grafana">
<section id="grafana-section">
<h2>Grafana — llama.cpp &amp; GPU</h2>
<p class="section-desc">Real-time performance. Requires the <code>monitoring</code> profile; opens full Grafana in a <a id="grafana-open" href="#" target="_blank" rel="noopener">new tab</a>.</p>
<div id="grafana-embed" style="width:100%;height:78vh;border:1px solid var(--border,#333);border-radius:8px;overflow:hidden;background:#111;">
<!-- iframe injected lazily by loadGrafanaTab() on first activation -->
</div>
</section>
</div>

<div class="toast-container" id="toasts" role="region" aria-label="Notifications" aria-live="polite"></div>

<div id="auth-modal" class="modal-overlay" style="display:none;" role="dialog" aria-labelledby="auth-modal-title" aria-modal="true">
Expand Down Expand Up @@ -3982,8 +3994,25 @@ <h2 id="auth-modal-title">Dashboard login</h2>
});
// ── 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;
Expand All @@ -4004,6 +4033,7 @@ <h2 id="auth-modal-title">Dashboard login</h2>
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("#", "")));
Expand Down
Loading