L'interface webapp ne peut plus rester silencieusement périmée

La webapp légère bâchait app.js/app.css dans l'image au build : après une
évolution de l'interface, le Pi servait l'ancienne carte sans aucun signal
(tuiles invisibles, vieux fichiers). Désormais l'interface embarque sa
version (hash CSS+JS) que le serveur de données publie via /api/tiles : en
cas de divergence, bandeau « interface périmée » dans la carte + log d'alerte
côté webapp. Les assets sont servis en revalidation (jamais immutable) et
une page ouverte depuis plus de 15 min se recharge seule au retour au premier
plan — l'ancienne interface n'est plus jamais affichée après un déploiement.
This commit is contained in:
Antoine Jacquin
2026-09-21 23:43:19 +02:00
parent 7c10ae3e18
commit 64eaad751c
5 changed files with 237 additions and 19 deletions

View File

@ -307,11 +307,19 @@ def test_build_index_generates_html(tmp_path):
# les tuiles terminées sans recharger (mode incrémental du pipeline).
assert "/api/tiles" in app_js and "pollLiveTiles" in app_js
assert "registerTile" in app_js and "mergeTilesData" in app_js
# Garde anti-page périmée : un onglet ouvert depuis plus de 15 min
# (JS ancien après un déploiement) se recharge au retour au premier
# plan — l'ancienne interface n'est jamais affichée.
assert "reloadStalePage" in app_js and "visibilitychange" in app_js
# Export des données de carte (servi par /api/tiles)
data = json.loads((output_dir / "index_tiles.json").read_text(encoding='utf-8'))
assert data['tiles'] and data['tiles'][0]['corners']
assert 'aspect' in data['viz_meta']
assert data['stats']['n_tiles'] == len(data['tiles'])
# Version de l'interface exportée : la webapp légère détecte une image
# périmée (assets bâchés au build, non reconstruite après évolution)
from lidar_pipeline.index import ui_version
assert data['stats']['ui_version'] == ui_version()
# Vérifie les vignettes générées
thumb_dir = output_dir / "index_thumbs"
assert thumb_dir.is_dir()
@ -320,13 +328,23 @@ def test_build_index_generates_html(tmp_path):
def test_write_ui_assets(tmp_path):
"""_write_ui_assets écrit app.js/app.css dans le dossier cible (bâchés image)."""
from lidar_pipeline.index import _write_ui_assets, _APP_JS
"""_write_ui_assets écrit app.js/app.css dans le dossier cible (bâchés image).
app.js a __UI_VERSION__ substitué par la version réelle (ui_version) :
le JS compare cette version à celle du serveur de données et signale
une webapp périmée (bandeau, cf. checkUiVersion).
"""
from lidar_pipeline.index import _write_ui_assets, _APP_JS, ui_version
dst = tmp_path / "ui"
_write_ui_assets(dst)
v = ui_version()
assert v == ui_version() and len(v) == 10
js = (dst / "app.js").read_text(encoding="utf-8")
assert js == _APP_JS
assert js == _APP_JS.replace("__UI_VERSION__", v)
assert v in js and "__UI_VERSION__" not in js
# Le placeholder et le check sont embarqués dans la source
assert '"__UI_VERSION__"' in _APP_JS and "checkUiVersion" in _APP_JS
assert (dst / "app.css").read_text(encoding="utf-8").startswith("/*")