umap-project 2.1.3__py3-none-any.whl → 2.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of umap-project might be problematic. Click here for more details.

Files changed (200) hide show
  1. umap/__init__.py +1 -1
  2. umap/context_processors.py +1 -0
  3. umap/locale/br/LC_MESSAGES/django.mo +0 -0
  4. umap/locale/en/LC_MESSAGES/django.po +32 -32
  5. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  6. umap/locale/it/LC_MESSAGES/django.mo +0 -0
  7. umap/locale/ms/LC_MESSAGES/django.mo +0 -0
  8. umap/migrations/0020_alter_tilelayer_url_template.py +19 -0
  9. umap/migrations/0021_remove_map_description.py +16 -0
  10. umap/models.py +8 -6
  11. umap/settings/base.py +1 -0
  12. umap/static/umap/base.css +43 -156
  13. umap/static/umap/content.css +7 -25
  14. umap/static/umap/css/icon.css +112 -0
  15. umap/static/umap/css/panel.css +140 -0
  16. umap/static/umap/img/16-white.svg +5 -1
  17. umap/static/umap/img/16.svg +7 -4
  18. umap/static/umap/img/24-white.svg +3 -1
  19. umap/static/umap/img/24.svg +3 -4
  20. umap/static/umap/img/source/16-white.svg +176 -940
  21. umap/static/umap/img/source/16.svg +8 -5
  22. umap/static/umap/img/source/24-white.svg +5 -3
  23. umap/static/umap/img/source/24.svg +6 -7
  24. umap/static/umap/js/modules/browser.js +97 -73
  25. umap/static/umap/js/modules/dompurify.js +12 -0
  26. umap/static/umap/js/modules/facets.js +149 -0
  27. umap/static/umap/js/modules/global.js +9 -1
  28. umap/static/umap/js/modules/i18n.js +7 -0
  29. umap/static/umap/js/modules/orderable.js +84 -0
  30. umap/static/umap/js/modules/panel.js +76 -0
  31. umap/static/umap/js/modules/request.js +0 -1
  32. umap/static/umap/js/modules/schema.js +324 -223
  33. umap/static/umap/js/modules/urls.js +1 -16
  34. umap/static/umap/js/modules/utils.js +340 -0
  35. umap/static/umap/js/umap.autocomplete.js +40 -25
  36. umap/static/umap/js/umap.controls.js +227 -369
  37. umap/static/umap/js/umap.core.js +77 -366
  38. umap/static/umap/js/umap.datalayer.permissions.js +1 -1
  39. umap/static/umap/js/umap.features.js +62 -42
  40. umap/static/umap/js/umap.forms.js +128 -36
  41. umap/static/umap/js/umap.icon.js +11 -4
  42. umap/static/umap/js/umap.importer.js +78 -57
  43. umap/static/umap/js/umap.js +179 -156
  44. umap/static/umap/js/umap.layer.js +79 -40
  45. umap/static/umap/js/umap.permissions.js +13 -9
  46. umap/static/umap/js/umap.popup.js +26 -30
  47. umap/static/umap/js/umap.share.js +12 -9
  48. umap/static/umap/js/umap.tableeditor.js +4 -6
  49. umap/static/umap/js/umap.ui.js +10 -60
  50. umap/static/umap/locale/am_ET.js +243 -227
  51. umap/static/umap/locale/am_ET.json +21 -9
  52. umap/static/umap/locale/ar.js +243 -227
  53. umap/static/umap/locale/ar.json +21 -9
  54. umap/static/umap/locale/ast.js +243 -227
  55. umap/static/umap/locale/ast.json +21 -9
  56. umap/static/umap/locale/bg.js +243 -227
  57. umap/static/umap/locale/bg.json +21 -9
  58. umap/static/umap/locale/br.js +253 -237
  59. umap/static/umap/locale/br.json +25 -13
  60. umap/static/umap/locale/ca.js +243 -227
  61. umap/static/umap/locale/ca.json +21 -9
  62. umap/static/umap/locale/cs_CZ.js +243 -227
  63. umap/static/umap/locale/cs_CZ.json +21 -9
  64. umap/static/umap/locale/da.js +243 -227
  65. umap/static/umap/locale/da.json +21 -9
  66. umap/static/umap/locale/de.js +243 -227
  67. umap/static/umap/locale/de.json +21 -9
  68. umap/static/umap/locale/el.js +243 -227
  69. umap/static/umap/locale/el.json +21 -9
  70. umap/static/umap/locale/en.js +243 -234
  71. umap/static/umap/locale/en.json +22 -10
  72. umap/static/umap/locale/en_US.json +21 -9
  73. umap/static/umap/locale/es.js +243 -227
  74. umap/static/umap/locale/es.json +21 -9
  75. umap/static/umap/locale/et.js +243 -227
  76. umap/static/umap/locale/et.json +21 -9
  77. umap/static/umap/locale/eu.js +227 -199
  78. umap/static/umap/locale/eu.json +1 -1
  79. umap/static/umap/locale/fa_IR.js +243 -227
  80. umap/static/umap/locale/fa_IR.json +21 -9
  81. umap/static/umap/locale/fi.js +243 -227
  82. umap/static/umap/locale/fi.json +21 -9
  83. umap/static/umap/locale/fr.js +243 -234
  84. umap/static/umap/locale/fr.json +21 -9
  85. umap/static/umap/locale/gl.js +243 -227
  86. umap/static/umap/locale/gl.json +21 -9
  87. umap/static/umap/locale/he.js +243 -227
  88. umap/static/umap/locale/he.json +21 -9
  89. umap/static/umap/locale/hr.js +243 -227
  90. umap/static/umap/locale/hr.json +21 -9
  91. umap/static/umap/locale/hu.js +243 -234
  92. umap/static/umap/locale/hu.json +21 -9
  93. umap/static/umap/locale/id.js +243 -227
  94. umap/static/umap/locale/id.json +21 -9
  95. umap/static/umap/locale/is.js +243 -227
  96. umap/static/umap/locale/is.json +21 -9
  97. umap/static/umap/locale/it.js +243 -234
  98. umap/static/umap/locale/it.json +21 -9
  99. umap/static/umap/locale/ja.js +243 -227
  100. umap/static/umap/locale/ja.json +21 -9
  101. umap/static/umap/locale/ko.js +243 -227
  102. umap/static/umap/locale/ko.json +21 -9
  103. umap/static/umap/locale/lt.js +243 -227
  104. umap/static/umap/locale/lt.json +21 -9
  105. umap/static/umap/locale/ms.js +243 -234
  106. umap/static/umap/locale/ms.json +22 -10
  107. umap/static/umap/locale/nl.js +246 -230
  108. umap/static/umap/locale/nl.json +21 -9
  109. umap/static/umap/locale/no.js +243 -227
  110. umap/static/umap/locale/no.json +21 -9
  111. umap/static/umap/locale/pl.js +243 -227
  112. umap/static/umap/locale/pl.json +21 -9
  113. umap/static/umap/locale/pl_PL.json +21 -9
  114. umap/static/umap/locale/pt.js +243 -227
  115. umap/static/umap/locale/pt.json +21 -9
  116. umap/static/umap/locale/pt_BR.js +243 -227
  117. umap/static/umap/locale/pt_BR.json +21 -9
  118. umap/static/umap/locale/pt_PT.js +243 -227
  119. umap/static/umap/locale/pt_PT.json +21 -9
  120. umap/static/umap/locale/ro.js +243 -227
  121. umap/static/umap/locale/ro.json +21 -9
  122. umap/static/umap/locale/ru.js +243 -227
  123. umap/static/umap/locale/ru.json +21 -9
  124. umap/static/umap/locale/si.js +1 -1
  125. umap/static/umap/locale/si.json +1 -1
  126. umap/static/umap/locale/sk_SK.js +243 -227
  127. umap/static/umap/locale/sk_SK.json +21 -9
  128. umap/static/umap/locale/sl.js +243 -227
  129. umap/static/umap/locale/sl.json +21 -9
  130. umap/static/umap/locale/sr.js +243 -227
  131. umap/static/umap/locale/sr.json +21 -9
  132. umap/static/umap/locale/sv.js +243 -227
  133. umap/static/umap/locale/sv.json +21 -9
  134. umap/static/umap/locale/th_TH.js +243 -227
  135. umap/static/umap/locale/th_TH.json +21 -9
  136. umap/static/umap/locale/tr.js +243 -227
  137. umap/static/umap/locale/tr.json +21 -9
  138. umap/static/umap/locale/uk_UA.js +243 -227
  139. umap/static/umap/locale/uk_UA.json +21 -9
  140. umap/static/umap/locale/vi.js +243 -227
  141. umap/static/umap/locale/vi.json +21 -9
  142. umap/static/umap/locale/vi_VN.json +21 -9
  143. umap/static/umap/locale/zh.js +243 -227
  144. umap/static/umap/locale/zh.json +21 -9
  145. umap/static/umap/locale/zh_CN.json +21 -9
  146. umap/static/umap/locale/zh_TW.Big5.json +21 -9
  147. umap/static/umap/locale/zh_TW.js +243 -234
  148. umap/static/umap/locale/zh_TW.json +21 -9
  149. umap/static/umap/map.css +124 -264
  150. umap/static/umap/test/DataLayer.js +463 -0
  151. umap/static/umap/test/Feature.js +0 -226
  152. umap/static/umap/test/TableEditor.js +104 -0
  153. umap/static/umap/test/Util.js +0 -521
  154. umap/static/umap/test/index.html +0 -1
  155. umap/static/umap/unittests/URLs.js +1 -1
  156. umap/static/umap/unittests/utils.js +610 -0
  157. umap/static/umap/vars.css +9 -0
  158. umap/static/umap/vendors/dompurify/purify.es.mjs +1525 -0
  159. umap/static/umap/vendors/formbuilder/Leaflet.FormBuilder.js +1 -0
  160. umap/static/umap/vendors/iconlayers/iconLayers.js +1 -1
  161. umap/templates/umap/css.html +2 -0
  162. umap/templates/umap/js.html +0 -1
  163. umap/templates/umap/map_detail.html +4 -0
  164. umap/templates/umap/map_table.html +12 -10
  165. umap/templatetags/umap_tags.py +5 -0
  166. umap/tests/integration/conftest.py +12 -1
  167. umap/tests/integration/test_anonymous_owned_map.py +27 -5
  168. umap/tests/integration/test_basics.py +21 -0
  169. umap/tests/integration/test_browser.py +12 -25
  170. umap/tests/integration/test_choropleth.py +1 -1
  171. umap/tests/integration/test_dashboard.py +10 -0
  172. umap/tests/integration/test_datalayer.py +8 -6
  173. umap/tests/integration/test_edit_datalayer.py +24 -19
  174. umap/tests/integration/test_edit_map.py +189 -2
  175. umap/tests/integration/test_edit_marker.py +120 -0
  176. umap/tests/integration/test_edit_polygon.py +122 -0
  177. umap/tests/integration/test_facets_browser.py +104 -14
  178. umap/tests/integration/test_import.py +72 -20
  179. umap/tests/integration/test_map.py +19 -17
  180. umap/tests/integration/test_map_list.py +28 -0
  181. umap/tests/integration/test_owned_map.py +10 -10
  182. umap/tests/integration/test_picto.py +5 -5
  183. umap/tests/integration/test_querystring.py +9 -15
  184. umap/tests/integration/test_slideshow.py +0 -5
  185. umap/tests/integration/test_statics.py +3 -2
  186. umap/tests/integration/test_tableeditor.py +1 -5
  187. umap/tests/integration/test_tilelayer.py +10 -0
  188. umap/tests/integration/test_view_marker.py +64 -0
  189. umap/tests/integration/test_view_polygon.py +59 -0
  190. umap/tests/integration/test_view_polyline.py +51 -0
  191. umap/tests/test_map_views.py +13 -0
  192. {umap_project-2.1.3.dist-info → umap_project-2.2.0.dist-info}/METADATA +12 -12
  193. {umap_project-2.1.3.dist-info → umap_project-2.2.0.dist-info}/RECORD +198 -182
  194. {umap_project-2.1.3.dist-info → umap_project-2.2.0.dist-info}/WHEEL +1 -1
  195. umap/static/umap/vendors/dompurify/purify.min.js +0 -3
  196. umap/static/umap/vendors/dompurify/purify.min.js.map +0 -1
  197. /umap/tests/integration/{test_polygon.py → test_draw_polygon.py} +0 -0
  198. /umap/tests/integration/{test_polyline.py → test_draw_polyline.py} +0 -0
  199. {umap_project-2.1.3.dist-info → umap_project-2.2.0.dist-info}/entry_points.txt +0 -0
  200. {umap_project-2.1.3.dist-info → umap_project-2.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -208,6 +208,7 @@ L.FormBuilder.Textarea = L.FormBuilder.Element.extend({
208
208
  build: function () {
209
209
  this.input = L.DomUtil.create('textarea', this.options.className || '', this.parentNode);
210
210
  if (this.options.placeholder) this.input.placeholder = this.options.placeholder;
211
+ this.input.name = this.name;
211
212
  this.fetch();
212
213
  L.DomEvent.on(this.input, 'input', this.sync, this);
213
214
  L.DomEvent.on(this.input, 'keypress', this.onKeyPress, this);
@@ -307,4 +307,4 @@
307
307
  iconLayers.Constructor = IconLayers;
308
308
 
309
309
  return iconLayers;
310
- });
310
+ });
@@ -23,8 +23,10 @@
23
23
  href="{% static 'umap/vendors/iconlayers/iconLayers.css' %}" />
24
24
  <link rel="stylesheet" href="{% static 'umap/vars.css' %}" />
25
25
  <link rel="stylesheet" href="{% static 'umap/font.css' %}" />
26
+ <link rel="stylesheet" href="{% static 'umap/css/icon.css' %}" />
26
27
  <link rel="stylesheet" href="{% static 'umap/base.css' %}" />
27
28
  <link rel="stylesheet" href="{% static 'umap/content.css' %}" />
28
29
  <link rel="stylesheet" href="{% static 'umap/nav.css' %}" />
29
30
  <link rel="stylesheet" href="{% static 'umap/map.css' %}" />
31
+ <link rel="stylesheet" href="{% static 'umap/css/panel.css' %}" />
30
32
  <link rel="stylesheet" href="{% static 'umap/theme.css' %}" />
@@ -42,7 +42,6 @@
42
42
  <script src="{% static 'umap/vendors/tokml/tokml.js' %}" defer></script>
43
43
  <script src="{% static 'umap/vendors/locatecontrol/L.Control.Locate.min.js' %}"
44
44
  defer></script>
45
- <script src="{% static 'umap/vendors/dompurify/purify.min.js' %}" defer></script>
46
45
  <script src="{% static 'umap/vendors/colorbrewer/colorbrewer.js' %}" defer></script>
47
46
  <script src="{% static 'umap/vendors/simple-statistics/simple-statistics.min.js' %}"
48
47
  defer></script>
@@ -18,6 +18,10 @@
18
18
  type="application/json+oembed"
19
19
  href="{{ oembed_absolute_uri }}?url={{ quoted_absolute_uri }}&format=json"
20
20
  title="{{ map.name }} oEmbed URL" />
21
+ <meta property="og:url" content="{{ SITE_URL }}{{ map.get_absolute_url }}" />
22
+ <meta property="og:title" content="{{ map.name }}" />
23
+ <meta property="og:description" content="{{ map.description }}" />
24
+ <meta property="og:site_name" content="{{ SITE_NAME }}" />
21
25
  {% endblock extra_head %}
22
26
  {% block content %}
23
27
  {% block map_init %}
@@ -68,16 +68,18 @@
68
68
  <span class="sr-only">{% translate "Clone" %}</span>
69
69
  </button>
70
70
  </form>
71
- <form action="{% url 'map_delete' map_inst.pk %}"
72
- method="post"
73
- class="map-delete">
74
- {% csrf_token %}
75
- <input type="hidden" name="next" value="{% url 'user_dashboard' %}">
76
- <button class="map-icon" type="submit" title="{% translate "Delete" %}">
77
- <span class="icon-dashboard icon-delete"></span>
78
- <span class="sr-only">{% translate "Delete" %}</span>
79
- </button>
80
- </form>
71
+ {% if map_inst|can_delete_map:request %}
72
+ <form action="{% url 'map_delete' map_inst.pk %}"
73
+ method="post"
74
+ class="map-delete">
75
+ {% csrf_token %}
76
+ <input type="hidden" name="next" value="{% url 'user_dashboard' %}">
77
+ <button class="map-icon" type="submit" title="{% translate "Delete" %}">
78
+ <span class="icon-dashboard icon-delete"></span>
79
+ <span class="sr-only">{% translate "Delete" %}</span>
80
+ </button>
81
+ </form>
82
+ {% endif %}
81
83
  </td>
82
84
  </tr>
83
85
  {% endwith %}
@@ -43,6 +43,11 @@ def tilelayer_preview(tilelayer):
43
43
  return output
44
44
 
45
45
 
46
+ @register.filter
47
+ def can_delete_map(map, request):
48
+ return map.can_delete(request.user, request)
49
+
50
+
46
51
  @register.filter
47
52
  def notag(s):
48
53
  return s.replace("<", "&lt;")
@@ -1,9 +1,20 @@
1
+ import os
2
+
1
3
  import pytest
2
4
 
3
5
 
4
6
  @pytest.fixture(autouse=True)
5
7
  def set_timeout(context):
6
- context.set_default_timeout(5000)
8
+ context.set_default_timeout(int(os.environ.get("PLAYWRIGHT_TIMEOUT", 7500)))
9
+ context.set_default_navigation_timeout(
10
+ int(os.environ.get("PLAYWRIGHT_TIMEOUT", 7500))
11
+ )
12
+
13
+
14
+ @pytest.fixture(autouse=True)
15
+ def mock_osm_tiles(page):
16
+ if not bool(os.environ.get("PLAYWRIGHT_USE_TILES", False)):
17
+ page.route("*/**/osmfr/**", lambda route: route.fulfill())
7
18
 
8
19
 
9
20
  @pytest.fixture
@@ -34,7 +34,7 @@ def test_map_load_with_owner(anonymap, live_server, owner_session):
34
34
  expect(save).to_be_visible()
35
35
  add_marker = owner_session.get_by_title("Draw a marker")
36
36
  expect(add_marker).to_be_visible()
37
- edit_settings = owner_session.get_by_title("Edit map properties")
37
+ edit_settings = owner_session.get_by_title("Map advanced properties")
38
38
  expect(edit_settings).to_be_visible()
39
39
  edit_permissions = owner_session.get_by_title("Update permissions and editors")
40
40
  expect(edit_permissions).to_be_visible()
@@ -65,7 +65,7 @@ def test_map_load_with_anonymous_but_editable_layer(
65
65
  expect(save).to_be_visible()
66
66
  add_marker = page.get_by_title("Draw a marker")
67
67
  expect(add_marker).to_be_visible()
68
- edit_settings = page.get_by_title("Edit map properties")
68
+ edit_settings = page.get_by_title("Map advanced properties")
69
69
  expect(edit_settings).to_be_hidden()
70
70
  edit_permissions = page.get_by_title("Update permissions and editors")
71
71
  expect(edit_permissions).to_be_hidden()
@@ -114,12 +114,13 @@ def test_anonymous_can_add_marker_on_editable_layer(
114
114
  marker = page.locator(".leaflet-marker-icon")
115
115
  map_el = page.locator("#map")
116
116
  expect(marker).to_have_count(2)
117
- expect(map_el).not_to_have_class(re.compile("umap-ui"))
117
+ panel = page.locator(".panel.right.on")
118
+ expect(panel).to_be_hidden()
118
119
  add_marker.click()
119
120
  map_el.click(position={"x": 100, "y": 100})
120
121
  expect(marker).to_have_count(3)
121
122
  # Edit panel is open
122
- expect(map_el).to_have_class(re.compile("umap-ui"))
123
+ expect(panel).to_be_visible()
123
124
  datalayer_select = page.locator("select[name='datalayer']")
124
125
  expect(datalayer_select).to_be_visible()
125
126
  options = page.locator("select[name='datalayer'] option")
@@ -132,7 +133,7 @@ def test_can_change_perms_after_create(tilelayer, live_server, page):
132
133
  page.goto(f"{live_server.url}/en/map/new")
133
134
  # Create a layer
134
135
  page.get_by_title("Manage layers").click()
135
- page.get_by_role("button", name="Add a layer").click()
136
+ page.get_by_title("Add a layer").click()
136
137
  page.locator("input[name=name]").fill("Layer 1")
137
138
  save = page.get_by_role("button", name="Save")
138
139
  expect(save).to_be_visible()
@@ -202,3 +203,24 @@ def test_email_sending_error_are_catched(tilelayer, page, live_server):
202
203
  alert.get_by_role("button", name="Send me the link").click()
203
204
  assert patched.called
204
205
  expect(alert.get_by_text("Can't send email to foo@bar.com")).to_be_visible()
206
+
207
+
208
+ @pytest.mark.skip(reason="Changing DEFAULT_FROM_EMAIL at runtime has no effect")
209
+ def test_alert_message_after_create_show_link_even_without_mail(
210
+ tilelayer, live_server, page, monkeypatch, settings
211
+ ):
212
+ # Disable email
213
+ settings.DEFAULT_FROM_EMAIL = None
214
+ page.goto(f"{live_server.url}/en/map/new")
215
+ with page.expect_response(re.compile(r".*/map/create/")):
216
+ page.get_by_role("button", name="Save").click()
217
+ alert = page.locator(".umap-alert")
218
+ expect(alert).to_be_visible()
219
+ expect(
220
+ alert.get_by_text(
221
+ "Your map has been created! As you are not logged in, here is your secret "
222
+ "link to edit the map, please keep it safe:"
223
+ )
224
+ ).to_be_visible()
225
+ expect(alert.get_by_role("button", name="Copy")).to_be_visible()
226
+ expect(alert.get_by_role("button", name="Send me the link")).to_be_hidden()
@@ -45,3 +45,24 @@ def test_create_map_with_cursor(page, live_server, tilelayer):
45
45
  "z-index: 200;"
46
46
  ),
47
47
  )
48
+
49
+
50
+ def test_cannot_put_script_tag_in_datalayer_name_or_description(
51
+ openmap, live_server, page, tilelayer
52
+ ):
53
+ page.goto(f"{live_server.url}{openmap.get_absolute_url()}")
54
+ page.get_by_role("button", name="Edit").click()
55
+ page.get_by_role("link", name="Manage layers").click()
56
+ page.get_by_role("button", name="Add a layer").click()
57
+ page.locator('input[name="name"]').click()
58
+ page.locator('input[name="name"]').fill('<script>alert("attack")</script>')
59
+ page.locator(".umap-field-description textarea").click()
60
+ page.locator(".umap-field-description textarea").fill(
61
+ '<p>before <script>alert("attack")</script> after</p>'
62
+ )
63
+ page.get_by_role("button", name="Save").click()
64
+ page.get_by_role("button", name="About").click()
65
+ # Title should contain raw HTML (we are using textContent)
66
+ expect(page.get_by_text('<script>alert("attack")</script>')).to_be_visible()
67
+ # Description should contain escaped HTML
68
+ expect(page.get_by_text("before after")).to_be_visible()
@@ -63,7 +63,7 @@ def bootstrap(map, live_server):
63
63
 
64
64
  def test_data_browser_should_be_open(live_server, page, bootstrap, map):
65
65
  page.goto(f"{live_server.url}{map.get_absolute_url()}")
66
- el = page.locator(".umap-browse-data")
66
+ el = page.locator(".umap-browser")
67
67
  expect(el).to_be_visible()
68
68
  expect(page.get_by_text("one point in france")).to_be_visible()
69
69
  expect(page.get_by_text("one line in new zeland")).to_be_visible()
@@ -81,7 +81,7 @@ def test_data_browser_should_be_filterable(live_server, page, bootstrap, map):
81
81
  expect(filter_).to_be_visible()
82
82
  filter_.type("poly")
83
83
  expect(page.get_by_title("Features in this layer: 1/3")).to_be_visible()
84
- expect(page.get_by_title("Features in this layer: 1/3")).to_have_text("1/3")
84
+ expect(page.get_by_title("Features in this layer: 1/3")).to_have_text("(1/3)")
85
85
  expect(page.get_by_text("one point in france")).to_be_hidden()
86
86
  expect(page.get_by_text("one line in new zeland")).to_be_hidden()
87
87
  expect(page.get_by_text("one polygon in greenland")).to_be_visible()
@@ -159,20 +159,19 @@ def test_data_browser_bbox_filter_should_be_persistent(
159
159
  el = page.get_by_text("Current map view")
160
160
  expect(el).to_be_visible()
161
161
  el.click()
162
- browser = page.locator("#umap-ui-container")
162
+ browser = page.locator(".panel.left.on")
163
163
  expect(browser.get_by_text("one point in france")).to_be_visible()
164
164
  expect(browser.get_by_text("one line in new zeland")).to_be_hidden()
165
165
  expect(browser.get_by_text("one polygon in greenland")).to_be_hidden()
166
166
  # Close and reopen the browser to make sure this settings is persistent
167
- close = browser.get_by_text("Close")
167
+ close = browser.get_by_title("Close")
168
168
  close.click()
169
169
  expect(browser).to_be_hidden()
170
170
  sleep(0.5)
171
171
  expect(browser.get_by_text("one point in france")).to_be_hidden()
172
172
  expect(browser.get_by_text("one line in new zeland")).to_be_hidden()
173
173
  expect(browser.get_by_text("one polygon in greenland")).to_be_hidden()
174
- page.get_by_title("See data layers").click()
175
- page.get_by_role("button", name="Browse data").click()
174
+ page.get_by_title("See layers").click()
176
175
  expect(browser.get_by_text("one point in france")).to_be_visible()
177
176
  expect(browser.get_by_text("one line in new zeland")).to_be_hidden()
178
177
  expect(browser.get_by_text("one polygon in greenland")).to_be_hidden()
@@ -185,7 +184,7 @@ def test_data_browser_bbox_filtered_is_clickable(live_server, page, bootstrap, m
185
184
  el = page.get_by_text("Current map view")
186
185
  expect(el).to_be_visible()
187
186
  el.click()
188
- browser = page.locator("#umap-ui-container")
187
+ browser = page.locator(".panel.left.on")
189
188
  expect(browser.get_by_text("one point in france")).to_be_visible()
190
189
  expect(browser.get_by_text("one line in new zeland")).to_be_hidden()
191
190
  expect(browser.get_by_text("one polygon in greenland")).to_be_hidden()
@@ -217,18 +216,6 @@ def test_data_browser_with_variable_in_name(live_server, page, bootstrap, map):
217
216
  expect(page.get_by_text("one polygon in greenland (polygon)")).to_be_visible()
218
217
 
219
218
 
220
- def test_can_open_databrowser_from_layers_list(live_server, map, page, bootstrap):
221
- page.goto(f"{live_server.url}{map.get_absolute_url()}")
222
- page.get_by_title("See data layers").click()
223
- page.get_by_role("button", name="Browse data").click()
224
- browser = page.locator(".umap-browse-data")
225
- expect(browser).to_be_visible()
226
- expect(browser.get_by_text("test datalayer")).to_be_visible()
227
- expect(browser.get_by_text("one point in france")).to_be_visible()
228
- expect(browser.get_by_text("one line in new zeland")).to_be_visible()
229
- expect(browser.get_by_text("one polygon in greenland")).to_be_visible()
230
-
231
-
232
219
  def test_should_sort_features_in_natural_order(live_server, map, page):
233
220
  map.settings["properties"]["onLoadPanel"] = "databrowser"
234
221
  map.save()
@@ -238,7 +225,7 @@ def test_should_sort_features_in_natural_order(live_server, map, page):
238
225
  datalayer_data["features"][2]["properties"]["name"] = "100. a line"
239
226
  DataLayerFactory(map=map, data=datalayer_data)
240
227
  page.goto(f"{live_server.url}{map.get_absolute_url()}")
241
- features = page.locator(".umap-browse-data li")
228
+ features = page.locator(".umap-browser .datalayer li")
242
229
  expect(features).to_have_count(3)
243
230
  expect(features.nth(0)).to_have_text("1. a poly")
244
231
  expect(features.nth(1)).to_have_text("9. a marker")
@@ -249,7 +236,7 @@ def test_should_redraw_list_on_feature_delete(live_server, openmap, page, bootst
249
236
  page.goto(f"{live_server.url}{openmap.get_absolute_url()}")
250
237
  # Enable edit
251
238
  page.get_by_role("button", name="Edit").click()
252
- buttons = page.locator(".umap-browse-data li .feature-delete")
239
+ buttons = page.locator(".umap-browser .datalayer li .icon-delete")
253
240
  expect(buttons).to_have_count(3)
254
241
  page.on("dialog", lambda dialog: dialog.accept())
255
242
  buttons.nth(0).click()
@@ -265,7 +252,7 @@ def test_should_show_header_for_display_on_load_false(
265
252
  datalayer.settings["name"] = "This layer is not loaded"
266
253
  datalayer.save()
267
254
  page.goto(f"{live_server.url}{map.get_absolute_url()}")
268
- browser = page.locator(".umap-browse-data")
255
+ browser = page.locator(".umap-browser")
269
256
  expect(browser).to_be_visible()
270
257
  expect(browser.get_by_text("This layer is not loaded")).to_be_visible()
271
258
 
@@ -279,7 +266,7 @@ def test_should_use_color_variable(live_server, map, page):
279
266
  datalayer_data["features"][2]["properties"]["mycolor"] = "DarkGreen"
280
267
  DataLayerFactory(map=map, data=datalayer_data)
281
268
  page.goto(f"{live_server.url}{map.get_absolute_url()}")
282
- features = page.locator(".umap-browse-data li .feature-color")
269
+ features = page.locator(".umap-browser .datalayer li .feature-color")
283
270
  expect(features).to_have_count(3)
284
271
  # DarkGreen
285
272
  expect(features.nth(0)).to_have_css("background-color", "rgb(0, 100, 0)")
@@ -295,7 +282,7 @@ def test_should_allow_to_toggle_datalayer_visibility(live_server, map, page, boo
295
282
  paths = page.locator(".leaflet-overlay-pane path")
296
283
  expect(markers).to_have_count(1)
297
284
  expect(paths).to_have_count(2)
298
- toggle = page.locator("#umap-ui-container").get_by_title("Show/hide layer")
285
+ toggle = page.locator(".umap-browser").get_by_title("Show/hide layer")
299
286
  toggle.click()
300
287
  expect(markers).to_have_count(0)
301
288
  expect(paths).to_have_count(0)
@@ -303,7 +290,7 @@ def test_should_allow_to_toggle_datalayer_visibility(live_server, map, page, boo
303
290
 
304
291
  def test_should_have_edit_buttons_in_edit_mode(live_server, openmap, page, bootstrap):
305
292
  page.goto(f"{live_server.url}{openmap.get_absolute_url()}")
306
- browser = page.locator("#umap-ui-container")
293
+ browser = page.locator(".umap-browser")
307
294
  edit_layer = browser.get_by_title("Edit", exact=True)
308
295
  in_table = browser.get_by_title("Edit properties in a table")
309
296
  delete_layer = browser.get_by_title("Delete layer")
@@ -49,7 +49,7 @@ def test_basic_choropleth_map_with_custom_brewer(openmap, live_server, page):
49
49
  # Now change brewer from UI
50
50
  page.get_by_role("button", name="Edit").click()
51
51
  page.get_by_role("link", name="Manage layers").click()
52
- page.locator("#umap-ui-container").get_by_title("Edit", exact=True).click()
52
+ page.locator(".panel").get_by_title("Edit", exact=True).click()
53
53
  page.get_by_role("heading", name="Choropleth: settings").click()
54
54
  page.locator('select[name="brewer"]').select_option("Greens")
55
55
 
@@ -36,3 +36,13 @@ def test_dashboard_map_preview(map, live_server, datalayer, login):
36
36
  expect(dialog).to_be_visible()
37
37
  # Let's check we have a marker on it, so we can guess the map loaded correctly
38
38
  expect(dialog.locator(".leaflet-marker-icon")).to_be_visible()
39
+
40
+
41
+ def test_no_delete_button_for_editors(map, live_server, datalayer, login, user):
42
+ map.name = "Map I cannot delete"
43
+ map.editors.add(user)
44
+ map.save()
45
+ page = login(user)
46
+ page.goto(f"{live_server.url}/en/me")
47
+ expect(page.get_by_text("Map I cannot delete")).to_be_visible()
48
+ expect(page.get_by_title("Delete")).to_be_hidden()
@@ -20,14 +20,14 @@ def set_options(datalayer, **options):
20
20
 
21
21
  def test_honour_displayOnLoad_false(map, live_server, datalayer, page):
22
22
  set_options(datalayer, displayOnLoad=False)
23
- page.goto(f"{live_server.url}{map.get_absolute_url()}")
23
+ page.goto(f"{live_server.url}{map.get_absolute_url()}?onLoadPanel=datalayers")
24
24
  expect(page.locator(".leaflet-marker-icon")).to_be_hidden()
25
- layers = page.locator(".umap-browse-datalayers li")
25
+ layers = page.locator(".umap-browser .datalayer")
26
26
  markers = page.locator(".leaflet-marker-icon")
27
- layers_off = page.locator(".umap-browse-datalayers li.off")
27
+ layers_off = page.locator(".umap-browser .datalayer.off")
28
28
  expect(layers).to_have_count(1)
29
29
  expect(layers_off).to_have_count(1)
30
- page.get_by_role("button", name="See data layers").click()
30
+ page.get_by_role("button", name="See layers").click()
31
31
  page.get_by_label("Zoom in").click()
32
32
  expect(markers).to_be_hidden()
33
33
  page.get_by_title("Show/hide layer").click()
@@ -109,10 +109,12 @@ def test_should_honour_color_variable(live_server, map, page):
109
109
 
110
110
 
111
111
  def test_datalayers_in_query_string(live_server, datalayer, map, page):
112
+ map.settings["properties"]["onLoadPanel"] = "datalayers"
113
+ map.save()
112
114
  with_old_id = DataLayerFactory(old_id=134, map=map, name="with old id")
113
115
  set_options(with_old_id, name="with old id")
114
- visible = page.locator(".leaflet-control-browse li:not(.off) span")
115
- hidden = page.locator(".leaflet-control-browse li.off span")
116
+ visible = page.locator(".umap-browser .datalayer:not(.off) .datalayer-name")
117
+ hidden = page.locator(".umap-browser .datalayer.off .datalayer-name")
116
118
  page.goto(f"{live_server.url}{map.get_absolute_url()}")
117
119
  expect(visible).to_have_count(2)
118
120
  expect(hidden).to_have_count(0)
@@ -1,3 +1,4 @@
1
+ import platform
1
2
  import re
2
3
 
3
4
  from playwright.sync_api import expect
@@ -11,16 +12,13 @@ def test_should_have_fieldset_for_layer_type_properties(page, live_server, tilel
11
12
  page.goto(f"{live_server.url}/en/map/new/")
12
13
 
13
14
  # Open DataLayers list
14
- button = page.get_by_title("Manage Layers")
15
- expect(button).to_be_visible()
16
- button.click()
15
+ page.get_by_title("Manage layers").click()
17
16
 
18
17
  # Create a layer
19
- page.get_by_title("Manage layers").click()
20
- page.get_by_role("button", name="Add a layer").click()
18
+ page.get_by_title("Add a layer").click()
21
19
  page.locator("input[name=name]").fill("Layer 1")
22
20
 
23
- select = page.locator("#umap-ui-container .umap-field-type select")
21
+ select = page.locator(".panel.on .umap-field-type select")
24
22
  expect(select).to_be_visible()
25
23
 
26
24
  choropleth_header = page.get_by_text("Choropleth: settings")
@@ -56,32 +54,32 @@ def test_cancel_deleting_datalayer_should_restore(
56
54
  live_server, openmap, datalayer, page
57
55
  ):
58
56
  page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
59
- layers = page.locator(".umap-browse-datalayers li")
57
+ page.get_by_title("See layers").click()
58
+ layers = page.locator(".umap-browser .datalayer")
60
59
  markers = page.locator(".leaflet-marker-icon")
61
60
  expect(layers).to_have_count(1)
62
61
  expect(markers).to_have_count(1)
63
62
  page.get_by_role("link", name="Manage layers").click()
64
63
  page.once("dialog", lambda dialog: dialog.accept())
65
- page.locator("#umap-ui-container").get_by_title("Delete layer").click()
64
+ page.locator(".panel.right").get_by_title("Delete layer").click()
66
65
  expect(markers).to_have_count(0)
67
- page.get_by_role("button", name="See data layers").click()
66
+ page.get_by_role("button", name="See layers").click()
68
67
  expect(page.get_by_text("test datalayer")).to_be_hidden()
69
68
  page.once("dialog", lambda dialog: dialog.accept())
70
69
  page.get_by_role("button", name="Cancel edits").click()
71
70
  expect(markers).to_have_count(1)
72
- expect(
73
- page.locator(".leaflet-control-browse").get_by_text("test datalayer")
74
- ).to_be_visible()
71
+ expect(page.locator(".umap-browser").get_by_text("test datalayer")).to_be_visible()
75
72
 
76
73
 
77
74
  def test_can_clone_datalayer(live_server, openmap, login, datalayer, page):
78
75
  page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
79
- layers = page.locator(".umap-browse-datalayers li")
76
+ page.get_by_title("See layers").click()
77
+ layers = page.locator(".umap-browser .datalayer")
80
78
  markers = page.locator(".leaflet-marker-icon")
81
79
  expect(layers).to_have_count(1)
82
80
  expect(markers).to_have_count(1)
83
81
  page.get_by_role("link", name="Manage layers").click()
84
- page.locator("#umap-ui-container").get_by_title("Edit", exact=True).click()
82
+ page.locator(".panel.right").get_by_title("Edit", exact=True).click()
85
83
  page.get_by_role("heading", name="Advanced actions").click()
86
84
  page.get_by_role("button", name="Clone").click()
87
85
  expect(layers).to_have_count(2)
@@ -105,7 +103,7 @@ def test_can_change_icon_class(live_server, openmap, page):
105
103
  expect(page.locator(".umap-div-icon")).to_be_visible()
106
104
  page.get_by_role("link", name="Manage layers").click()
107
105
  expect(page.locator(".umap-circle-icon")).to_be_hidden()
108
- page.locator("#umap-ui-container").get_by_title("Edit", exact=True).click()
106
+ page.locator(".panel.right").get_by_title("Edit", exact=True).click()
109
107
  page.get_by_role("heading", name="Shape properties").click()
110
108
  page.locator(".umap-field-iconClass a.define").click()
111
109
  page.get_by_text("Circle").click()
@@ -118,12 +116,12 @@ def test_can_change_name(live_server, openmap, page, datalayer):
118
116
  f"{live_server.url}{openmap.get_absolute_url()}?edit&datalayersControl=expanded"
119
117
  )
120
118
  page.get_by_role("link", name="Manage layers").click()
121
- page.locator("#umap-ui-container").get_by_title("Edit", exact=True).click()
119
+ page.locator(".panel.right").get_by_title("Edit", exact=True).click()
122
120
  expect(page.locator(".umap-is-dirty")).to_be_hidden()
123
121
  page.locator('input[name="name"]').click()
124
122
  page.locator('input[name="name"]').press("Control+a")
125
123
  page.locator('input[name="name"]').fill("new name")
126
- expect(page.locator(".leaflet-control-browse li span")).to_contain_text("new name")
124
+ expect(page.locator(".umap-browser .datalayer")).to_contain_text("new name")
127
125
  expect(page.locator(".umap-is-dirty")).to_be_visible()
128
126
  with page.expect_response(re.compile(".*/datalayer/update/.*")):
129
127
  page.get_by_role("button", name="Save").click()
@@ -149,7 +147,7 @@ def test_can_create_new_datalayer(live_server, openmap, page, datalayer):
149
147
  expect(page.locator(".umap-is-dirty")).to_be_hidden()
150
148
  # Edit again, it should not create a new datalayer
151
149
  page.get_by_role("link", name="Manage layers").click()
152
- page.locator("#umap-ui-container").get_by_title("Edit", exact=True).first.click()
150
+ page.locator(".panel.right").get_by_title("Edit", exact=True).first.click()
153
151
  page.locator('input[name="name"]').click()
154
152
  page.locator('input[name="name"]').fill("my new layer with a new name")
155
153
  expect(page.get_by_text("my new layer with a new name")).to_be_visible()
@@ -173,8 +171,15 @@ def test_can_restore_version(live_server, openmap, page, datalayer):
173
171
  page.get_by_role("button", name="Save").click()
174
172
  expect(marker).to_have_class(re.compile(".*umap-div-icon.*"))
175
173
  page.get_by_role("link", name="Manage layers").click()
176
- page.locator("#umap-ui-container").get_by_title("Edit", exact=True).click()
174
+ page.locator(".panel.right").get_by_title("Edit", exact=True).click()
177
175
  page.get_by_role("heading", name="Versions").click()
178
176
  page.once("dialog", lambda dialog: dialog.accept())
179
177
  page.get_by_role("button", name="Restore this version").last.click()
180
178
  expect(marker).to_have_class(re.compile(".*umap-ball-icon.*"))
179
+
180
+
181
+ def test_can_edit_layer_on_ctrl_shift_click(live_server, openmap, page, datalayer):
182
+ modifier = "Meta" if platform.system() == "Darwin" else "Control"
183
+ page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
184
+ page.locator(".leaflet-marker-icon").click(modifiers=[modifier, "Shift"])
185
+ expect(page.get_by_role("heading", name="Layer properties")).to_be_visible()