Surface GPX/FIT parse errors instead of silently rendering nothing
CI / check (push) Successful in 44s
CI / deploy (push) Successful in 17s

_addLayers handed MapLibre a URL and let it fetch the GeoJSON
internally — a 422 (a file REXML/Fit can't parse) just meant the
layer never appeared, with nothing telling the user why. It now
fetches the file itself first, alerts with the actual error and
un-checks the box on failure.
This commit is contained in:
randy committed 2026-09-07 14:10:46 +02:00
1 parent a0476f1204
commit 11fc14824e
2 files changed
+41 -7

No files matched your search

+34 -6
View File
@@ -206,7 +206,7 @@ export class GpxPanelControl {
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = this._visible.has(file.path);
checkbox.addEventListener("change", () => this._toggleFile(file.path, checkbox.checked));
checkbox.addEventListener("change", () => this._toggleFile(file.path, checkbox.checked, checkbox));
const name = document.createElement("span");
name.className = "gpx-tree__file-name";
name.textContent = file.name;
@@ -269,21 +269,48 @@ export class GpxPanelControl {
});
}
_toggleFile(path, visible) {
async _toggleFile(path, visible, checkbox) {
if (visible) {
this._visible.add(path);
this._addLayers(path);
const ok = await this._addLayers(path);
if (!ok) {
// Loading failed (see _addLayers) — don't leave the box checked
// for a file that isn't actually showing anything.
this._visible.delete(path);
if (checkbox) checkbox.checked = false;
}
} else {
this._visible.delete(path);
this._removeLayers(path);
}
}
_addLayers(path) {
// Fetches the file's GeoJSON itself (rather than handing maplibre a URL
// to fetch internally) so a parse failure — a real GPX a device/app
// wrote in some way REXML doesn't like, say — surfaces as an alert
// instead of the layer just silently never appearing. Returns whether it
// succeeded.
async _addLayers(path) {
const id = sourceId(path);
if (this._map.getSource(id)) return;
if (this._map.getSource(id)) return true;
this._map.addSource(id, { type: "geojson", data: gpxFileUrl(path) });
let geojson;
try {
const response = await fetch(gpxFileUrl(path));
if (!response.ok) {
const { error } = await response.json().catch(() => ({}));
window.alert(error || `Could not load "${path}".`);
return false;
}
geojson = await response.json();
} catch (err) {
window.alert(`Could not load "${path}": ${err.message}`);
return false;
}
if (this._map.getSource(id)) return true; // added concurrently (e.g. a style.load race) while this was fetching
this._map.addSource(id, { type: "geojson", data: geojson });
this._map.addLayer({
id: `${id}-line`,
type: "line",
@@ -307,6 +334,7 @@ export class GpxPanelControl {
this._registerPointInteractivity(`${id}-points`);
this._registerLineInteractivity(`${id}-line`);
return true;
}
// Registered once per layer id, ever — map.on(type, layerId, fn) is a