Sert l'interface (app.js/app.css) depuis l'image, plus depuis le volume
- Les assets de l'interface étaient écrits dans le volume (output/assets) et servis d'ici : sur la webapp légère, un app.js périmé restait servi même après rebuild de l'image. - app.js/app.css (+ Leaflet vendorisé) sont désormais bâchés dans l'image au build (Dockerfile.webapp) et servis depuis l'image ; le volume ne porte que les données (index.html, vignettes, tuiles). - _write_ui_assets() génère les assets dans un dossier cible ; repli de régénération au démarrage si non bâchés (dev). build_index continue d'écrire output/assets/ pour le mode serveur statique.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@ -26,6 +26,9 @@ build/
|
|||||||
.coverage
|
.coverage
|
||||||
htmlcov/
|
htmlcov/
|
||||||
|
|
||||||
|
# Interface bâchée dans l'image (régénérée au build, cf. Dockerfile.webapp)
|
||||||
|
lidar_pipeline/webapp_assets/
|
||||||
|
|
||||||
# Docker
|
# Docker
|
||||||
.docker/
|
.docker/
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,11 @@ RUN pip3 install --no-cache-dir \
|
|||||||
COPY lidar_pipeline/ ./lidar_pipeline/
|
COPY lidar_pipeline/ ./lidar_pipeline/
|
||||||
COPY webapp-entrypoint.sh /webapp-entrypoint.sh
|
COPY webapp-entrypoint.sh /webapp-entrypoint.sh
|
||||||
|
|
||||||
|
# CSS/JS de l'interface (app.js/app.css + Leaflet) bâchés dans l'image : la
|
||||||
|
# webapp les sert depuis /app/lidar_pipeline/webapp_assets, plus depuis le
|
||||||
|
# volume — le code de l'interface suit l'image, régénéré à chaque build.
|
||||||
|
RUN python3 -c "import sys; sys.path.insert(0, '/app'); from lidar_pipeline.index import _write_ui_assets; _write_ui_assets('/app/lidar_pipeline/webapp_assets')"
|
||||||
|
|
||||||
RUN groupadd -g 1000 lidar && \
|
RUN groupadd -g 1000 lidar && \
|
||||||
useradd -u 1000 -g lidar -m -s /bin/bash lidar && \
|
useradd -u 1000 -g lidar -m -s /bin/bash lidar && \
|
||||||
mkdir -p /data/output /data/input && \
|
mkdir -p /data/output /data/input && \
|
||||||
|
|||||||
@ -1138,14 +1138,16 @@ def build_index(output_dir, output_format='avif'):
|
|||||||
return html_path
|
return html_path
|
||||||
|
|
||||||
|
|
||||||
def _write_assets(output_dir):
|
def _write_ui_assets(assets_dir):
|
||||||
"""Écrit les fichiers statiques de l'interface (CSS + JS) dans output/assets/.
|
"""Écrit les fichiers statiques de l'interface (CSS + JS) dans `assets_dir`.
|
||||||
|
|
||||||
Inclut Leaflet vendorisé (assets/vendor/leaflet) : la carte reste
|
Inclut Leaflet vendorisé (vendor/leaflet) : la carte reste fonctionnelle
|
||||||
fonctionnelle hors ligne, sans dépendance au CDN unpkg.
|
hors ligne, sans dépendance au CDN unpkg. La webapp bâche ces fichiers
|
||||||
|
dans l'image (cf. Dockerfile.webapp) ; le mode serveur statique les écrit
|
||||||
|
dans output/assets/ (cf. _write_assets).
|
||||||
"""
|
"""
|
||||||
import shutil
|
import shutil
|
||||||
assets_dir = Path(output_dir) / 'assets'
|
assets_dir = Path(assets_dir)
|
||||||
assets_dir.mkdir(parents=True, exist_ok=True)
|
assets_dir.mkdir(parents=True, exist_ok=True)
|
||||||
(assets_dir / 'app.css').write_text(_APP_CSS, encoding='utf-8')
|
(assets_dir / 'app.css').write_text(_APP_CSS, encoding='utf-8')
|
||||||
(assets_dir / 'app.js').write_text(_APP_JS, encoding='utf-8')
|
(assets_dir / 'app.js').write_text(_APP_JS, encoding='utf-8')
|
||||||
@ -1156,6 +1158,10 @@ def _write_assets(output_dir):
|
|||||||
shutil.copytree(src_vendor, dst_vendor)
|
shutil.copytree(src_vendor, dst_vendor)
|
||||||
|
|
||||||
|
|
||||||
|
def _write_assets(output_dir):
|
||||||
|
"""Écrit les fichiers statiques de l'interface dans output/assets/."""
|
||||||
|
_write_ui_assets(Path(output_dir) / 'assets')
|
||||||
|
|
||||||
def _panel_selection(all_viz_keys):
|
def _panel_selection(all_viz_keys):
|
||||||
"""Couches proposées dans le panneau + couche activée par défaut.
|
"""Couches proposées dans le panneau + couche activée par défaut.
|
||||||
|
|
||||||
|
|||||||
@ -319,6 +319,17 @@ def test_build_index_generates_html(tmp_path):
|
|||||||
assert len(thumbs) >= 2 # au moins hillshade pour chaque tuile
|
assert len(thumbs) >= 2 # au moins hillshade pour chaque tuile
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
dst = tmp_path / "ui"
|
||||||
|
_write_ui_assets(dst)
|
||||||
|
js = (dst / "app.js").read_text(encoding="utf-8")
|
||||||
|
assert js == _APP_JS
|
||||||
|
assert (dst / "app.css").read_text(encoding="utf-8").startswith("/*")
|
||||||
|
|
||||||
|
|
||||||
def test_mid_thumbnails_generated(tmp_path):
|
def test_mid_thumbnails_generated(tmp_path):
|
||||||
"""Vignette intermédiaire 640 px générée et référencée dans l'index."""
|
"""Vignette intermédiaire 640 px générée et référencée dans l'index."""
|
||||||
from lidar_pipeline.index import build_index
|
from lidar_pipeline.index import build_index
|
||||||
|
|||||||
@ -146,10 +146,15 @@ async def _log_client_ip(request: Request, call_next):
|
|||||||
logger.info(f"{request.method} {path} — client : {ip or '?'}")
|
logger.info(f"{request.method} {path} — client : {ip or '?'}")
|
||||||
return await call_next(request)
|
return await call_next(request)
|
||||||
|
|
||||||
# assets/ (CSS/JS de l'interface) est créé dès le démarrage pour que le monteur
|
# CSS/JS de l'interface : servis depuis l'IMAGE (bâchés au build, cf.
|
||||||
# statique soit actif même avant la première génération de l'index.
|
# Dockerfile.webapp), plus depuis le volume — le code de l'interface suit
|
||||||
_assets_dir = OUTPUT_DIR / "assets"
|
# l'image, pas le cache de tuiles. En repli (dev, source non bâchée), on les
|
||||||
_assets_dir.mkdir(parents=True, exist_ok=True)
|
# régénère depuis les constantes de l'index pour que /assets soit actif même
|
||||||
|
# avant la première génération.
|
||||||
|
_assets_dir = Path(__file__).resolve().parent / "webapp_assets"
|
||||||
|
if not (_assets_dir / "app.js").is_file():
|
||||||
|
from .index import _write_ui_assets
|
||||||
|
_write_ui_assets(_assets_dir)
|
||||||
|
|
||||||
# --- Cache à la demande : la visualisation peuple le cache local -------------
|
# --- Cache à la demande : la visualisation peuple le cache local -------------
|
||||||
# Les images viennent de la machine de traitement par HTTP : une image absente
|
# Les images viennent de la machine de traitement par HTTP : une image absente
|
||||||
|
|||||||
Reference in New Issue
Block a user