diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 3aecb0314..ca57ae22d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -418,6 +418,10 @@ jobs: BASE_URL=http://localhost:13581 node test-channels-client-state-152-e2e.js 2>&1 | tee -a e2e-output.txt CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-channels-154-155-e2e.js 2>&1 | tee -a e2e-output.txt BASE_URL=http://localhost:13581 node test-map-modal-fluid-e2e.js 2>&1 | tee -a e2e-output.txt + # #332 — no map may request a tile from basemaps.cartocdn.com. + # No config.json here, so this exercises the built-in non-CARTO + # fallback (tile.openstreetmap.org) a default install resolves to. + CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-issue-332-no-carto-tiles-e2e.js 2>&1 | tee -a e2e-output.txt CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-map-nodes-pagination-e2e.js 2>&1 | tee -a e2e-output.txt CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-issue-123-map-lifecycle-e2e.js 2>&1 | tee -a e2e-output.txt BASE_URL=http://localhost:13581 node test-observer-iata-1188-e2e.js 2>&1 | tee -a e2e-output.txt diff --git a/config.example.json b/config.example.json index a89aff342..4e6c7dc25 100644 --- a/config.example.json +++ b/config.example.json @@ -94,10 +94,11 @@ }, "map": { "tiles": { - "darkDefault": "carto-dark", - "lightDefault": "carto-light", + "_comment_defaults": "#332 — the built-in defaults are 'osm-dark' / 'osm-standard' (keyless OpenStreetMap, tiles to zoom 18). Set darkDefault/lightDefault to any enabled style id to override; they take priority over the built-in fallback. Carto is NOT the default any more: since August 2026 keyless Carto raster tiles come back HTTP 200 with 'API KEY REQUIRED' stamped into the PNG, and CoreScope has no Carto basemap-key plumbing.", + "darkDefault": "osm-dark", + "lightDefault": "osm-standard", "providers": { - "_comment_carto": "Carto is the default free-tier provider. Optional: specify 'domain' for Carto enterprise (e.g. 'mycompany' for 'https://{s}.mycompany.cartocdn.com').", + "_comment_carto": "Carto styles stay available and selectable, but keyless raster tiles are watermarked 'API KEY REQUIRED' (see _comment_defaults). Optional: specify 'domain' for Carto enterprise (e.g. 'mycompany' for 'https://{s}.mycompany.cartocdn.com').", "carto": { "enabled": true, "domain": "" diff --git a/public/analytics.js b/public/analytics.js index 06eed67a1..39d90f2bf 100644 --- a/public/analytics.js +++ b/public/analytics.js @@ -2534,7 +2534,20 @@ // Render minimap if (hasMap && typeof L !== 'undefined') { const map = L.map('subpathMap', { zoomControl: false, attributionControl: false }); - L.tileLayer(getTileUrl(), { maxZoom: 18 }).addTo(map); + // #332 — go through the one shared helper (nodes.js, also used by the + // node-detail inset, node-reach, packet-path, area-nodes and + // rx-coverage maps). It resolves the configured provider for the + // current theme AND applies that provider's invertFilter to THIS + // map's own tile pane. A bare L.tileLayer(getTileUrl()) skipped the + // filter, so the keyless-OSM dark default (the light OSM template + // plus an invert filter) rendered a light basemap in a dark page. + if (typeof window._applyTilesToNodeMap === 'function') { + window._applyTilesToNodeMap(map); + } else { + // Loud, not silent: the shared tile helper is missing. + console.warn('subpath minimap: _applyTilesToNodeMap unavailable — using OSM fallback'); + L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18 }).addTo(map); + } const latlngs = []; nodesWithLoc.forEach((n, i) => { diff --git a/public/customize-v2.js b/public/customize-v2.js index d1d844cfd..54eedfc9c 100644 --- a/public/customize-v2.js +++ b/public/customize-v2.js @@ -1637,8 +1637,12 @@ function _renderTileProviderSelector() { var reg = (typeof window !== 'undefined') && window.MC_TILE_PROVIDERS; if (!reg) return ''; - var activeDark = (typeof window.MC_getDarkTileProvider === 'function') ? window.MC_getDarkTileProvider() : 'carto-dark'; - var activeLight = (typeof window.MC_getLightTileProvider === 'function') ? window.MC_getLightTileProvider() : 'carto-light'; + // #332 — the last-resort id comes from the registry's own exported + // defaults, never from a hard-coded 'carto-*'. CARTO is no longer the + // built-in default, so naming it here would have preselected a style + // the instance may not even have enabled. + var activeDark = (typeof window.MC_getDarkTileProvider === 'function') ? window.MC_getDarkTileProvider() : window.MC_DARK_TILE_DEFAULT; + var activeLight = (typeof window.MC_getLightTileProvider === 'function') ? window.MC_getLightTileProvider() : window.MC_LIGHT_TILE_DEFAULT; var darkIds = Object.keys(reg).filter(function(id) { return reg[id].type === 'dark'; }); var lightIds = Object.keys(reg).filter(function(id) { return reg[id].type === 'light'; }); @@ -1766,6 +1770,21 @@ ''; } + /* #332 — both geo-filter preview maps used to hard-code the CARTO + * light_all template, so they rendered "API KEY REQUIRED" tiles even on + * instances configured for Esri/OpenTopoMap/OSM. Resolve the operator's + * configured LIGHT provider instead (these previews are always + * light-styled regardless of the app theme), falling back to roles.js + * TILE_LIGHT, which is itself non-CARTO. */ + function _cv2PreviewTile() { + var spec = (typeof window.MC_getTileSpec === 'function') ? window.MC_getTileSpec('light') : null; + return { + url: (spec && spec.url) || window.TILE_LIGHT, + attribution: (spec && spec.attribution) || '© OpenStreetMap contributors', + maxZoom: (spec && spec.maxZoom) || 19 + }; + } + function _gfOpenModal(container) { var existing = document.getElementById('cv2-gf-modal-overlay'); if (existing) existing.remove(); @@ -1835,8 +1854,9 @@ var modalClosingLine = null; _gfModalMap = L.map(mapDiv, { zoomControl: true }); - L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', { - attribution: '© OpenStreetMap © CartoDB', maxZoom: 19 + var _cv2Tile = _cv2PreviewTile(); + L.tileLayer(_cv2Tile.url, { + attribution: _cv2Tile.attribution, maxZoom: _cv2Tile.maxZoom }).addTo(_gfModalMap); function renderModal() { @@ -2044,8 +2064,9 @@ if (!mapEl || typeof L === 'undefined') return; _gfMap = L.map(mapEl, { zoomControl: false, dragging: false, scrollWheelZoom: false, doubleClickZoom: false, touchZoom: false }); - L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', { - attribution: '© OpenStreetMap © CartoDB', maxZoom: 19 + var _cv2Tile = _cv2PreviewTile(); + L.tileLayer(_cv2Tile.url, { + attribution: _cv2Tile.attribution, maxZoom: _cv2Tile.maxZoom }).addTo(_gfMap); if (!_gfLoaded) { diff --git a/public/geofilter-builder.html b/public/geofilter-builder.html index 2a55ca840..c2ae0fd5f 100644 --- a/public/geofilter-builder.html +++ b/public/geofilter-builder.html @@ -21,6 +21,11 @@ #btnClear:hover { background: #7a2020; } .hint { font-size: 0.8rem; color: #888; margin-left: auto; } #map { flex: 1; } + /* #332 — the keyless OSM basemap is a LIGHT style; invert the tile pane so + this builder keeps the dark map it had while it hard-coded CARTO + dark_all. Same filter string as INVERT_CSS in map-tile-providers.js. + Scoped to the tile pane, so markers and the polygon stay true-colour. */ + #map .leaflet-tile-pane { filter: invert(1) hue-rotate(180deg) brightness(0.9) contrast(1.05); } #output-panel { background: #0f0f23; border-top: 1px solid #333; padding: 12px 16px; display: flex; gap: 12px; align-items: flex-start; } #output-panel label { font-size: 0.75rem; color: #888; white-space: nowrap; padding-top: 6px; } #output { flex: 1; background: #111; border: 1px solid #333; border-radius: 6px; padding: 10px 12px; font-family: monospace; font-size: 0.78rem; color: #7ec8e3; white-space: pre; overflow-x: auto; min-height: 54px; max-height: 140px; overflow-y: auto; cursor: text; } @@ -88,8 +93,14 @@