diff --git a/CHANGELOG.md b/CHANGELOG.md index c0b6d91..c91d50e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,34 @@ # Changelog - FlowDeck +## v7.59.2 (2026-10-07) — Corrections : aide, « Insert below », listes numérotées + +### Fixed + +- **Aide** — bouton **✕** en haut à droite du panneau (classe partagée + `settings-close` : 32 px desktop / **44 px mobile**) + méthode `close()` dans + `help.js` (retour à la page précédente, sinon `/workspaces`) ; + `.settings-panel` passé en `position:relative` pour ancrer les boutons au + panneau (hamburger + ✕) plutôt qu'à la page. +- **Éditeur — « Insert below » (/Write with AI)** : on insère le **markdown + source** conservé à la génération (`AIC._md`) au lieu du texte extrait du + HTML rendu (`_resultText()` ne reste qu'en repli pour les messages d'erreur) — + titres, listes, gras et numéros survivent à l'insertion. +- **Listes numérotées** — elles n'avaient **aucun numéro au rendu** : le CSS + ne déclarait que le retrait, jamais le marqueur. Le rang des blocs + `numbered_list` contigus est désormais calculé au rendu (`data-num`) et + affiché via `content: attr(data-num) ". "` → **`/numbered list` et + l'insertion depuis l'assistant affichent enfin 1, 2, 3**. +- **`md2b`** (markdown → blocs, chemin agent) : les cases à cocher `- [ ]` / + `- [x]` sont testées **avant** la branche des puces (une ligne `- [ ]` + était avalée par cette branche) — aligné sur l'ordre déjà correct de + `paste2b` ; le séparateur `1)` est accepté (CommonMark). +- **Menu slash** — une requête tapée **dans le bloc** (`/numbered list`, focus + qui n'a pas rejoint l'entrée du menu) est répercutée dans le filtre au lieu + d'être ignorée. +- **Tests** — `tests/test_v7592_ui_fixes.py` : **5 tests**, dont 1 test + comportemental **node** qui exécute le vrai `md2b` extrait de la source. +- `ruff` : ordre d'imports de `tests/test_agent.py` (I001 préexistant au pull). + ## v7.59.1 (2026-10-07) — Fix fournisseur Mistral (clé valide, 403 tier_not_allowed) ### Fixed diff --git a/VERSION b/VERSION index b50130e..f06905a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.59.1 +7.59.2 diff --git a/app/main.py b/app/main.py index 1d69fe4..c9340e8 100644 --- a/app/main.py +++ b/app/main.py @@ -186,7 +186,7 @@ async def lifespan(_app: FastAPI): app = FastAPI( title="FlowDeck", - version="7.59.1", + version="7.59.2", docs_url="/docs", redoc_url="/redoc", lifespan=lifespan, diff --git a/app/templates/help.html b/app/templates/help.html index a485252..5c79132 100644 --- a/app/templates/help.html +++ b/app/templates/help.html @@ -35,6 +35,7 @@ +
diff --git a/docs/openapi-v2.json b/docs/openapi-v2.json index 5313079..5c617ba 100644 --- a/docs/openapi-v2.json +++ b/docs/openapi-v2.json @@ -2,7 +2,7 @@ "openapi": "3.1.0", "info": { "title": "FlowDeck", - "version": "7.58.0" + "version": "7.59.2" }, "paths": { "/auth/register": { @@ -1098,7 +1098,7 @@ "dashboard" ], "summary": "Help Page", - "description": "Comprehensive help & documentation page.", + "description": "Help & documentation page — settings-style panel with side navigation.", "operationId": "help_page_help_get", "responses": { "200": { diff --git a/static/css/app.css b/static/css/app.css index 83f9ab7..465ada7 100644 --- a/static/css/app.css +++ b/static/css/app.css @@ -2476,11 +2476,20 @@ button.breadcrumb-current { max-width: 260px; } font-size: 16px; } -/* Numbered list */ +/* Numbered list — data-num est calculé au rendu (rangée contiguë) */ .block-numbered { - padding-left: 22px; + padding-left: 32px; position: relative; } +.block-numbered[data-num]::before { + content: attr(data-num) ". "; + position: absolute; + left: 0; + top: 0; + min-width: 24px; + color: var(--text-primary); + font-size: 16px; +} /* To-do */ .block-todo { diff --git a/static/css/settings.css b/static/css/settings.css index 705a091..6933885 100644 --- a/static/css/settings.css +++ b/static/css/settings.css @@ -1,6 +1,6 @@ /* ═══ Panel skeleton shared by /settings and /help (Notion-style modal) ═══ */ .settings-overlay{position:fixed;inset:0;z-index:500;display:flex;background:rgba(0,0,0,.4);backdrop-filter:blur(2px);} -.settings-panel{display:flex;width:1050px;max-width:98vw;height:85vh;margin:auto;background:var(--bg-primary);border:1px solid var(--border-strong);border-radius:14px;box-shadow:var(--shadow-modal);overflow:hidden;} +.settings-panel{position:relative;display:flex;width:1050px;max-width:98vw;height:85vh;margin:auto;background:var(--bg-primary);border:1px solid var(--border-strong);border-radius:14px;box-shadow:var(--shadow-modal);overflow:hidden;} .settings-nav{width:200px;min-width:200px;background:var(--bg-sidebar);border-right:1px solid var(--border);padding:8px 0;overflow-y:auto;} .settings-nav-header{padding:12px 16px;font-size:13px;font-weight:600;color:var(--text-dim);text-transform:uppercase;letter-spacing:.5px;} .settings-nav-item{display:flex;align-items:center;gap:8px;padding:6px 16px;font-size:13px;color:var(--text-secondary);cursor:pointer;transition:background 100ms;border-radius:0;} diff --git a/static/js/help.js b/static/js/help.js index 7450c28..07a6cde 100644 --- a/static/js/help.js +++ b/static/js/help.js @@ -7,6 +7,11 @@ function helpInit() { section: 'start', navOpen: false, closeNavOnMobile() { this.navOpen = false; }, + // Bouton ✕ (haut droite, visible aussi en mobile) : ferme l'aide. + close() { + if (document.referrer && document.referrer !== location.href) { history.back(); } + else { location.href = '/workspaces'; } + }, go(sec) { this.section = sec; this.navOpen = false; diff --git a/static/js/page_editor_scripts.js b/static/js/page_editor_scripts.js index ccbb508..837e915 100644 --- a/static/js/page_editor_scripts.js +++ b/static/js/page_editor_scripts.js @@ -419,7 +419,7 @@ const PD=(()=>{try{const el=document.getElementById('page-data');return el?JSON. // ═══════════ Inline AI composer (Notion AI-style) ═══════════ // Space on an empty paragraph → "Edit with AI" pill → Enter → "Brewing…" // → framed result → "Insert below" → applyAIBlocks. - const AIC={_open:false,_idx:-1,_stage:'',_html:'', + const AIC={_open:false,_idx:-1,_stage:'',_html:'',_md:'', ROOT:null, mk(){ if(this.ROOT) return this.ROOT; const d=document.createElement('div'); d.id='_aiC'; d.style.cssText='position:fixed;z-index:1200;width:420px;max-width:92vw;display:none'; @@ -432,7 +432,7 @@ const PD=(()=>{try{const el=document.getElementById('page-data');return el?JSON. this.paint(); this.ROOT.style.display='block'; this._open=true; this._focusIngest(); document.addEventListener('mousedown',function onDoc(ev){ if(!self.ROOT.contains(ev.target)){ self.close(); document.removeEventListener('mousedown',onDoc); } }); }, - close(){ if(this.ROOT)this.ROOT.style.display='none'; this._open=false; this._html=''; if(window.E)window.E.dirty=true; this._stage=''; }, + close(){ if(this.ROOT)this.ROOT.style.display='none'; this._open=false; this._html=''; this._md=''; if(window.E)window.E.dirty=true; this._stage=''; }, _anchorRect(idx){ const E=window.E; if(!E||!E.blocks)return{left:Math.max(24,window.innerWidth/2-210),top:window.innerHeight/2,bottom:window.innerHeight/2,width:420}; const b=E.blocks[idx]; const el=E.getEl(b?b.id:null); if(el){const r=el.getBoundingClientRect();return r;} return {left:24,top:120,bottom:180,width:420}; }, _focusIngest(){ const i=this.ROOT.querySelector('.aici-input'); if(i){i.focus();} }, @@ -478,12 +478,17 @@ const PD=(()=>{try{const el=document.getElementById('page-data');return el?JSON. const E=window.E; const ctx=(typeof window.fdGetPageContext==='function')?String(window.fdGetPageContext()||''):''; if(!(window.fdAgent&&window.fdAgent.generate)){ this._err('Agent IA non configuré'); return; } window.fdAgent.generate(prompt, ctx).then(function(text){ - self._html=self._mdToHtml(text||''); self._stage='result'; self.paint(); + // On conserve le MARKDOWN source : c'est lui qui est inséré (md2b), + // pas le texte extrait du HTML rendu qui perd titres/listes/gras. + self._md=String(text||''); + self._html=self._mdToHtml(self._md); self._stage='result'; self.paint(); }).catch(function(err){ self._err((err&&err.message)?err.message:'Erreur'); }); }, - _err(msg){ this._html='⚠ '+esc(msg)+'
'; this._stage='result'; this.paint(); }, + _err(msg){ this._md=''; this._html='⚠ '+esc(msg)+'
'; this._stage='result'; this.paint(); }, insert(){ const E=window.E; if(!E||typeof E.applyAIBlocks!=='function')return; E.sync(); - const result=this._resultText(); if(!result)return; E.applyAIBlocks(result); E.dirty=true; E.autoSave(); this.close(); }, + // Markdown source d'abord ; repli sur le texte visible (erreurs). + const result=String(this._md||'').trim()||this._resultText(); if(!result)return; + E.applyAIBlocks(result); E.dirty=true; E.autoSave(); this.close(); }, _resultText(){ const el=this.ROOT&&this.ROOT.querySelector('.aici-result'); if(!el)return ''; const r=document.createRange();r.selectNodeContents(el);return r.toString(); }, toast(m){ if(window.showToast)window.showToast(m,'info'); } }; @@ -595,11 +600,19 @@ const PD=(()=>{try{const el=document.getElementById('page-data');return el?JSON. const cls=tag==='div'?`block-content ${b.type==='bulleted_list'?'block-bullet':b.type==='numbered_list'?'block-numbered':b.type==='to_do'?'block-todo':b.type==='toggle'?'block-toggle':b.type==='code'?'block-code':b.type==='callout'?'block-callout':''}`:`block-content block-${tag}`; const style=b.type==='callout'?` style="background:${(b.style&&b.style.bgColor)||'var(--blue-bg)'}${(b.style&&b.style.color)?';color:'+b.style.color:''}"`:((b.style&&(b.style.bgColor||b.style.color))?` style="${(b.style.bgColor?'background:'+b.style.bgColor+';':'')+(b.style.color?'color:'+b.style.color+';':'')}"`:''); const bidAttr=b.type.startsWith('heading_')?` id="h-${(b.id||'').replace(/[^a-zA-Z0-9]/g,'')}"`:''; + // Numéro d'ordre : rang des blocs `numbered_list` contigus (1,2,3…) ; + // passé en attribut data-num → le CSS le rend hors du contenu éditable. + let numAttr=''; + if(b.type==='numbered_list'&&idx>=0){ + const bs=(window.E&&window.E.blocks)||[]; + let s=idx; while(s>0&&bs[s-1]&&bs[s-1].type==='numbered_list')s--; + numAttr=` data-num="${idx-s+1}"`; + } const actions=idx>=0?``:''; return `