diff --git a/src/pages/tableau.py b/src/pages/tableau.py index 56bdf00..74b0b5d 100644 --- a/src/pages/tableau.py +++ b/src/pages/tableau.py @@ -25,6 +25,7 @@ from src.utils import get_data_update_timestamp, logger from src.utils.seo import META_CONTENT from src.utils.table import ( COLUMNS, + build_view_query, filter_table_data, get_default_hidden_columns, invert_columns, @@ -425,19 +426,7 @@ def sync_url_and_reset_button(filter_query, sort_by, hidden_columns, href): # Extract base URL (remove existing query params) base_url = href.split("?")[0] - params = {} - if filter_query: - params["filtres"] = filter_query - - if sort_by: - params["tris"] = json.dumps(sort_by) - - if hidden_columns: - table_columns = invert_columns(hidden_columns) - table_columns = ",".join(table_columns) - params["colonnes"] = table_columns - - query_string = urllib.parse.urlencode(params) + query_string = build_view_query(filter_query, sort_by, hidden_columns) full_url = f"{base_url}?{query_string}" if query_string else base_url copy_button = dcc.Clipboard( diff --git a/src/utils/table.py b/src/utils/table.py index 1a96289..0298012 100644 --- a/src/utils/table.py +++ b/src/utils/table.py @@ -1,4 +1,6 @@ +import json import os +import urllib.parse import uuid import polars as pl @@ -557,6 +559,23 @@ def invert_columns(columns): return inverted_columns +def build_view_query(filter_query, sort_by, hidden_columns) -> str: + """ + Construit la query string d'une vue Tableau (filtres + tris + colonnes), + identique à celle produite par le bouton « Partager la vue ». + + hidden_columns : colonnes masquées ; on stocke les colonnes visibles. + """ + params = {} + if filter_query: + params["filtres"] = filter_query + if sort_by: + params["tris"] = json.dumps(sort_by) + if hidden_columns: + params["colonnes"] = ",".join(invert_columns(hidden_columns)) + return urllib.parse.urlencode(params) + + COLUMNS = schema.names() _EXCEL_MIN_COLUMN_WIDTH = 132 # ≈ 3.5 cm à 96 DPI diff --git a/tests/saved_views/test_build_view_query.py b/tests/saved_views/test_build_view_query.py new file mode 100644 index 0000000..78f59e5 --- /dev/null +++ b/tests/saved_views/test_build_view_query.py @@ -0,0 +1,34 @@ +import urllib.parse + +from src.utils.table import build_view_query + + +def test_empty_inputs_give_empty_string(): + assert build_view_query(None, None, None) == "" + assert build_view_query("", [], []) == "" + + +def test_filter_only(): + q = build_view_query("{objet} icontains route", None, None) + params = urllib.parse.parse_qs(q) + assert params["filtres"] == ["{objet} icontains route"] + assert "tris" not in params + assert "colonnes" not in params + + +def test_sort_is_json_encoded(): + sort_by = [{"column_id": "montant", "direction": "desc"}] + q = build_view_query(None, sort_by, None) + params = urllib.parse.parse_qs(q) + import json + + assert json.loads(params["tris"][0]) == sort_by + + +def test_hidden_columns_become_visible_csv(): + # build_view_query reçoit les colonnes MASQUÉES et stocke les VISIBLES + q = build_view_query(None, None, ["objet"]) + params = urllib.parse.parse_qs(q) + visible = params["colonnes"][0].split(",") + assert "objet" not in visible + assert len(visible) > 0