From 715659607a7deb57eec38d877e53895a1b4cc3f0 Mon Sep 17 00:00:00 2001 From: Louis King Date: Tue, 21 Jul 2026 19:03:04 +0100 Subject: [PATCH] =?UTF-8?q?feat(web):=20React=20charts/maps/QR=20=E2=80=94?= =?UTF-8?q?=20Phase=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace all window.Chart / window.L / window.QRCode globals and the charts.js helper script with bundled React components: - react-chartjs-2: typed config builders in utils/charts.ts (buildLineChart, buildActivityChart, buildStackedBar, buildRoutesTrend, buildRouteDetailStrip + ChartColors, averageRouteTier, routeQualityToTier) and wrappers in components/charts/Charts.tsx (ActivityChart, TrendLineChart, StackedBarChart, RoutesTrendChart, RouteDetailStrip). utils/charts.ts imports chart.js/auto. Wired into Home, Dashboard, Routes. - react-leaflet: MapPage rewritten with MapContainer/TileLayer/Marker/Popup + a useMap MapController for fit-bounds and memoized markers; NodeDetail static hero map with divIcon marker + OffsetCenter. Both import leaflet/dist/leaflet.css. - react-qr-code: replaces window.QRCode in Channels and NodeDetail. Bundling & shell: - Chart.js, Leaflet (+CSS), react-qr-code now bundled by Vite; removed the leaflet/chart.js/qrcodejs vendor - - - - - - - - - - - {% if asset_app_css %} - - {% endif %} {% if asset_app_js %} {% else %} diff --git a/tests/test_collector/test_routes.py b/tests/test_collector/test_routes.py index 3351095..76157f8 100644 --- a/tests/test_collector/test_routes.py +++ b/tests/test_collector/test_routes.py @@ -1125,8 +1125,8 @@ class TestComputeAverageQuality: """Rolling-average tier over a history window (server-side badge source). Mirrors the ``averageRouteTier`` JS helper in - ``web/static/js/charts.js`` so the route card badge matches the chart - line color when both render the same window. + ``web/static/js/spa-react/utils/charts.ts`` so the route card badge matches + the chart line color when both render the same window. """ @staticmethod diff --git a/tests/test_web/test_caching.py b/tests/test_web/test_caching.py index 93f5892..280d789 100644 --- a/tests/test_web/test_caching.py +++ b/tests/test_web/test_caching.py @@ -19,7 +19,7 @@ class TestCacheControlHeaders: def test_static_js_with_version(self, client): """Static JS with version parameter should have long-term cache.""" - response = client.get(f"/static/js/charts.js?v={__version__}") + response = client.get(f"/static/js/spa/app.js?v={__version__}") assert response.status_code == 200 assert "cache-control" in response.headers assert ( @@ -59,7 +59,7 @@ class TestCacheControlHeaders: def test_static_js_without_version(self, client): """Static JS without version should have short fallback cache.""" - response = client.get("/static/js/charts.js") + response = client.get("/static/js/spa/app.js") assert response.status_code == 200 assert "cache-control" in response.headers assert response.headers["cache-control"] == "public, max-age=3600" @@ -152,19 +152,6 @@ class TestVersionParameterInHTML: assert css_link is not None assert f"?v={__version__}" in css_link["href"] - def test_charts_js_has_version(self, client): - """Charts.js script should include version parameter.""" - response = client.get("/") - assert response.status_code == 200 - - soup = BeautifulSoup(response.text, "html.parser") - charts_script = soup.find( - "script", {"src": lambda x: x and "/static/js/charts.js" in x} - ) - - assert charts_script is not None - assert f"?v={__version__}" in charts_script["src"] - def test_app_js_has_version(self, client): """SPA app.js script should include version or content hash.""" response = client.get("/")