Redesign the screen editor's element tree and add duplication
The "Éléments de cet écran" tree now renders every level of nesting (previously stopped after one level of children) as a compact single-line list, and right-clicking a row opens a context menu to duplicate the element (and its full subtree) in place, in its current container. Also: all property panels start collapsed instead of some being open by default, the redundant nested element list inside "Ajouter DANS ce conteneur" is removed (it only needs the widget picker), and the now-unneeded "a container is selected" warning banner is gone. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
3039489e39
commit
bb79f2f93d
@@ -182,6 +182,70 @@ def test_image_gets_object_fit_cover_by_default(client, game):
|
||||
assert "object-fit:cover" in html
|
||||
|
||||
|
||||
def test_duplicate_top_level_element_creates_independent_copy(client, game):
|
||||
screen_id = _create_screen(client, game)
|
||||
resp = client.post(f"/game/{game}/screens/{screen_id}/elements/add", data={"widget": "titre"})
|
||||
original_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1))
|
||||
client.post(f"/game/{game}/elements/{original_id}/save", data={"ctrl_content": "Bienvenue"})
|
||||
|
||||
resp = client.post(f"/game/{game}/elements/{original_id}/duplicate", follow_redirects=False)
|
||||
assert resp.status_code == 302
|
||||
new_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1))
|
||||
assert new_id != original_id
|
||||
|
||||
html = client.get(f"/game/{game}/screens/{screen_id}/edit").data.decode()
|
||||
assert html.count("Bienvenue") == 2 # original + copie, chacun un élément séparé
|
||||
|
||||
# Modifier la copie ne doit pas toucher l'original (deux lignes indépendantes).
|
||||
client.post(f"/game/{game}/elements/{new_id}/save", data={"ctrl_content": "Copie modifiée"})
|
||||
html = client.get(f"/game/{game}/screens/{screen_id}/edit").data.decode()
|
||||
assert "Bienvenue" in html
|
||||
assert "Copie modifiée" in html
|
||||
|
||||
|
||||
def test_duplicate_container_deep_copies_children(client, game):
|
||||
"""Régression : dupliquer un conteneur doit copier tout son sous-arbre
|
||||
(pas juste la boîte vide) — voir screens/elements/duplicate_element.py,
|
||||
qui réutilise le même parcours récursif que la copie d'écran-modèle."""
|
||||
screen_id = _create_screen(client, game)
|
||||
resp = client.post(f"/game/{game}/screens/{screen_id}/elements/add", data={"widget": "conteneur"})
|
||||
container_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1))
|
||||
resp = client.post(f"/game/{game}/elements/{container_id}/children/add", data={"widget": "titre"})
|
||||
child_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1))
|
||||
client.post(f"/game/{game}/elements/{child_id}/save", data={"ctrl_content": "Titre enfant"})
|
||||
|
||||
resp = client.post(f"/game/{game}/elements/{container_id}/duplicate", follow_redirects=False)
|
||||
new_container_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1))
|
||||
assert new_container_id != container_id
|
||||
|
||||
html = client.get(f"/game/{game}/screens/{screen_id}/edit").data.decode()
|
||||
assert html.count("Titre enfant") == 2 # l'enfant a bien été copié avec son parent
|
||||
|
||||
|
||||
def test_duplicate_child_element_stays_in_same_container(client, game):
|
||||
screen_id = _create_screen(client, game)
|
||||
resp = client.post(f"/game/{game}/screens/{screen_id}/elements/add", data={"widget": "conteneur"})
|
||||
container_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1))
|
||||
resp = client.post(f"/game/{game}/elements/{container_id}/children/add", data={"widget": "texte"})
|
||||
child_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1))
|
||||
|
||||
client.post(f"/game/{game}/elements/{child_id}/duplicate")
|
||||
html = client.get(f"/game/{game}/screens/{screen_id}/edit").data.decode()
|
||||
assert html.count("↳") == 0 # l'ancienne arborescence imbriquée dans "Ajouter DANS ce conteneur" a disparu
|
||||
tree_html = html[html.find('class="elementTree"'):]
|
||||
assert tree_html.count("treeChildren") >= 1 # le conteneur a bien 2 enfants imbriqués (le nouveau + l'original)
|
||||
|
||||
|
||||
def test_screen_editor_property_panels_closed_by_default(client, game):
|
||||
screen_id = _create_screen(client, game)
|
||||
resp = client.post(f"/game/{game}/screens/{screen_id}/elements/add", data={"widget": "conteneur"})
|
||||
container_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1))
|
||||
|
||||
html = client.get(f"/game/{game}/screens/{screen_id}/edit?selected={container_id}").data.decode()
|
||||
assert "<details class=\"propGroup\" open>" not in html
|
||||
assert "Un conteneur est sélectionné" not in html
|
||||
|
||||
|
||||
def test_delete_element_type_removes_hidden_template_screen(client, game):
|
||||
resp = client.post(f"/game/{game}/element-types", data={"name": "ToDelete", "icon": "🧩"}, follow_redirects=False)
|
||||
html = client.get(f"/game/{game}/element-types").data.decode()
|
||||
|
||||
Reference in New Issue
Block a user