Corrige la condition de visibilité (mode "objet") à l'intérieur d'un Répéteur
Bug remonté : dans une "Mail card" (élément de jeu réutilisable, deux
icônes - enveloppe fermée/ouverte - conditionnées sur le champ is_opened
de l'objet Email) posée dans un Répéteur de données, rien ne s'affichait
jamais correctement.
Cause : is_element_visible() (mode "objet") allait toujours chercher en
base la ligne la plus récente de l'objet ciblé (convention "1 seule ligne
= état de partie", correcte pour une Jauge suivant un état de partie),
sans jamais tenir compte de la ligne EN COURS DE RENDU dans un Répéteur -
donc tous les exemplaires du même modèle de ligne évaluaient la MÊME
ligne (la plus récente de tout l'objet Email) au lieu de chacun la
sienne, et affichaient donc tous exactement le même résultat.
Fix : is_element_visible() reçoit maintenant le ctx de rendu (les
{{champ}} de la ligne en cours, déjà posés par render_repeater.py) et,
si le champ réglé s'y trouve, utilise directement cette valeur plutôt que
d'interroger la base - un exemplaire de Répéteur voit donc bien SA propre
ligne. Hors Répéteur, le comportement (ligne la plus récente de l'objet)
est inchangé.
Ajoute tests/test_visibility_condition.py (mode variable, mode objet hors
Répéteur, absence dans l'éditeur, et ce cas précis dans un Répéteur) -
cette fonctionnalité n'avait jusqu'ici aucun test persistant, seulement
des scripts ad-hoc jetés après vérification.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
11b08c8503
commit
ff01b3903c
@@ -47,7 +47,7 @@ def render_element_html(el, slug=None, children_map=None, ctx=None, parent_flex_
|
||||
# ce cas d'office.
|
||||
has_visibility_condition = attrs_raw.get("_visibilite_cond_mode") in ("variable", "objet")
|
||||
play_mode = bool((ctx or {}).get("_forge_play_mode"))
|
||||
if play_mode and has_visibility_condition and not is_element_visible(slug, attrs_raw):
|
||||
if play_mode and has_visibility_condition and not is_element_visible(slug, attrs_raw, ctx):
|
||||
return f'<div class="visibilityGated" data-element-id="{el["id"]}" style="display:none;"></div>'
|
||||
|
||||
def _mark(html_str):
|
||||
|
||||
@@ -3,17 +3,29 @@ import db
|
||||
from .filter_repeater_rows import _resolve_filter_value, _compare, _field_column
|
||||
|
||||
|
||||
def is_element_visible(slug, attrs):
|
||||
def is_element_visible(slug, attrs, ctx=None):
|
||||
"""Condition de visibilité (panneau de propriétés, tout widget — voir
|
||||
VISIBILITY_CONDITION_CONTROLS) : masque un élément selon soit une
|
||||
VARIABLE GLOBALE (une seule valeur pour tout le jeu, voir
|
||||
db/global_vars/), soit le champ d'un objet de données (convention "1
|
||||
seule ligne = état de partie", déjà utilisée par la Jauge/Donnée liée).
|
||||
Absente de réglage (_visibilite_cond_mode vide) => toujours visible,
|
||||
comportement inchangé pour tous les éléments déjà créés. Réutilise
|
||||
db/global_vars/), soit le champ d'un objet de données. Absente de
|
||||
réglage (_visibilite_cond_mode vide) => toujours visible, comportement
|
||||
inchangé pour tous les éléments déjà créés. Réutilise
|
||||
_compare/_resolve_filter_value/_field_column de filter_repeater_rows.py
|
||||
pour rester cohérent avec les mêmes opérateurs et la même syntaxe
|
||||
"{{Objet.champ}}" pour une valeur de comparaison dynamique."""
|
||||
"{{Objet.champ}}" pour une valeur de comparaison dynamique.
|
||||
|
||||
`ctx` porte les {{champ}} de la ligne en cours (voir render_repeater.py)
|
||||
quand cet élément est descendant d'un Répéteur de données — en mode
|
||||
"objet", si le champ réglé s'y trouve déjà, sa valeur est utilisée telle
|
||||
quelle plutôt que d'aller chercher la ligne la plus récente de l'objet
|
||||
en base : sans ça, TOUS les exemplaires d'un même modèle de ligne (ex.
|
||||
une "Mail card" répétée pour chaque e-mail) évalueraient la même ligne
|
||||
(la plus récente de l'objet) au lieu de chacun la sienne, et
|
||||
n'afficheraient donc jamais rien de cohérent. Hors Répéteur (mode
|
||||
"objet" sur un élément posé directement sur l'écran), le champ n'est
|
||||
pas dans ctx et on retombe sur la convention "1 seule ligne = état de
|
||||
partie" (déjà utilisée par la Jauge/Donnée liée) : la ligne la plus
|
||||
récente de l'objet choisi."""
|
||||
mode = attrs.get("_visibilite_cond_mode")
|
||||
if mode not in ("variable", "objet"):
|
||||
return True
|
||||
@@ -36,9 +48,13 @@ def is_element_visible(slug, attrs):
|
||||
definition = db.get_definition(slug, int(definition_id))
|
||||
if not definition:
|
||||
return True
|
||||
field_type = next((f["type"] for f in definition["fields"] if f["name"] == field_name), "texte")
|
||||
|
||||
if ctx and field_name in ctx:
|
||||
return _compare(ctx.get(field_name), operator, expected, field_type)
|
||||
|
||||
rows = db.list_rows(slug, definition)
|
||||
if not rows:
|
||||
return True # objet sans donnée pour l'instant : ne bloque pas
|
||||
row = rows[0] # convention "état de partie" : une seule ligne, voir data_definition_options.py
|
||||
field_type = next((f["type"] for f in definition["fields"] if f["name"] == field_name), "texte")
|
||||
return _compare(row.get(_field_column(definition, field_name)), operator, expected, field_type)
|
||||
|
||||
Reference in New Issue
Block a user