From 00228ccf926a8c6a6020fc532b5d45c7d5d2674e Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Fri, 25 Apr 2025 11:25:54 +0200 Subject: [PATCH] fix: loading remote data should not make the map dirty --- umap/static/umap/js/modules/data/layer.js | 23 +++---- umap/tests/integration/test_datalayer.py | 1 - umap/tests/integration/test_remote_data.py | 79 ++++++++++++++++++++++ 3 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 umap/tests/integration/test_remote_data.py diff --git a/umap/static/umap/js/modules/data/layer.js b/umap/static/umap/js/modules/data/layer.js index 9cc31283..c4e0e037 100644 --- a/umap/static/umap/js/modules/data/layer.js +++ b/umap/static/umap/js/modules/data/layer.js @@ -294,16 +294,6 @@ export class DataLayer { } } - clear() { - // TODO do not startBatch for remoteData layer - this.sync.startBatch() - for (const feature of Object.values(this._features)) { - feature.del() - } - this.sync.commitBatch() - this.dataChanged() - } - backupData() { if (this._geojson) { this._geojson_bk = Utils.CopyJSON(this._geojson) @@ -354,7 +344,7 @@ export class DataLayer { url = this._umap.proxyUrl(url, this.options.remoteData.ttl) } return await this.getUrl(url, remoteUrl).then((raw) => { - this.clear() + this.clear(false) return this._umap.formatter .parse(raw, this.options.remoteData.format) .then((geojson) => this.fromGeoJSON(geojson, false)) @@ -655,7 +645,16 @@ export class DataLayer { empty() { if (this.isRemoteLayer()) return + this.sync.startBatch() this.clear() + this.sync.commitBatch() + } + + clear(sync = true) { + for (const feature of Object.values(this._features)) { + feature.del(sync) + } + this.dataChanged() } clone() { @@ -1177,7 +1176,7 @@ export class DataLayer { // Response contains geojson only if save has conflicted and conflicts have // been resolved. So we need to reload to get extra data (added by someone else) if (data.geojson) { - this.clear() + this.clear(false) this.fromGeoJSON(data.geojson) delete data.geojson } diff --git a/umap/tests/integration/test_datalayer.py b/umap/tests/integration/test_datalayer.py index 64cd46d4..ed191f32 100644 --- a/umap/tests/integration/test_datalayer.py +++ b/umap/tests/integration/test_datalayer.py @@ -1,5 +1,4 @@ import json -import os import re import pytest diff --git a/umap/tests/integration/test_remote_data.py b/umap/tests/integration/test_remote_data.py new file mode 100644 index 00000000..d6de5029 --- /dev/null +++ b/umap/tests/integration/test_remote_data.py @@ -0,0 +1,79 @@ +from playwright.sync_api import expect + +from umap.models import Map + +from ..base import DataLayerFactory + + +def test_dynamic_remote_data(page, live_server, tilelayer, map): + data = [ + { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {"name": "Point 2"}, + "geometry": { + "type": "Point", + "coordinates": [4.3375, 11.2707], + }, + } + ], + }, + { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {"name": "Point 1"}, + "geometry": { + "type": "Point", + "coordinates": [4.3375, 12.2707], + }, + } + ], + }, + ] + + def handle(route): + route.fulfill(json=data.pop()) + + settings = { + "remoteData": { + "url": "https://remote.org/data.json", + "format": "geojson", + "dynamic": True, + }, + "showLabel": True, + } + DataLayerFactory(map=map, settings=settings) + map.edit_status = Map.ANONYMOUS + map.settings["properties"]["zoom"] = 6 + map.settings["geometry"] = { + "type": "Point", + "coordinates": [5, 12], + } + map.save() + + # Intercept the route to the proxy + page.route("https://remote.org/data.json", handle) + page.goto(f"{live_server.url}{map.get_absolute_url()}") + + expect(page.get_by_role("tooltip", name="Point 1")).to_be_visible() + + # Now drag the map + map_el = page.locator("#map") + map_el.drag_to( + map_el, + source_position={"x": 100, "y": 100}, + target_position={"x": 110, "y": 110}, + ) + + expect(page.get_by_role("tooltip", name="Point 2")).to_be_visible() + # Needed otherwise it found two (!) tooltip with name "Point 1"… + page.wait_for_timeout(300) + expect(page.get_by_role("tooltip", name="Point 1")).to_be_hidden() + + # Map must not be dirty + page.get_by_role("button", name="Edit").click() + expect(page.locator(".edit-undo")).to_be_disabled()