feat: menu + — Design System – Canevas — phase 3/8 (v7.53.0)
- 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:
+1
-1
@@ -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,
|
||||
|
||||
@@ -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 ──
|
||||
|
||||
@@ -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."),
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user