Retour de l'utilisateur sur le premier jet : "Déclencher un événement" ne doit JAMAIS faire choisir un élément — c'est une notification pure, rien de plus. C'est à l'ÉCOUTEUR (déclencheur "Sur un événement personnalisé" → condition → action) de décider quoi faire ensuite, avec ses réglages habituels (cible fixe, "Ligne cliquée"...), jamais à l'événement de transporter un paramètre. Retire donc tout le mécanisme de transmission ajouté au tour précédent (has_element_param, target_element_from_event, EVENT_ROW_ID, window.lastEventParams) : - db/custom_events/ : _custom_events perd sa colonne has_element_param — un événement n'est plus qu'un nom + une description. - screens/flow/ : retire target_element_from_event (colonne ajoutée par ALTER TABLE, laissée inerte sur les bases déjà migrées — sans conséquence, plus jamais lue ni écrite) et la constante EVENT_ROW_ID. - routes/flow/flow_node_run_data.py : retire la résolution EVENT_ROW_ID, revient à sa forme d'origine (seul CLICKED_ROW_ID reste géré). - templates/screen_edit.html : le nœud Action "Déclencher un événement" n'a plus qu'un sélecteur d'événement — plus de champs élément/ligne. Le nœud Action "Modifier un élément" perd la case "Utiliser l'élément transmis par l'événement en cours". L'onglet Événements perd la case à cocher "Paramètre" (création et édition). - templates/play.html : window.dispatchGameEvent(eventId) ne prend plus que l'id de l'événement — scan global inchangé, mais ne pose plus aucun window.lastEventParams. modifier_element et readFieldValue reviennent à leur résolution d'origine (plus de branche event-aware). 208 tests au total (2 tests retirés, devenus sans objet : la persistance de target_element_from_event et la résolution serveur d'EVENT_ROW_ID). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
88 lines
4.5 KiB
Python
88 lines
4.5 KiB
Python
import db
|
|
|
|
|
|
def ensure_flow_schema(slug):
|
|
conn = db.connect(slug)
|
|
conn.executescript(
|
|
"""
|
|
CREATE TABLE IF NOT EXISTS _flow_nodes (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
screen_id INTEGER NOT NULL REFERENCES _screens(id) ON DELETE CASCADE,
|
|
node_type TEXT NOT NULL,
|
|
x REAL NOT NULL DEFAULT 40,
|
|
y REAL NOT NULL DEFAULT 40,
|
|
trigger_element_id INTEGER REFERENCES _screen_elements(id),
|
|
trigger_event TEXT,
|
|
cond_definition_id INTEGER,
|
|
cond_row_id INTEGER,
|
|
cond_field TEXT,
|
|
cond_field_type TEXT,
|
|
cond_operator TEXT,
|
|
cond_value TEXT,
|
|
action_type TEXT,
|
|
target_screen_id INTEGER REFERENCES _screens(id),
|
|
target_element_id INTEGER REFERENCES _screen_elements(id),
|
|
element_property TEXT,
|
|
element_value TEXT,
|
|
target_definition_id INTEGER,
|
|
target_row_id INTEGER,
|
|
target_field TEXT,
|
|
data_operation TEXT,
|
|
data_value TEXT
|
|
);
|
|
CREATE TABLE IF NOT EXISTS _flow_edges (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
screen_id INTEGER NOT NULL REFERENCES _screens(id) ON DELETE CASCADE,
|
|
from_node_id INTEGER NOT NULL REFERENCES _flow_nodes(id) ON DELETE CASCADE,
|
|
from_port TEXT NOT NULL DEFAULT 'out',
|
|
to_node_id INTEGER NOT NULL REFERENCES _flow_nodes(id) ON DELETE CASCADE
|
|
);
|
|
"""
|
|
)
|
|
# 2.4 — conditions combinées (ET/OU) : un nœud Condition peut tester
|
|
# PLUSIEURS champs à la fois plutôt qu'un seul. cond_clauses (JSON, une
|
|
# liste de clauses en plus de la clause "historique" cond_definition_id/
|
|
# cond_field/etc.) + cond_combinator ('et'/'ou') sont ajoutés en ALTER
|
|
# TABLE pour ne rien casser sur les jeux déjà créés — un nœud sans
|
|
# cond_clauses garde exactement son comportement d'avant (une seule
|
|
# comparaison), voir evaluateConditionNode() dans templates/play.html.
|
|
cols = {r["name"] for r in conn.execute("PRAGMA table_info(_flow_nodes)").fetchall()}
|
|
if "cond_clauses" not in cols:
|
|
conn.execute("ALTER TABLE _flow_nodes ADD COLUMN cond_clauses TEXT")
|
|
if "cond_combinator" not in cols:
|
|
conn.execute("ALTER TABLE _flow_nodes ADD COLUMN cond_combinator TEXT NOT NULL DEFAULT 'et'")
|
|
if "target_variable" not in cols:
|
|
# Action "Modifier une variable" (voir apply_variable_action.py) —
|
|
# cible une variable globale par NOM plutôt qu'un champ d'objet ;
|
|
# réutilise data_operation/data_value, déjà là pour "modifier_donnee".
|
|
conn.execute("ALTER TABLE _flow_nodes ADD COLUMN target_variable TEXT")
|
|
if "cond_source" not in cols:
|
|
# Un nœud Condition peut désormais tester soit un champ d'objet
|
|
# (comportement historique, cond_source absent ou "objet"), soit
|
|
# une VARIABLE GLOBALE (cond_source="variable" — cond_variable :
|
|
# son nom ; cond_variable_chemin : chemin optionnel ".champ"/
|
|
# "[index]" si elle est de type objet/tableau, même syntaxe que
|
|
# "Chemin dans la variable" de la Condition de visibilité — voir
|
|
# visibility_condition_controls.py). Chaque clause de cond_clauses
|
|
# (JSON) porte les mêmes 3 clés en plus des siennes. Évalué côté
|
|
# CLIENT (templates/play.html, evaluateConditionClause) contre
|
|
# gameData.variables, exposé par full_game_payload.py.
|
|
conn.execute("ALTER TABLE _flow_nodes ADD COLUMN cond_source TEXT")
|
|
if "cond_variable" not in cols:
|
|
conn.execute("ALTER TABLE _flow_nodes ADD COLUMN cond_variable TEXT")
|
|
if "cond_variable_chemin" not in cols:
|
|
conn.execute("ALTER TABLE _flow_nodes ADD COLUMN cond_variable_chemin TEXT")
|
|
if "trigger_custom_event_id" not in cols:
|
|
# Événements personnalisés (voir screens/custom_events/) : quel
|
|
# événement un nœud Déclencheur écoute (trigger_event="evenement")
|
|
# ou un nœud Action déclenche (action_type="declencher_evenement").
|
|
# Pas de FK vers _custom_events : une suppression d'événement
|
|
# nettoie déjà ces colonnes elle-même (voir
|
|
# screens/custom_events/delete_custom_event.py), une contrainte
|
|
# ferait double emploi sans rien apporter de plus.
|
|
conn.execute("ALTER TABLE _flow_nodes ADD COLUMN trigger_custom_event_id INTEGER")
|
|
if "target_custom_event_id" not in cols:
|
|
conn.execute("ALTER TABLE _flow_nodes ADD COLUMN target_custom_event_id INTEGER")
|
|
conn.commit()
|
|
conn.close()
|