"""FlowDeck — Projection Form builder -> pipeline public /f/ (§16.5). Le builder ecrit ``form_questions`` + reglages de la vue form ; le projecteur regenere ``collections.form_config_json`` (format v6.8 inchange) consomme par GET/POST /f/. Le public ne lit jamais les tables du builder : zero regression possible sur les liens deja diffuses. """ from __future__ import annotations import json def project_form_config(view_config: dict, questions: list[dict]) -> dict: """Construit le ``form_config_json`` v6.8 depuis le builder.""" cfg = dict(view_config or {}) sharing = cfg.get("sharing") or {} submit = cfg.get("submit_screen") or {} fields = [] for q in sorted(questions, key=lambda x: x.get("position", 0)): fields.append({ "property": q.get("property_name"), "label": q.get("label_override") or q.get("property_name"), "required": bool(q.get("required")), "help": q.get("help_text") or "", "widget": q.get("widget") or "auto", "max_selections": q.get("max_selections"), "conditional": json.loads(q["conditional_json"]) if q.get("conditional_json") else None, }) return { "title": cfg.get("title") or "Form", "description": cfg.get("description") or "", "fields": fields, "sharing": { "audience": sharing.get("audience", "workspace"), "anonymous": bool(sharing.get("anonymous", False)), "respondent_access": sharing.get("respondent_access", "none"), "branding": sharing.get("branding", True), }, "submit": { "button_text": submit.get("button_text", "Envoyer"), "button_color": submit.get("button_color", "blue"), "confirmation_title": submit.get("confirmation_title", "Merci !"), "confirmation_body": submit.get("confirmation_body", "Votre réponse a été enregistrée."), }, "form_view_id": cfg.get("form_view_id"), } def default_questions_for(properties: list[dict]) -> list[dict]: """Questions initiales depuis les proprietes exposables (hors formules).""" skip = {"formula", "rollup", "button", "unique_id", "created_time", "created_by", "last_edited_time", "last_edited_by"} out = [] for i, p in enumerate(properties): if p.get("prop_type") in skip: continue out.append({ "property_name": p.get("name"), "position": i, "label_override": None, "sync_label": 1, "help_text": "", "required": 0, "widget": "auto", "max_selections": None, "conditional_json": None, }) return out