diff --git a/screens/rendering/filter_repeater_rows.py b/screens/rendering/filter_repeater_rows.py index f3dfbaaf..2b7e0cd2 100644 --- a/screens/rendering/filter_repeater_rows.py +++ b/screens/rendering/filter_repeater_rows.py @@ -76,19 +76,30 @@ def _compare(actual, operator, expected, field_type): return False -def filter_repeater_rows(slug, definition, rows, attrs): - """Ne garde, parmi les lignes d'un Répéteur, que celles qui correspondent - au filtre optionnel réglé dans ses propriétés (_filtre_champ / - _filtre_operateur / _filtre_valeur) — voir 1.2 dans la doc de cadrage - Forge Engine ("affichage piloté par la donnée sur un écran unique") : - c'est ce qui permet à un seul écran de n'afficher, par exemple, que les - mails du niveau en cours plutôt que la boîte de réception entière.""" - field_name = (attrs.get("_filtre_champ") or "").strip() - operator = attrs.get("_filtre_operateur") or "egal" +def _apply_one_filter(slug, definition, rows, field_name, operator, raw_value): if not field_name: return rows - raw_value = attrs.get("_filtre_valeur") or "" - expected = _resolve_filter_value(slug, raw_value) + expected = _resolve_filter_value(slug, raw_value or "") field_type = next((f["type"] for f in definition["fields"] if f["name"] == field_name), "texte") col = db.slugify(field_name).replace("-", "_") return [r for r in rows if _compare(r.get(col), operator, expected, field_type)] + + +def filter_repeater_rows(slug, definition, rows, attrs): + """Ne garde, parmi les lignes d'un Répéteur, que celles qui correspondent + au(x) filtre(s) optionnel(s) réglé(s) dans ses propriétés (_filtre_champ/ + _filtre_operateur/_filtre_valeur, ET, si renseigné, _filtre2_champ/ + _filtre2_operateur/_filtre2_valeur combiné en ET avec le premier) — voir + 1.2 dans la doc de cadrage Forge Engine ("affichage piloté par la donnée + sur un écran unique") : c'est ce qui permet à un seul écran de n'afficher, + par exemple, que le niveau du parcours en cours (2 conditions : le bon + parcours ET le bon numéro de niveau) plutôt que tous les niveaux.""" + rows = _apply_one_filter( + slug, definition, rows, + (attrs.get("_filtre_champ") or "").strip(), attrs.get("_filtre_operateur") or "egal", attrs.get("_filtre_valeur"), + ) + rows = _apply_one_filter( + slug, definition, rows, + (attrs.get("_filtre2_champ") or "").strip(), attrs.get("_filtre2_operateur") or "egal", attrs.get("_filtre2_valeur"), + ) + return rows diff --git a/screens/widgets/registry.py b/screens/widgets/registry.py index 23fd4756..0184bd59 100644 --- a/screens/widgets/registry.py +++ b/screens/widgets/registry.py @@ -222,6 +222,11 @@ WIDGETS = { c_select("filtre_operateur", "...est", "attr:_filtre_operateur", CONDITION_OPERATORS, default="egal", group="Filtre"), c_text("filtre_valeur", "...cette valeur, ou {{NomObjet.champ}} pour comparer à une donnée qui change en cours de partie", "attr:_filtre_valeur", placeholder="ex. 3 ou {{Partie.niveau_courant}}", default="", group="Filtre"), + c_text("filtre2_champ", "ET (optionnel) : ce 2ᵉ champ", + "attr:_filtre2_champ", placeholder="ex. parcour_id", default="", group="Filtre"), + c_select("filtre2_operateur", "...est", "attr:_filtre2_operateur", CONDITION_OPERATORS, default="egal", group="Filtre"), + c_text("filtre2_valeur", "...cette valeur, ou {{NomObjet.champ}}", + "attr:_filtre2_valeur", placeholder="ex. 1 ou {{Partie.parcours_courant}}", default="", group="Filtre"), ], }, "jauge": {