feat: display a more descriptive alert on invalid geojson error

Co-authored-by: David Larlet <david@larlet.fr>
This commit is contained in:
Yohan Boniface 2025-01-31 17:08:35 +01:00
parent 3e9982c8cb
commit 37ecea0799
4 changed files with 45 additions and 13 deletions

View file

@ -249,6 +249,7 @@ export class DataLayer extends ServerStored {
}
fromGeoJSON(geojson, sync = true) {
if (!geojson) return []
const features = this.addData(geojson, sync)
this._geojson = geojson
this.onDataLoaded()
@ -319,7 +320,9 @@ export class DataLayer extends ServerStored {
if (!this.isRemoteLayer()) return
if (!this.hasDynamicData() && this.hasDataLoaded() && !force) return
if (!this.isVisible()) return
let url = this._umap.renderUrl(this.options.remoteData.url)
// Keep non proxied url for later use in Alert.
const remoteUrl = this._umap.renderUrl(this.options.remoteData.url)
let url = remoteUrl
if (this.options.remoteData.proxy) {
url = this._umap.proxyUrl(url, this.options.remoteData.ttl)
}
@ -328,6 +331,14 @@ export class DataLayer extends ServerStored {
return this._umap.formatter
.parse(raw, this.options.remoteData.format)
.then((geojson) => this.fromGeoJSON(geojson))
.catch((error) => {
Alert.error(
translate('Cannot parse remote data for layer "{layer}" with url "{url}"', {
layer: this.getName(),
url: remoteUrl,
})
)
})
})
}
@ -455,7 +466,7 @@ export class DataLayer extends ServerStored {
// otherwise the layer becomes uneditable.
return this.makeFeatures(geojson, sync)
} catch (err) {
console.log('Error with DataLayer', this.id)
console.debug('Error with DataLayer', this.id)
console.error(err)
return []
}
@ -502,7 +513,7 @@ export class DataLayer extends ServerStored {
feature = new Polygon(this._umap, this, geojson, id)
break
default:
console.log(geojson)
console.debug(geojson)
Alert.error(
translate('Skipping unknown geometry.type: {type}', {
type: geometry.type || 'undefined',
@ -524,6 +535,9 @@ export class DataLayer extends ServerStored {
if (data?.length) this.isDirty = true
return data
})
.catch((error) => {
Alert.error(translate('Import failed: invalid data'))
})
}
readFile(f) {

View file

@ -1,5 +1,6 @@
/* Uses globals for: csv2geojson, osmtogeojson (not available as ESM) */
import { translate } from './i18n.js'
import { uMapAlert as Alert } from '../components/alerts/alert.js'
export const EXPORT_FORMATS = {
geojson: {
@ -58,11 +59,7 @@ export class Formatter {
}
async fromGeoJSON(str) {
try {
return JSON.parse(str)
} catch (err) {
U.Alert.error(`Invalid JSON file: ${err}`)
}
return JSON.parse(str)
}
async fromOSM(str) {
@ -106,8 +103,8 @@ export class Formatter {
message: err[0].message,
})
}
U.Alert.error(message, 10000)
console.error(err)
Alert.error(message, 10000)
console.debug(err)
}
if (result?.features.length) {
callback(result)
@ -127,7 +124,7 @@ export class Formatter {
const doc = new DOMParser().parseFromString(x, 'text/xml')
const errorNode = doc.querySelector('parsererror')
if (errorNode) {
U.Alert.error(translate('Cannot parse data'))
Alert.error(translate('Cannot parse data'))
}
return doc
}

View file

@ -305,7 +305,7 @@ export default class Importer extends Utils.WithTemplate {
this.onSuccess()
} catch (e) {
this.onError(translate('Invalid umap data'))
console.error(e)
console.debug(e)
return false
}
}

View file

@ -71,7 +71,6 @@ def test_umap_import_from_file(live_server, tilelayer, page):
expect(nonloaded).to_have_count(1)
@pytest.mark.skip
def test_umap_import_from_textarea(live_server, tilelayer, page, settings):
settings.UMAP_ALLOW_ANONYMOUS = True
page.goto(f"{live_server.url}/map/new/")
@ -123,6 +122,28 @@ def test_import_geojson_from_textarea(tilelayer, live_server, page):
expect(paths).to_have_count(3)
def test_import_invalid_data(tilelayer, live_server, page):
uncaught_errors = []
page.on("pageerror", lambda exc: uncaught_errors.append(exc))
page.goto(f"{live_server.url}/map/new/")
page.get_by_title("Open browser").click()
layers = page.locator(".umap-browser .datalayer")
markers = page.locator(".leaflet-marker-icon")
paths = page.locator("path")
expect(markers).to_have_count(0)
expect(paths).to_have_count(0)
expect(layers).to_have_count(0)
button = page.get_by_title("Import data")
expect(button).to_be_visible()
button.click()
textarea = page.locator(".umap-upload textarea")
textarea.fill("invalid data")
for format in ["geojson", "csv", "gpx", "kml", "georss", "osm", "umap"]:
page.locator('select[name="format"]').select_option(format)
page.get_by_role("button", name="Import data", exact=True).click()
assert not uncaught_errors, f"Error with format {format}"
def test_import_kml_from_textarea(tilelayer, live_server, page):
page.goto(f"{live_server.url}/map/new/")
page.get_by_title("Open browser").click()