diff --git a/src/pages/observatoire.py b/src/pages/observatoire.py index d48518c..67ab659 100644 --- a/src/pages/observatoire.py +++ b/src/pages/observatoire.py @@ -1,9 +1,21 @@ +import urllib.parse from datetime import datetime, timedelta import dash_bootstrap_components as dbc import polars as pl import polars.selectors as cs -from dash import ALL, Input, Output, State, callback, ctx, dcc, html, register_page +from dash import ( + ALL, + Input, + Output, + State, + callback, + ctx, + dcc, + html, + no_update, + register_page, +) from src.figures import ( get_barchart_sources, @@ -107,7 +119,7 @@ def _apply_filters( layout = [ dcc.Store(id="dashboard-filters"), - dcc.Location(id="dashboard_url"), + dcc.Location(id="dashboard_url", refresh="callback-nav"), dbc.Modal( [ dbc.ModalHeader(dbc.ModalTitle("Montants")), @@ -280,6 +292,24 @@ Alors, on fait comment ? ] +@callback( + Output("dashboard_acheteur_id", "value"), + Output("dashboard_titulaire_id", "value"), + Output("dashboard_url", "search"), + Input("dashboard_url", "search"), +) +def restore_filters_from_url(search): + if not search: + return no_update, no_update, no_update + + params = urllib.parse.parse_qs(search.lstrip("?")) + + acheteur_id = params.get("acheteur_id", [None])[0] or no_update + titulaire_id = params.get("titulaire_id", [None])[0] or no_update + + return acheteur_id, titulaire_id, "" + + @callback( Output("cards", "children"), Output("btn-download-observatoire", "disabled"), diff --git a/tests/conftest.py b/tests/conftest.py index b14e0f8..f0f2b00 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -34,6 +34,11 @@ def test_data(): "sourceFile": "test.xml", "sourceDataset": "test_dataset", "datePublicationDonnees": datetime.date(2025, 1, 1), + "considerationsSociales": "", + "considerationsEnvironnementales": "", + "type": "Marché", + "acheteur_categorie": "Collectivité", + "titulaire_categorie": "PME", } ] path = "tests/test.parquet" diff --git a/tests/test_main.py b/tests/test_main.py index e3f77bb..995a669 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -137,3 +137,23 @@ def test_005_add_links_observatoire_titulaire(): # titulaire_id should NOT contain observatoire link assert "/observatoire" not in id_value + + +def test_006_observatoire_url_to_input(dash_duo: DashComposite): + from src.app import app + + dash_duo.start_server(app) + dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4) + + # Navigate to observatoire with acheteur_id query param + dash_duo.wait_for_page(f"{dash_duo.server_url}/observatoire?acheteur_id=a1") + dash_duo.wait_for_element("#dashboard_acheteur_id", timeout=4) + + import time + + time.sleep(1) # Allow callback chain to complete + + acheteur_input = dash_duo.find_element("#dashboard_acheteur_id") + assert acheteur_input.get_attribute("value") == "a1", ( + "acheteur_id input should be populated from URL param" + )