From d1ffc97dc3ecddc3630a3675c8ee63a4a00eeda1 Mon Sep 17 00:00:00 2001 From: nathaninline Date: Wed, 5 Aug 2026 21:45:34 +0200 Subject: [PATCH] Menu : reserver la hauteur des blocs charges par le reseau --- internal/ajean/ui/index.html | 38 +++++++++++++++++++++++-- internal/ajean/ui/src/index.tmpl.html | 4 ++- internal/ajean/ui/src/js/06-settings.js | 33 ++++++++++++++++++++- internal/ajean/ui/src/styles.css | 1 + 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/internal/ajean/ui/index.html b/internal/ajean/ui/index.html index c7e75f5..41538bf 100644 --- a/internal/ajean/ui/index.html +++ b/internal/ajean/ui/index.html @@ -869,6 +869,7 @@ textarea.sctl{min-height:76px;resize:vertical;line-height:1.5} .lc-spin{display:inline-block;animation:spin 1s linear infinite} /* Serveurs MCP */ .mcp-list{display:flex;flex-direction:column;gap:4px} + .mcp-row{display:flex;align-items:center;gap:8px;padding:6px 10px;border:1px solid var(--border);border-radius:6px;background:var(--panel);cursor:pointer} .mcp-row:hover{border-color:var(--accent)} .mcp-row.off{opacity:.6} @@ -1130,7 +1131,9 @@ button:hover{border-color:var(--dim);color:var(--text)}
Serveurs MCP?Connecte des serveurs MCP (Model Context Protocol) pour donner de nouveaux outils à l'IA : accès fichiers, bases de données, APIs métier… stdio = programme lancé localement (npx/uvx/binaire) · http = serveur distant. ⚠ un serveur stdio exécute du code sur cette machine, au même titre que le shell.
-
+ +
(aucun serveur — ajoute un serveur fichiers, une base de données, une API…)
@@ -2074,6 +2077,31 @@ async function loadCfg(){ if(m) rows.push(row('N-CPU-MOE', m[1])); document.getElementById('cfg').innerHTML = rows.join(''); } +// --- Réserve de hauteur des blocs peuplés par le réseau --------------------- +// Ces blocs sont vides (ou réduits à « … ») tant que le serveur n'a pas répondu, +// puis prennent leur vraie taille : tout le menu sautait alors d'un cran, ce qui +// se voyait surtout sur les sections du bas (« Moteur »). On mémorise leur +// hauteur d'une session à l'autre et on la réserve au démarrage ; la réserve +// tombe dès que le vrai contenu est là (elle ne fait que TENIR la place, elle +// n'affiche jamais rien de faux). +const HRESERVE=['cfg','vram','ram-details','presets','internet-status','mcp-list']; +function reserveHeights(){ + HRESERVE.forEach(id=>{ + try{ + const h=parseInt(localStorage.getItem('jean-h-'+id)||'0',10); + const el=document.getElementById(id); + if(el && h>0) el.style.minHeight=h+'px'; + }catch(e){} + }); +} +function releaseHeights(){ + HRESERVE.forEach(id=>{ + const el=document.getElementById(id); if(!el) return; + el.style.minHeight=''; + try{ localStorage.setItem('jean-h-'+id, String(el.offsetHeight||0)); }catch(e){} + }); +} +document.addEventListener('DOMContentLoaded', reserveHeights); async function loadPresets(){ const p=await jget('/api/presets'); const act = p.find(x=>x.active); @@ -2340,7 +2368,13 @@ async function clearCrawlKey(){ renderInternet(await jpost('/api/internet',{key:''})); toast('clé retirée'); } -async function loadAll(){ await Promise.all([loadStatus(),loadVram(),loadRam(),loadCfg(),loadPresets(),loadAgent(),loadInternet(),loadMCP(),loadApiKey(),loadPrefs(),loadLlamacpp(),loadRemote()]); } +async function loadAll(){ + // allSettled et pas all : un seul chargement en échec (accès distant coupé, + // clé API absente…) ne doit pas empêcher la suite — et surtout pas laisser les + // hauteurs réservées en place pour toujours. + await Promise.allSettled([loadStatus(),loadVram(),loadRam(),loadCfg(),loadPresets(),loadAgent(),loadInternet(),loadMCP(),loadApiKey(),loadPrefs(),loadLlamacpp(),loadRemote()]); + releaseHeights(); // tout est en place : on rend la main et on mesure pour la prochaine fois +} async function act(a){ toast(a+'…'); await jpost('/api/'+a); setTimeout(loadAll,1500); } function openBenchModal(){ showModal('bench-modal'); } function closeBenchModal(){ hideModal('bench-modal'); } diff --git a/internal/ajean/ui/src/index.tmpl.html b/internal/ajean/ui/src/index.tmpl.html index cad5be3..da2b786 100644 --- a/internal/ajean/ui/src/index.tmpl.html +++ b/internal/ajean/ui/src/index.tmpl.html @@ -140,7 +140,9 @@
Serveurs MCP?Connecte des serveurs MCP (Model Context Protocol) pour donner de nouveaux outils à l'IA : accès fichiers, bases de données, APIs métier… stdio = programme lancé localement (npx/uvx/binaire) · http = serveur distant. ⚠ un serveur stdio exécute du code sur cette machine, au même titre que le shell.
-
+ +
(aucun serveur — ajoute un serveur fichiers, une base de données, une API…)
diff --git a/internal/ajean/ui/src/js/06-settings.js b/internal/ajean/ui/src/js/06-settings.js index 1f1ebd7..d8f7c72 100644 --- a/internal/ajean/ui/src/js/06-settings.js +++ b/internal/ajean/ui/src/js/06-settings.js @@ -1,3 +1,28 @@ +// --- Réserve de hauteur des blocs peuplés par le réseau --------------------- +// Ces blocs sont vides (ou réduits à « … ») tant que le serveur n'a pas répondu, +// puis prennent leur vraie taille : tout le menu sautait alors d'un cran, ce qui +// se voyait surtout sur les sections du bas (« Moteur »). On mémorise leur +// hauteur d'une session à l'autre et on la réserve au démarrage ; la réserve +// tombe dès que le vrai contenu est là (elle ne fait que TENIR la place, elle +// n'affiche jamais rien de faux). +const HRESERVE=['cfg','vram','ram-details','presets','internet-status','mcp-list']; +function reserveHeights(){ + HRESERVE.forEach(id=>{ + try{ + const h=parseInt(localStorage.getItem('jean-h-'+id)||'0',10); + const el=document.getElementById(id); + if(el && h>0) el.style.minHeight=h+'px'; + }catch(e){} + }); +} +function releaseHeights(){ + HRESERVE.forEach(id=>{ + const el=document.getElementById(id); if(!el) return; + el.style.minHeight=''; + try{ localStorage.setItem('jean-h-'+id, String(el.offsetHeight||0)); }catch(e){} + }); +} +document.addEventListener('DOMContentLoaded', reserveHeights); async function loadPresets(){ const p=await jget('/api/presets'); const act = p.find(x=>x.active); @@ -264,5 +289,11 @@ async function clearCrawlKey(){ renderInternet(await jpost('/api/internet',{key:''})); toast('clé retirée'); } -async function loadAll(){ await Promise.all([loadStatus(),loadVram(),loadRam(),loadCfg(),loadPresets(),loadAgent(),loadInternet(),loadMCP(),loadApiKey(),loadPrefs(),loadLlamacpp(),loadRemote()]); } +async function loadAll(){ + // allSettled et pas all : un seul chargement en échec (accès distant coupé, + // clé API absente…) ne doit pas empêcher la suite — et surtout pas laisser les + // hauteurs réservées en place pour toujours. + await Promise.allSettled([loadStatus(),loadVram(),loadRam(),loadCfg(),loadPresets(),loadAgent(),loadInternet(),loadMCP(),loadApiKey(),loadPrefs(),loadLlamacpp(),loadRemote()]); + releaseHeights(); // tout est en place : on rend la main et on mesure pour la prochaine fois +} async function act(a){ toast(a+'…'); await jpost('/api/'+a); setTimeout(loadAll,1500); } diff --git a/internal/ajean/ui/src/styles.css b/internal/ajean/ui/src/styles.css index 514a249..3e4a24c 100644 --- a/internal/ajean/ui/src/styles.css +++ b/internal/ajean/ui/src/styles.css @@ -843,6 +843,7 @@ textarea.sctl{min-height:76px;resize:vertical;line-height:1.5} .lc-spin{display:inline-block;animation:spin 1s linear infinite} /* Serveurs MCP */ .mcp-list{display:flex;flex-direction:column;gap:4px} + .mcp-row{display:flex;align-items:center;gap:8px;padding:6px 10px;border:1px solid var(--border);border-radius:6px;background:var(--panel);cursor:pointer} .mcp-row:hover{border-color:var(--accent)} .mcp-row.off{opacity:.6}