From eb4c42b0b5f58c50bdc2310b56a17e0a189cdf52 Mon Sep 17 00:00:00 2001 From: Spark Date: Fri, 23 Oct 2026 04:06:11 +0000 Subject: [PATCH] =?UTF-8?q?7.81.0=20=E2=80=94=20Panneau=20Spark=20V3=20:?= =?UTF-8?q?=20la=20console=20en=20surimpression=20pleine=20page=20(panneau?= =?UTF-8?q?=20octet-identique=20=C3=A0=20TikTak=200.60.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 26 +++++++ VERSION | 2 +- static/js/draco-panneau.js | 134 ++++++++++++++++++++++++++++++++++--- 3 files changed, 151 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3254a34..36986a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog - FlowDeck +## v7.81.0 (2026-10-22) — Panneau Spark V3 : la console en surimpression pleine page + +- **Fini le nouvel onglet** (demande de Bruno) : le bouton + « Console ↗ » du panneau Spark devient « Console ⤢ » et ouvre + la console du service d'agents **dans la même page**, en + surimpression qui naît à la géométrie du panneau (ancrée à + droite, sa largeur) puis **s'étend en ~300 ms jusqu'à recouvrir + toute la fenêtre**. L'URL profonde est inchangée + (`?disc=`, `?app=flowdeck`). +- **Barre d'outils de la surimpression** : « ◧ Mode sidebar » + (animation inverse, retour au panneau latéral resté ouvert + dessous) et « ✕ Fermer l'agent » (referme surimpression **et** + panneau). Échap hors iframe = « Mode sidebar ». +- **Iframe créé paresseusement et conservé** : chargé au premier + clic, puis masqué/réaffiché sans rechargement — l'état de la + console persiste entre ouvertures. `allow="microphone"` pour + la dictée encadrée (aucune Permissions-Policy de Flowdeck ne + bloque le micro, vérifié) ; côté service, la 0.20.0 autorise + l'encadrement par les seules origines des 4 applications + (CSP `frame-ancestors`). +- La surimpression vit entièrement dans le fichier panneau + (DOM + styles injectés, thème synchronisé) ; seul + `static/js/draco-panneau.js` change ici, **octet-identique** + au canonique TikTak 0.60.0 (md5 commun vérifié). Kanbante et + ObsiGate suivront en vague 2 du panneau V3. + ## v7.80.2 (2026-10-22) — /api/health : version lue depuis le fichier VERSION - La version de l'app FastAPI était une constante codée en dur diff --git a/VERSION b/VERSION index 4e816fc..80af335 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.80.2 +7.81.0 diff --git a/static/js/draco-panneau.js b/static/js/draco-panneau.js index b954674..4f0d5df 100644 --- a/static/js/draco-panneau.js +++ b/static/js/draco-panneau.js @@ -18,10 +18,16 @@ * Panneau v2 (Lot 1) : rendu Markdown, largeur réglable à la souris * (persistée), thème clair/sombre aligné sur l'app hôte * (html[data-theme], repli prefers-color-scheme, suivi en direct). - * Bouton « Console ↗ » (barre des discussions) : ouvre la console web - * du même service (agent.dracodev.net) dans un nouvel onglet, sur la - * discussion courante (?disc=) et avec l'app d'origine (?app=), - * déduite du sous-domaine de l'hôte. + * Bouton « Console » (barre des discussions) : ouvre la console web + * du même service (agent.dracodev.net) DANS la page, en surimpression + * pleine page (iframe) qui naît à la géométrie du panneau puis + * s'étend à toute la fenêtre ; l'URL profonde (?disc= discussion + * courante, ?app= app d'origine déduite du sous-domaine) est celle + * du premier chargement — l'iframe est créé paresseusement et + * conservé, la console garde son état entre ouvertures. La barre + * d'outils de la surimpression offre « Mode sidebar » (retour au + * panneau seul, animation inverse) et « Fermer l'agent » (referme + * surimpression et panneau). * États honnêtes : service injoignable / session non reconnue / LLM non * configuré / exécuteur non configuré sont affichés tels quels. */ (function () { @@ -48,23 +54,124 @@ catch (e) { return null; } } - /* ── Console web (même service, nouvel onglet) ─────────────── */ + /* ── Console web (même service, surimpression pleine page) ─── */ function appHote() { var h = (window.location.hostname || "").split(".")[0]; var correspondance = { tiktak: "tiktak", flowdeck: "flowdeck", kanbante: "kanbante", og: "obsigate" }; return correspondance[h] || null; } - function ouvrirConsole() { + function urlConsole() { var params = []; var id = convId || convStockee(); if (id) params.push("disc=" + encodeURIComponent(id)); var app = appHote(); if (app) params.push("app=" + encodeURIComponent(app)); - window.open(API + "/" + (params.length ? "?" + params.join("&") : ""), - "_blank", "noopener"); + return API + "/" + (params.length ? "?" + params.join("&") : ""); } + /* La surimpression vit entièrement dans ce fichier (DOM + styles + * injectés) : les apps hôtes n'ont que ce fichier à recopier. Son + * thème suit celui du panneau (data-draco-theme synchronisé par + * appliquerTheme) et sa palette reprend les mêmes valeurs que + * draco-panneau.css. L'iframe est créé au premier clic puis + * conservé : rouvrir la console ne le recharge pas. */ + var surEl = null, surCadre = null, surOuverte = false; + var STYLES_CONSOLE = + ".draco-console-sur{" + + "--p-fond:#fbfbfa;--p-surface:#ffffff;--p-bord:#e4e5e0;--p-texte:#242624;" + + "--p-chip:#f4f5f1;--p-chip-bord:#d6d8d1;--p-chip-survol:#e9ebe4;--p-accent:#7c5cd6;" + + "position:fixed;top:0;right:0;height:100dvh;width:388px;max-width:100vw;z-index:1000;" + + "background:var(--p-fond);color:var(--p-texte);" + + "box-shadow:-12px 0 36px rgb(0 0 0 / .22);" + + "display:flex;flex-direction:column;transition:width .3s ease;" + + "font:14px/1.5 system-ui,\"Segoe UI\",sans-serif}" + + ".draco-console-sur[data-draco-theme=\"dark\"]{" + + "--p-fond:#17181a;--p-surface:#1f2023;--p-bord:#33353a;--p-texte:#eceeeb;" + + "--p-chip:#26272b;--p-chip-bord:#3a3c41;--p-chip-survol:#2e3036}" + + ".draco-console-sur[hidden]{display:none}" + + ".draco-console-barre{display:flex;align-items:center;gap:9px;flex:none;" + + "padding:9px 12px;border-bottom:1px solid var(--p-bord);background:var(--p-surface)}" + + ".draco-console-barre .dc-titre{font-weight:700;font-size:14px;" + + "display:flex;align-items:center;gap:8px;white-space:nowrap}" + + ".draco-console-barre .dc-etoile{color:var(--p-accent);font-size:17px}" + + ".draco-console-barre .dc-actions{margin-left:auto;display:flex;gap:7px}" + + ".draco-console-barre button{border:1px solid var(--p-chip-bord);" + + "background:var(--p-chip);color:var(--p-texte);border-radius:999px;" + + "padding:5px 12px;font:600 12.5px system-ui;cursor:pointer;white-space:nowrap}" + + ".draco-console-barre button:hover{background:var(--p-chip-survol)}" + + ".draco-console-cadre{flex:1;width:100%;border:0;display:block;background:var(--p-fond)}"; + + function assurerSurimpression() { + if (surEl) return; + if (!document.getElementById("draco-console-styles")) { + var st = document.createElement("style"); + st.id = "draco-console-styles"; + st.textContent = STYLES_CONSOLE; + document.head.appendChild(st); + } + surEl = document.createElement("div"); + surEl.className = "draco-console-sur"; + surEl.setAttribute("aria-label", "Console Spark"); + surEl.hidden = true; + surEl.innerHTML = + '
' + + ' ✦ Console Spark' + + ' ' + + ' ' + + ' ' + + '
' + + ''; + document.body.appendChild(surEl); + surCadre = surEl.querySelector("iframe"); + surEl.querySelector('[data-dc="sidebar"]') + .addEventListener("click", modeSidebarConsole); + surEl.querySelector('[data-dc="fermer"]') + .addEventListener("click", fermerAgentConsole); + appliquerTheme(); + } + + function largeurPanneau() { + if (root) { + var w = root.getBoundingClientRect().width; + if (w > 0) return Math.round(w); + } + return 388; + } + + function ouvrirConsole() { + assurerSurimpression(); + if (!surCadre.getAttribute("src")) surCadre.src = urlConsole(); + if (surOuverte) return; + surOuverte = true; + /* Naissance à la géométrie du panneau (ancrée à droite), puis + * extension à toute la page ; le double rAF laisse le temps de + * peindre la largeur de départ, sinon la transition ne joue pas. */ + surEl.style.width = largeurPanneau() + "px"; + surEl.hidden = false; + requestAnimationFrame(function () { + requestAnimationFrame(function () { surEl.style.width = "100%"; }); + }); + } + + function retrecirConsole() { + if (!surEl || !surOuverte) return; + surOuverte = false; + var fini = false; + function terminer() { + if (fini) return; + fini = true; + surEl.removeEventListener("transitionend", surFin); + surEl.hidden = true; // l'iframe reste chargé, juste masqué + } + function surFin(ev) { if (ev.propertyName === "width") terminer(); } + surEl.addEventListener("transitionend", surFin); + setTimeout(terminer, 380); // filet si transitionend ne vient pas + surEl.style.width = largeurPanneau() + "px"; + } + function modeSidebarConsole() { retrecirConsole(); } + function fermerAgentConsole() { fermer(); retrecirConsole(); } + /* ── Thème : suivre l'app hôte ─────────────────────────────── */ function themeHote() { var t = document.documentElement.getAttribute("data-theme"); @@ -78,6 +185,7 @@ } function appliquerTheme() { if (root) root.setAttribute("data-draco-theme", themeHote()); + if (surEl) surEl.setAttribute("data-draco-theme", themeHote()); } function surveillerTheme() { try { @@ -143,7 +251,7 @@ ' Discussion principale' + ' ' + ' ' + - ' ' + + ' ' + '' + '' + '
' + @@ -178,7 +286,13 @@ appliquerLargeur(); window.addEventListener("resize", appliquerLargeur); document.addEventListener("keydown", function (ev) { - if (ev.key === "Escape" && root.classList.contains("open")) fermer(); + if (ev.key !== "Escape") return; + /* Surimpression ouverte : Échap = retour au panneau seul + * (« Mode sidebar »). Quand le focus est dans l'iframe de la + * console (autre origine), l'événement ne remonte pas + * jusqu'ici : il ne peut donc pas fermer par surprise. */ + if (surOuverte) { modeSidebarConsole(); return; } + if (root.classList.contains("open")) fermer(); }); }