diff --git a/lidar_pipeline/index.py b/lidar_pipeline/index.py index a1ec763..e462e36 100644 --- a/lidar_pipeline/index.py +++ b/lidar_pipeline/index.py @@ -3263,6 +3263,10 @@ function finishRunningTasks(d) { // l' se recharge et le nouveau rendu remplace l'ancien à l'écran — // cache navigateur compris. let liveTilesStamp = null; +// Le panneau est figé au chargement (VIZ_META initial) : le flux /api/tiles +// fusionne l'index du worker, qui peut encore proposer des couches retirées +// (index obsolète) — on n'ajoute au menu que des clés déjà connues. +const PANEL_KEYS = new Set(Object.keys(VIZ_META)); function mergeTilesData(data) { if (!data || !Array.isArray(data.tiles)) return; const byKey = new Map(); @@ -3296,7 +3300,7 @@ function mergeTilesData(data) { let metaChanged = false; if (data.viz_meta) { for (const k of Object.keys(data.viz_meta)) { - if (VIZ_META[k]) continue; + if (!PANEL_KEYS.has(k) || VIZ_META[k]) continue; VIZ_META[k] = data.viz_meta[k]; if (!state.layers.order.includes(k)) { state.layers.order.push(k); diff --git a/lidar_pipeline/tests/test_webapp.py b/lidar_pipeline/tests/test_webapp.py index 14532d8..4995cde 100644 --- a/lidar_pipeline/tests/test_webapp.py +++ b/lidar_pipeline/tests/test_webapp.py @@ -339,7 +339,12 @@ def test_tiles_endpoint_stamp_diffing(tmp_path, monkeypatch): def test_tiles_endpoint_merges_remote_index(tmp_path, monkeypatch): - """L'index du worker prime ; le cache local complète les positions perdues.""" + """L'index du worker prime ; le cache local complète les positions perdues. + + viz_meta est filtré aux couches du panneau (PANEL_VIZ) : une couche + retirée (absente de PANEL_VIZ) proposée par un index obsolète n'est + pas réintroduite. + """ import json import lidar_pipeline.webapp as webapp monkeypatch.setattr(webapp, "OUTPUT_DIR", tmp_path) @@ -349,7 +354,10 @@ def test_tiles_endpoint_merges_remote_index(tmp_path, monkeypatch): {"col": 1054, "row": 6882, "resolution": 0.2, "viz": {}}, # commun {"col": 1050, "row": 6882, "resolution": 0.2, "viz": {}}, # local seul ], - "viz_meta": {"local": {"label": "Locale"}}, + "viz_meta": { + "aspect": {"label": "Aspect local"}, + "slope": {"label": "Pente locale"}, + }, "stats": {}, }), encoding="utf-8") import os @@ -361,7 +369,10 @@ def test_tiles_endpoint_merges_remote_index(tmp_path, monkeypatch): {"col": 1054, "row": 6882, "resolution": 0.2, "viz": {"slope": {}}}, {"col": 1055, "row": 6882, "resolution": 0.2, "viz": {}}, # distant seul ], - "viz_meta": {"slope": {"label": "Pente"}}, + "viz_meta": { + "slope": {"label": "Pente"}, + "wavelet": {"label": "Ondulets"}, # hors panneau : filtrée + }, }) d = webapp.tiles_data() entries = {(t["col"], json.dumps(t["viz"], sort_keys=True)) for t in d["tiles"]} @@ -369,7 +380,8 @@ def test_tiles_endpoint_merges_remote_index(tmp_path, monkeypatch): assert (1055, '{}') in entries # tuile non cachée visible assert (1050, '{}') in entries # historique local conservé assert d["viz_meta"]["slope"]["label"] == "Pente" # distant prime - assert d["viz_meta"]["local"]["label"] == "Locale" # local complété + assert d["viz_meta"]["aspect"]["label"] == "Aspect local" # local complété + assert "wavelet" not in d["viz_meta"] # couche hors panneau filtrée assert d["stamp"] == remote_stamp # max des deux stamps diff --git a/lidar_pipeline/webapp.py b/lidar_pipeline/webapp.py index b2ee8ec..bf443d6 100644 --- a/lidar_pipeline/webapp.py +++ b/lidar_pipeline/webapp.py @@ -763,6 +763,13 @@ def tiles_data(stamp: Optional[float] = None): keys.add(k) viz_meta = dict((data or {}).get("viz_meta") or {}) viz_meta.update((remote or {}).get("viz_meta") or {}) + # Le panneau de couches est figé (PANEL_VIZ) : un index obsolète (ex. + # worker antérieur à la restriction) ne doit pas réintroduire de couches + # retirées dans le menu au rechargement de la page. + from .index import PANEL_VIZ + if PANEL_VIZ is not None: + allowed = set(PANEL_VIZ) + viz_meta = {k: v for k, v in viz_meta.items() if k in allowed} return { "tiles": merged, "viz_meta": viz_meta,