From 87ebd35ad560a01a34ee7cb58e2f0e9c0aaeed8d Mon Sep 17 00:00:00 2001 From: Luca Sacchi Ricciardi Date: Sat, 25 Apr 2026 13:31:04 +0200 Subject: [PATCH] Fix model details modal and make running models primary page --- app/web/static/js/app.js | 91 +++++++++++---------------- app/web/templates/models_running.html | 2 +- main.py | 12 +++- 3 files changed, 45 insertions(+), 60 deletions(-) diff --git a/app/web/static/js/app.js b/app/web/static/js/app.js index 3e8daae..b6847e7 100644 --- a/app/web/static/js/app.js +++ b/app/web/static/js/app.js @@ -39,62 +39,6 @@ class LLMMonitorApp { this.requestSync(); }); - // Listener click card modello - document.getElementById("models-container")?.addEventListener("click", (event) => { - const card = event.target.closest("[data-model-key]"); - if (!card) { - return; - } - const modelKey = card.getAttribute("data-model-key"); - if (!modelKey) { - return; - } - this.showModelDetails(decodeURIComponent(modelKey)); - }); - - // Apertura modal on-hover (con piccolo delay per evitare aperture involontarie) - document.getElementById("models-container")?.addEventListener("mouseover", (event) => { - const card = event.target.closest("[data-model-key]"); - if (!card) { - return; - } - - // Evita trigger quando il mouse si muove dentro la stessa card - if (event.relatedTarget && card.contains(event.relatedTarget)) { - return; - } - - const modelKey = card.getAttribute("data-model-key"); - if (!modelKey) { - return; - } - - if (this.hoverOpenTimer) { - clearTimeout(this.hoverOpenTimer); - } - - this.hoverOpenTimer = setTimeout(() => { - this.showModelDetails(decodeURIComponent(modelKey)); - }, this.hoverOpenDelayMs); - }); - - document.getElementById("models-container")?.addEventListener("mouseout", (event) => { - const card = event.target.closest("[data-model-key]"); - if (!card) { - return; - } - - // Non cancellare se si resta all'interno della stessa card - if (event.relatedTarget && card.contains(event.relatedTarget)) { - return; - } - - if (this.hoverOpenTimer) { - clearTimeout(this.hoverOpenTimer); - this.hoverOpenTimer = null; - } - }); - // Chiusura modal con pulsante X document.getElementById("model-details-close")?.addEventListener("click", () => { this.hideModelDetails(); @@ -223,9 +167,44 @@ class LLMMonitorApp { // Aggiornare solo se veramente diverso if (container.innerHTML !== newHTML) { container.innerHTML = newHTML; + this.bindModelCardInteractions(); } } + // Associare eventi card dopo ogni render (piu affidabile della delega su hover) + bindModelCardInteractions() { + const cards = document.querySelectorAll("#models-container [data-model-key]"); + cards.forEach((card) => { + const modelKey = card.getAttribute("data-model-key"); + if (!modelKey) { + return; + } + + const modelName = decodeURIComponent(modelKey); + + card.addEventListener("click", () => { + this.showModelDetails(modelName); + }); + + card.addEventListener("mouseenter", () => { + if (this.hoverOpenTimer) { + clearTimeout(this.hoverOpenTimer); + } + + this.hoverOpenTimer = setTimeout(() => { + this.showModelDetails(modelName); + }, this.hoverOpenDelayMs); + }); + + card.addEventListener("mouseleave", () => { + if (this.hoverOpenTimer) { + clearTimeout(this.hoverOpenTimer); + this.hoverOpenTimer = null; + } + }); + }); + } + // Renderizzare singola card modello renderModelCard(model) { const formattedDate = this.formatDate(model.modified_at); diff --git a/app/web/templates/models_running.html b/app/web/templates/models_running.html index 6455904..cc06064 100644 --- a/app/web/templates/models_running.html +++ b/app/web/templates/models_running.html @@ -30,7 +30,7 @@
- Dashboard + Modelli Disponibili
diff --git a/main.py b/main.py index ca12fa4..5229469 100644 --- a/main.py +++ b/main.py @@ -53,12 +53,18 @@ templates_path = Path(__file__).parent / "app" / "web" / "templates" @app.get("/") async def root(): - """Redirect alla dashboard""" - return FileResponse(templates_path / "index.html") + """Pagina principale: modelli residenti in memoria (ollama ps).""" + return FileResponse(templates_path / "models_running.html") @app.get("/dashboard") async def dashboard(): - """Dashboard principale""" + """Alias legacy della pagina principale.""" + return FileResponse(templates_path / "models_running.html") + + +@app.get("/models-available") +async def models_available_page(): + """Pagina modelli disponibili su disco.""" return FileResponse(templates_path / "index.html")