feat: menu + — Design System – Canevas — phase 3/8 (v7.53.0)
FlowDeck CI / lint (push) Successful in 2m12s
FlowDeck CI / test (push) Failing after 14m56s
FlowDeck CI / docker (push) Skipped

- Section « Design System – Canevas » : liste des canevas (intégrés +
  personnels, GET /board/api/page-templates) puis page de détail avec
  « Créer une page à partir du canevas », « Insérer dans le document ouvert »
  (désactivé sans document ouvert) et « Enregistrer le document ouvert comme
  canevas ».
- GET /board/api/page-templates/{id}/blocks (nouvelle route) : blocs d'un
  canevas — intégré via template_id=0&key=, sinon id ; 404 clé/id inconnu.
  Insertion côté front via ensureBlockIds() global + concat dans E.blocks
  + autoSave/render.
- Canevas « Design System » ajouté aux builtins (callout tokens, TOC, toggles
  composants, grille, checklist revue UI, citation).
- Fix : le front du panneau appelait /api/page-templates (404 silencieux) —
  le router est sous prefix=/board → /board/api/page-templates.
- Piège : pour /use la clé builtin se passe DANS LE BODY (body.key), pas en
  query string — test garde-fou ajouté.
- Tests : tests/test_v753_canvases.py (5) + test_v751 adapté. Suite complète
  1285 verts (-n auto), ruff 0, eslint 0 problème. OpenAPI 516 chemins.
This commit is contained in:
2026-10-06 21:59:34 -04:00
parent 18a2d45d46
commit a68e8848ea
11 changed files with 380 additions and 23 deletions
+1 -1
View File
@@ -185,7 +185,7 @@ async def lifespan(_app: FastAPI):
app = FastAPI(
title="FlowDeck",
version="7.52.0",
version="7.53.0",
docs_url="/docs",
redoc_url="/redoc",
lifespan=lifespan,
+34
View File
@@ -226,4 +226,38 @@ def use_page_template(request: Request, template_id: int, body: dict = Body(defa
return {"status": "ok", "id": page_id, "title": title or name}
@router.get("/api/page-templates/{template_id}/blocks")
def page_template_blocks(request: Request, template_id: int, key: str = ""):
"""v7.53.0 : blocs d'un canevas, pour l'insérer dans le document ouvert.
Builtin : ``template_id=0`` + ``?key=`` (même convention que ``/use``).
Canevas personnel : son ``id``. Les blocs builtin sont sans ``id`` — le
front appelle ``ensureBlockIds()`` (déjà global côté éditeur).
"""
user = SessionManager.decode_session(request.cookies.get("flowdeck_session", ""))
if template_id == 0:
from app.services.block_templates import blocks_json_for
raw = blocks_json_for(key or "empty")
if raw is None:
raise HTTPException(404, "Unknown built-in template")
else:
uid = (user or {}).get("id")
with get_conn() as conn:
row = conn.execute(
"SELECT blocks_json FROM page_global_templates "
"WHERE id=? AND (created_by IS NULL OR created_by=?)",
(template_id, uid),
).fetchone()
if not row:
raise HTTPException(404, "Template not found")
raw = row["blocks_json"]
try:
blocks = json.loads(raw)
except (json.JSONDecodeError, TypeError) as exc:
raise HTTPException(500, "Template content corrupted") from exc
if not isinstance(blocks, list):
raise HTTPException(500, "Template content corrupted")
return {"blocks": blocks}
# ── Core helpers ──
+28
View File
@@ -86,6 +86,34 @@ BUILTIN_TEMPLATES: dict[str, dict] = {
_b("bulleted_list"),
],
},
"design_system": {
"name": "Design System",
"icon": "🎨",
"description": "Tokens, composants et grille — canevas de référence UI.",
"blocks": [
_b("heading_1", "Design System"),
_b("callout",
"Tokens : couleur, espacement, typographie, rayon, ombres "
"(static/css/design-tokens.css).",
icon="🎨"),
_b("table_of_contents"),
_b("heading_2", "Composants"),
_b("toggle", "Boutons & actions", expanded=False,
children=[_b("paragraph", "Primaire · secondaire · danger — états idle, hover, focus, disabled.")]),
_b("toggle", "Cartes & panneaux", expanded=False,
children=[_b("paragraph", "Élévation, rayon, bordure, padding, zones de clic.")]),
_b("toggle", "Formulaires", expanded=False,
children=[_b("paragraph", "Champs, labels, hints, erreurs, focus visible.")]),
_b("heading_2", "Grille & espacement"),
_b("bulleted_list", "Base 4 px — pas d'espacement hors échelle."),
_b("bulleted_list", "Colonnes : 12 / 8 / 4 selon le point de rupture."),
_b("heading_2", "Revue UI"),
_b("to_do", "Contraste AA vérifié", checked=False),
_b("to_do", "États hover / focus / disabled", checked=False),
_b("to_do", "Responsive mobile", checked=False),
_b("quote", "Une décision de design vaut mieux qu'une justification après coup."),
],
},
}