Le sélecteur de champ apparaît maintenant sur tout nouveau widget d'un élément de jeu lié à un objet
Le tour précédent exigeait que CHAQUE widget règle sa propre "Donnée
liée" (_data_definition_id) pour voir apparaître le sélecteur de champ -
mais un élément de jeu ("Mail card"...) créé avec un "Objet lié" (voir
element_types.html, bound_definition_id) a précisément pour but d'éviter
ce réglage widget par widget : ses {{champ}} sont censés venir de CET
objet, fourni plus tard par le Répéteur qui l'utilisera comme modèle de
ligne. D'où le bug remonté : un nouveau Titre/Texte posé dans un tel
élément de jeu n'affichait jamais le sélecteur.
Ajoute get_element_type_by_template_screen(slug, screen_id), pour
retrouver depuis l'éditeur d'un écran-modèle l'entrée du catalogue (et
donc l'objet lié) dont il est la recette. screen_edit.py le calcule pour
le panneau de propriétés et le passe à controls_with_values(), qui
l'utilise comme repli pour le champ "Contenu" SEULEMENT si ce widget n'a
pas déjà sa propre "Donnée liée" réglée (priorité conservée au réglage le
plus spécifique).
Ajoute tests/test_element_type_bound_field_picker.py (apparition sans
réglage supplémentaire, absence sans objet lié, priorité à la "Donnée
liée" du widget si réglée).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
7e80ff952a
commit
9c9e3c5379
@@ -0,0 +1,76 @@
|
||||
"""Sélecteur de champ du panneau de propriétés ("+ Ajouter" à côté de
|
||||
"Contenu", voir insertFieldAtCursor() dans screen_edit.html) : doit
|
||||
apparaître dès qu'un objet est disponible dans le contexte, pas seulement
|
||||
quand le widget a lui-même une "Donnée liée" réglée."""
|
||||
import re
|
||||
|
||||
import screens
|
||||
|
||||
|
||||
def _create_email_object(client, slug):
|
||||
resp = client.post(f"/game/{slug}/objects/new", data={
|
||||
"object_name": "Email", "field_name[]": ["sujet"], "field_type[]": ["texte"],
|
||||
"field_relation[]": [""], "field_required[]": ["0"], "field_min[]": [""], "field_max[]": [""],
|
||||
}, follow_redirects=False)
|
||||
return int(resp.headers["Location"].rstrip("/").split("/")[-1])
|
||||
|
||||
|
||||
def test_new_widget_inside_a_bound_element_type_gets_the_field_picker_without_extra_setup(client, game):
|
||||
"""Régression : une "Mail card" (élément de jeu créé avec "Objet lié" =
|
||||
Email) doit proposer le sélecteur de champ sur tout nouveau Titre/Texte
|
||||
posé dans son écran-modèle, sans qu'il faille en plus régler "Lier à un
|
||||
objet de données" sur CE widget précis — l'objet lié à l'élément de jeu
|
||||
suffit."""
|
||||
def_id = _create_email_object(client, game)
|
||||
resp = client.post(f"/game/{game}/element-types", data={
|
||||
"name": "Mail card", "icon": "📧", "bound_definition_id": str(def_id),
|
||||
}, follow_redirects=False)
|
||||
assert resp.status_code == 302
|
||||
et = next(t for t in screens.list_element_types(game) if t["name"] == "Mail card")
|
||||
template_screen_id = et["template_screen_id"]
|
||||
|
||||
resp = client.post(f"/game/{game}/screens/{template_screen_id}/elements/add", data={"widget": "titre"}, follow_redirects=False)
|
||||
element_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1))
|
||||
|
||||
html = client.get(f"/game/{game}/screens/{template_screen_id}/edit?selected={element_id}").data.decode()
|
||||
assert 'id="fieldPicker-content"' in html
|
||||
assert '<option value="sujet">' in html
|
||||
|
||||
|
||||
def test_field_picker_absent_when_element_type_has_no_bound_object(client, game):
|
||||
resp = client.post(f"/game/{game}/element-types", data={"name": "Carte simple", "icon": "🃏"}, follow_redirects=False)
|
||||
assert resp.status_code == 302
|
||||
et = next(t for t in screens.list_element_types(game) if t["name"] == "Carte simple")
|
||||
template_screen_id = et["template_screen_id"]
|
||||
|
||||
resp = client.post(f"/game/{game}/screens/{template_screen_id}/elements/add", data={"widget": "titre"}, follow_redirects=False)
|
||||
element_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1))
|
||||
|
||||
html = client.get(f"/game/{game}/screens/{template_screen_id}/edit?selected={element_id}").data.decode()
|
||||
assert 'id="fieldPicker-content"' not in html
|
||||
|
||||
|
||||
def test_widget_own_data_binding_still_takes_priority_over_element_type_bound_object(client, game):
|
||||
"""Non-régression : si le widget a SA PROPRE "Donnée liée" réglée (sur
|
||||
un objet différent de celui de l'élément de jeu), c'est elle qui doit
|
||||
fournir les champs du sélecteur, pas l'objet lié de l'élément de jeu."""
|
||||
email_id = _create_email_object(client, game)
|
||||
resp = client.post(f"/game/{game}/objects/new", data={
|
||||
"object_name": "Partie", "field_name[]": ["score"], "field_type[]": ["nombre_entier"],
|
||||
"field_relation[]": [""], "field_required[]": ["0"], "field_min[]": [""], "field_max[]": [""],
|
||||
}, follow_redirects=False)
|
||||
partie_id = int(resp.headers["Location"].rstrip("/").split("/")[-1])
|
||||
|
||||
resp = client.post(f"/game/{game}/element-types", data={
|
||||
"name": "Mail card 2", "icon": "📧", "bound_definition_id": str(email_id),
|
||||
}, follow_redirects=False)
|
||||
et = next(t for t in screens.list_element_types(game) if t["name"] == "Mail card 2")
|
||||
template_screen_id = et["template_screen_id"]
|
||||
|
||||
resp = client.post(f"/game/{game}/screens/{template_screen_id}/elements/add", data={"widget": "titre"}, follow_redirects=False)
|
||||
element_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1))
|
||||
client.post(f"/game/{game}/elements/{element_id}/save", data={"ctrl_data_definition_id": str(partie_id)})
|
||||
|
||||
html = client.get(f"/game/{game}/screens/{template_screen_id}/edit?selected={element_id}").data.decode()
|
||||
assert '<option value="score">' in html
|
||||
assert '<option value="sujet">' not in html
|
||||
Reference in New Issue
Block a user