umap-project 2.7.3__py3-none-any.whl → 2.8.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.
Files changed (292) hide show
  1. umap/__init__.py +1 -1
  2. umap/forms.py +4 -14
  3. umap/locale/am_ET/LC_MESSAGES/django.mo +0 -0
  4. umap/locale/am_ET/LC_MESSAGES/django.po +278 -151
  5. umap/locale/ar/LC_MESSAGES/django.mo +0 -0
  6. umap/locale/ar/LC_MESSAGES/django.po +335 -141
  7. umap/locale/bg/LC_MESSAGES/django.mo +0 -0
  8. umap/locale/bg/LC_MESSAGES/django.po +279 -152
  9. umap/locale/br/LC_MESSAGES/django.mo +0 -0
  10. umap/locale/br/LC_MESSAGES/django.po +95 -79
  11. umap/locale/ca/LC_MESSAGES/django.mo +0 -0
  12. umap/locale/ca/LC_MESSAGES/django.po +85 -68
  13. umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  14. umap/locale/cs_CZ/LC_MESSAGES/django.po +78 -66
  15. umap/locale/da/LC_MESSAGES/django.mo +0 -0
  16. umap/locale/da/LC_MESSAGES/django.po +280 -153
  17. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  18. umap/locale/de/LC_MESSAGES/django.po +80 -64
  19. umap/locale/el/LC_MESSAGES/django.mo +0 -0
  20. umap/locale/el/LC_MESSAGES/django.po +82 -66
  21. umap/locale/en/LC_MESSAGES/django.po +73 -61
  22. umap/locale/es/LC_MESSAGES/django.mo +0 -0
  23. umap/locale/es/LC_MESSAGES/django.po +75 -63
  24. umap/locale/et/LC_MESSAGES/django.mo +0 -0
  25. umap/locale/et/LC_MESSAGES/django.po +280 -153
  26. umap/locale/eu/LC_MESSAGES/django.mo +0 -0
  27. umap/locale/eu/LC_MESSAGES/django.po +82 -66
  28. umap/locale/fa_IR/LC_MESSAGES/django.mo +0 -0
  29. umap/locale/fa_IR/LC_MESSAGES/django.po +80 -64
  30. umap/locale/fi/LC_MESSAGES/django.mo +0 -0
  31. umap/locale/fi/LC_MESSAGES/django.po +278 -151
  32. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  33. umap/locale/fr/LC_MESSAGES/django.po +75 -63
  34. umap/locale/gl/LC_MESSAGES/django.mo +0 -0
  35. umap/locale/gl/LC_MESSAGES/django.po +280 -153
  36. umap/locale/he/LC_MESSAGES/django.mo +0 -0
  37. umap/locale/he/LC_MESSAGES/django.po +281 -154
  38. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  39. umap/locale/hu/LC_MESSAGES/django.po +80 -64
  40. umap/locale/is/LC_MESSAGES/django.mo +0 -0
  41. umap/locale/is/LC_MESSAGES/django.po +280 -153
  42. umap/locale/it/LC_MESSAGES/django.mo +0 -0
  43. umap/locale/it/LC_MESSAGES/django.po +82 -66
  44. umap/locale/ja/LC_MESSAGES/django.mo +0 -0
  45. umap/locale/ja/LC_MESSAGES/django.po +280 -153
  46. umap/locale/ko/LC_MESSAGES/django.mo +0 -0
  47. umap/locale/ko/LC_MESSAGES/django.po +280 -153
  48. umap/locale/lt/LC_MESSAGES/django.mo +0 -0
  49. umap/locale/lt/LC_MESSAGES/django.po +280 -153
  50. umap/locale/ms/LC_MESSAGES/django.mo +0 -0
  51. umap/locale/ms/LC_MESSAGES/django.po +82 -66
  52. umap/locale/nl/LC_MESSAGES/django.mo +0 -0
  53. umap/locale/nl/LC_MESSAGES/django.po +280 -153
  54. umap/locale/pl/LC_MESSAGES/django.mo +0 -0
  55. umap/locale/pl/LC_MESSAGES/django.po +82 -66
  56. umap/locale/pt/LC_MESSAGES/django.mo +0 -0
  57. umap/locale/pt/LC_MESSAGES/django.po +75 -63
  58. umap/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  59. umap/locale/pt_BR/LC_MESSAGES/django.po +280 -153
  60. umap/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  61. umap/locale/pt_PT/LC_MESSAGES/django.po +280 -153
  62. umap/locale/ru/LC_MESSAGES/django.mo +0 -0
  63. umap/locale/ru/LC_MESSAGES/django.po +280 -153
  64. umap/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
  65. umap/locale/sk_SK/LC_MESSAGES/django.po +280 -153
  66. umap/locale/sl/LC_MESSAGES/django.mo +0 -0
  67. umap/locale/sl/LC_MESSAGES/django.po +280 -153
  68. umap/locale/sr/LC_MESSAGES/django.mo +0 -0
  69. umap/locale/sr/LC_MESSAGES/django.po +280 -153
  70. umap/locale/sv/LC_MESSAGES/django.mo +0 -0
  71. umap/locale/sv/LC_MESSAGES/django.po +81 -65
  72. umap/locale/th_TH/LC_MESSAGES/django.mo +0 -0
  73. umap/locale/th_TH/LC_MESSAGES/django.po +257 -185
  74. umap/locale/tr/LC_MESSAGES/django.mo +0 -0
  75. umap/locale/tr/LC_MESSAGES/django.po +280 -153
  76. umap/locale/uk_UA/LC_MESSAGES/django.mo +0 -0
  77. umap/locale/uk_UA/LC_MESSAGES/django.po +280 -153
  78. umap/locale/vi/LC_MESSAGES/django.mo +0 -0
  79. umap/locale/vi/LC_MESSAGES/django.po +278 -151
  80. umap/locale/zh/LC_MESSAGES/django.mo +0 -0
  81. umap/locale/zh/LC_MESSAGES/django.po +278 -151
  82. umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
  83. umap/locale/zh_TW/LC_MESSAGES/django.po +97 -81
  84. umap/management/commands/empty_trash.py +35 -0
  85. umap/management/commands/migrate_to_S3.py +29 -0
  86. umap/migrations/0023_alter_datalayer_uuid.py +19 -0
  87. umap/migrations/0024_alter_map_share_status.py +30 -0
  88. umap/migrations/0025_alter_datalayer_geojson.py +24 -0
  89. umap/models.py +68 -116
  90. umap/settings/base.py +23 -3
  91. umap/settings/local_s3.py +45 -0
  92. umap/static/umap/base.css +3 -603
  93. umap/static/umap/content.css +5 -3
  94. umap/static/umap/css/bar.css +202 -0
  95. umap/static/umap/css/form.css +620 -0
  96. umap/static/umap/css/icon.css +21 -1
  97. umap/static/umap/css/popup.css +125 -0
  98. umap/static/umap/img/16-white.svg +16 -4
  99. umap/static/umap/img/16.svg +1 -1
  100. umap/static/umap/img/source/16-white.svg +46 -45
  101. umap/static/umap/img/source/16.svg +1 -753
  102. umap/static/umap/js/components/fragment.js +3 -1
  103. umap/static/umap/js/modules/browser.js +20 -19
  104. umap/static/umap/js/modules/caption.js +21 -22
  105. umap/static/umap/js/modules/data/features.js +120 -78
  106. umap/static/umap/js/modules/data/layer.js +195 -153
  107. umap/static/umap/js/modules/facets.js +9 -9
  108. umap/static/umap/js/modules/formatter.js +5 -5
  109. umap/static/umap/js/modules/global.js +4 -52
  110. umap/static/umap/js/modules/help.js +18 -21
  111. umap/static/umap/js/modules/importer.js +133 -56
  112. umap/static/umap/js/modules/importers/cadastrefr.js +4 -0
  113. umap/static/umap/js/modules/importers/geodatamine.js +3 -3
  114. umap/static/umap/js/modules/importers/overpass.js +5 -0
  115. umap/static/umap/js/modules/permissions.js +85 -87
  116. umap/static/umap/js/modules/rendering/icon.js +2 -1
  117. umap/static/umap/js/modules/rendering/layers/base.js +15 -15
  118. umap/static/umap/js/modules/rendering/layers/classified.js +1 -1
  119. umap/static/umap/js/modules/rendering/layers/cluster.js +1 -1
  120. umap/static/umap/js/modules/rendering/layers/heat.js +1 -1
  121. umap/static/umap/js/modules/rendering/map.js +390 -0
  122. umap/static/umap/js/modules/rendering/popup.js +19 -19
  123. umap/static/umap/js/modules/rendering/template.js +88 -21
  124. umap/static/umap/js/modules/rendering/ui.js +63 -14
  125. umap/static/umap/js/modules/request.js +2 -2
  126. umap/static/umap/js/modules/rules.js +22 -25
  127. umap/static/umap/js/modules/saving.js +47 -0
  128. umap/static/umap/js/modules/schema.js +6 -0
  129. umap/static/umap/js/modules/share.js +21 -24
  130. umap/static/umap/js/modules/slideshow.js +24 -20
  131. umap/static/umap/js/modules/sync/updaters.js +7 -9
  132. umap/static/umap/js/modules/tableeditor.js +20 -19
  133. umap/static/umap/js/modules/ui/bar.js +196 -0
  134. umap/static/umap/js/modules/ui/dialog.js +5 -0
  135. umap/static/umap/js/modules/ui/panel.js +10 -9
  136. umap/static/umap/js/modules/umap.js +1691 -0
  137. umap/static/umap/js/modules/urls.js +2 -2
  138. umap/static/umap/js/modules/utils.js +22 -6
  139. umap/static/umap/js/umap.controls.js +81 -305
  140. umap/static/umap/js/umap.core.js +29 -50
  141. umap/static/umap/js/umap.forms.js +78 -27
  142. umap/static/umap/keycloak.png +0 -0
  143. umap/static/umap/locale/am_ET.js +26 -10
  144. umap/static/umap/locale/am_ET.json +26 -10
  145. umap/static/umap/locale/ar.js +26 -10
  146. umap/static/umap/locale/ar.json +26 -10
  147. umap/static/umap/locale/ast.js +26 -10
  148. umap/static/umap/locale/ast.json +26 -10
  149. umap/static/umap/locale/bg.js +26 -10
  150. umap/static/umap/locale/bg.json +26 -10
  151. umap/static/umap/locale/br.js +27 -20
  152. umap/static/umap/locale/br.json +27 -20
  153. umap/static/umap/locale/ca.js +32 -29
  154. umap/static/umap/locale/ca.json +32 -29
  155. umap/static/umap/locale/cs_CZ.js +24 -17
  156. umap/static/umap/locale/cs_CZ.json +24 -17
  157. umap/static/umap/locale/da.js +26 -10
  158. umap/static/umap/locale/da.json +26 -10
  159. umap/static/umap/locale/de.js +21 -14
  160. umap/static/umap/locale/de.json +21 -14
  161. umap/static/umap/locale/el.js +28 -12
  162. umap/static/umap/locale/el.json +28 -12
  163. umap/static/umap/locale/en.js +14 -9
  164. umap/static/umap/locale/en.json +14 -9
  165. umap/static/umap/locale/en_US.json +26 -10
  166. umap/static/umap/locale/es.js +16 -13
  167. umap/static/umap/locale/es.json +16 -13
  168. umap/static/umap/locale/et.js +26 -10
  169. umap/static/umap/locale/et.json +26 -10
  170. umap/static/umap/locale/eu.js +16 -9
  171. umap/static/umap/locale/eu.json +16 -9
  172. umap/static/umap/locale/fa_IR.js +16 -9
  173. umap/static/umap/locale/fa_IR.json +16 -9
  174. umap/static/umap/locale/fi.js +26 -10
  175. umap/static/umap/locale/fi.json +26 -10
  176. umap/static/umap/locale/fr.js +14 -9
  177. umap/static/umap/locale/fr.json +14 -9
  178. umap/static/umap/locale/gl.js +26 -10
  179. umap/static/umap/locale/gl.json +26 -10
  180. umap/static/umap/locale/he.js +26 -10
  181. umap/static/umap/locale/he.json +26 -10
  182. umap/static/umap/locale/hr.js +26 -10
  183. umap/static/umap/locale/hr.json +26 -10
  184. umap/static/umap/locale/hu.js +16 -9
  185. umap/static/umap/locale/hu.json +16 -9
  186. umap/static/umap/locale/id.js +26 -10
  187. umap/static/umap/locale/id.json +26 -10
  188. umap/static/umap/locale/is.js +26 -10
  189. umap/static/umap/locale/is.json +26 -10
  190. umap/static/umap/locale/it.js +26 -10
  191. umap/static/umap/locale/it.json +26 -10
  192. umap/static/umap/locale/ja.js +26 -10
  193. umap/static/umap/locale/ja.json +26 -10
  194. umap/static/umap/locale/ko.js +26 -10
  195. umap/static/umap/locale/ko.json +26 -10
  196. umap/static/umap/locale/lt.js +26 -10
  197. umap/static/umap/locale/lt.json +26 -10
  198. umap/static/umap/locale/ms.js +28 -12
  199. umap/static/umap/locale/ms.json +28 -12
  200. umap/static/umap/locale/nl.js +28 -12
  201. umap/static/umap/locale/nl.json +28 -12
  202. umap/static/umap/locale/no.js +26 -10
  203. umap/static/umap/locale/no.json +26 -10
  204. umap/static/umap/locale/pl.js +28 -12
  205. umap/static/umap/locale/pl.json +28 -12
  206. umap/static/umap/locale/pl_PL.json +26 -10
  207. umap/static/umap/locale/pt.js +16 -9
  208. umap/static/umap/locale/pt.json +16 -9
  209. umap/static/umap/locale/pt_BR.js +26 -10
  210. umap/static/umap/locale/pt_BR.json +26 -10
  211. umap/static/umap/locale/pt_PT.js +16 -9
  212. umap/static/umap/locale/pt_PT.json +16 -9
  213. umap/static/umap/locale/ro.js +26 -10
  214. umap/static/umap/locale/ro.json +26 -10
  215. umap/static/umap/locale/ru.js +26 -10
  216. umap/static/umap/locale/ru.json +26 -10
  217. umap/static/umap/locale/si.js +7 -7
  218. umap/static/umap/locale/si.json +7 -7
  219. umap/static/umap/locale/sk_SK.js +26 -10
  220. umap/static/umap/locale/sk_SK.json +26 -10
  221. umap/static/umap/locale/sl.js +26 -10
  222. umap/static/umap/locale/sl.json +26 -10
  223. umap/static/umap/locale/sr.js +26 -10
  224. umap/static/umap/locale/sr.json +26 -10
  225. umap/static/umap/locale/sv.js +27 -11
  226. umap/static/umap/locale/sv.json +27 -11
  227. umap/static/umap/locale/th_TH.js +28 -12
  228. umap/static/umap/locale/th_TH.json +28 -12
  229. umap/static/umap/locale/tr.js +26 -10
  230. umap/static/umap/locale/tr.json +26 -10
  231. umap/static/umap/locale/uk_UA.js +26 -10
  232. umap/static/umap/locale/uk_UA.json +26 -10
  233. umap/static/umap/locale/vi.js +26 -10
  234. umap/static/umap/locale/vi.json +26 -10
  235. umap/static/umap/locale/vi_VN.json +26 -10
  236. umap/static/umap/locale/zh.js +26 -10
  237. umap/static/umap/locale/zh.json +26 -10
  238. umap/static/umap/locale/zh_CN.json +26 -10
  239. umap/static/umap/locale/zh_TW.Big5.json +26 -10
  240. umap/static/umap/locale/zh_TW.js +34 -27
  241. umap/static/umap/locale/zh_TW.json +34 -27
  242. umap/static/umap/map.css +39 -530
  243. umap/static/umap/unittests/URLs.js +15 -15
  244. umap/static/umap/unittests/utils.js +23 -1
  245. umap/static/umap/vars.css +2 -1
  246. umap/static/umap/vendors/formbuilder/Leaflet.FormBuilder.js +5 -1
  247. umap/storage/__init__.py +3 -0
  248. umap/storage/fs.py +101 -0
  249. umap/storage/s3.py +61 -0
  250. umap/templates/base.html +2 -0
  251. umap/templates/registration/login.html +7 -6
  252. umap/templates/umap/components/alerts/alert.html +4 -0
  253. umap/templates/umap/css.html +6 -0
  254. umap/templates/umap/js.html +3 -2
  255. umap/templates/umap/map_init.html +6 -5
  256. umap/templates/umap/user_dashboard.html +20 -19
  257. umap/tests/base.py +5 -1
  258. umap/tests/fixtures/test_upload_simple_marker.json +19 -0
  259. umap/tests/integration/conftest.py +2 -1
  260. umap/tests/integration/test_anonymous_owned_map.py +18 -10
  261. umap/tests/integration/test_browser.py +16 -1
  262. umap/tests/integration/test_dashboard.py +1 -1
  263. umap/tests/integration/test_edit_datalayer.py +29 -7
  264. umap/tests/integration/test_import.py +28 -6
  265. umap/tests/integration/test_optimistic_merge.py +31 -8
  266. umap/tests/integration/test_owned_map.py +22 -16
  267. umap/tests/integration/test_popup.py +44 -0
  268. umap/tests/integration/test_save.py +35 -0
  269. umap/tests/integration/test_view_marker.py +12 -0
  270. umap/tests/integration/test_view_polyline.py +257 -0
  271. umap/tests/integration/test_websocket_sync.py +81 -9
  272. umap/tests/test_dashboard.py +82 -0
  273. umap/tests/test_datalayer.py +6 -7
  274. umap/tests/test_datalayer_s3.py +135 -0
  275. umap/tests/test_datalayer_views.py +28 -10
  276. umap/tests/test_empty_trash.py +34 -0
  277. umap/tests/test_map.py +12 -3
  278. umap/tests/test_map_views.py +69 -37
  279. umap/tests/test_statics.py +1 -1
  280. umap/tests/test_team_views.py +35 -1
  281. umap/tests/test_views.py +31 -52
  282. umap/urls.py +3 -3
  283. umap/views.py +126 -90
  284. {umap_project-2.7.3.dist-info → umap_project-2.8.0.dist-info}/METADATA +16 -13
  285. {umap_project-2.7.3.dist-info → umap_project-2.8.0.dist-info}/RECORD +289 -269
  286. umap/management/commands/purge_purgatory.py +0 -28
  287. umap/static/umap/js/umap.js +0 -1903
  288. umap/tests/test_purge_purgatory.py +0 -25
  289. /umap/{storage.py → storage/staticfiles.py} +0 -0
  290. {umap_project-2.7.3.dist-info → umap_project-2.8.0.dist-info}/WHEEL +0 -0
  291. {umap_project-2.7.3.dist-info → umap_project-2.8.0.dist-info}/entry_points.txt +0 -0
  292. {umap_project-2.7.3.dist-info → umap_project-2.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -120,7 +120,7 @@ def test_can_change_name(live_server, openmap, page, datalayer):
120
120
  page.locator('input[name="name"]').press("Control+a")
121
121
  page.locator('input[name="name"]').fill("new name")
122
122
  expect(page.locator(".umap-browser .datalayer")).to_contain_text("new name")
123
- expect(page.locator(".umap-is-dirty")).to_be_visible()
123
+ expect(page.locator("body")).to_have_class(re.compile(".*umap-is-dirty.*"))
124
124
  with page.expect_response(re.compile(".*/datalayer/update/.*")):
125
125
  page.get_by_role("button", name="Save").click()
126
126
  saved = DataLayer.objects.last()
@@ -129,32 +129,43 @@ def test_can_change_name(live_server, openmap, page, datalayer):
129
129
 
130
130
 
131
131
  def test_can_create_new_datalayer(live_server, openmap, page, datalayer):
132
+ """
133
+ Test the creation and editing of a new datalayer.
134
+
135
+ This test verifies that:
136
+ 1. A new datalayer can be created and saved.
137
+ 2. The newly created datalayer appears in the UI and is saved in the database.
138
+ 3. Editing the same datalayer updates it instead of creating a new one.
139
+ 4. The UI reflects the changes and the database is updated correctly.
140
+ 5. The 'dirty' state of the map is managed correctly during these operations.
141
+ """
142
+
132
143
  page.goto(
133
144
  f"{live_server.url}{openmap.get_absolute_url()}?edit&onLoadPanel=databrowser"
134
145
  )
135
146
  page.get_by_role("link", name="Manage layers").click()
136
147
  page.get_by_role("button", name="Add a layer").click()
137
148
  page.locator('input[name="name"]').click()
138
- page.locator('input[name="name"]').fill("my new layer")
139
- expect(page.get_by_text("my new layer")).to_be_visible()
149
+ page.locator('input[name="name"]').fill("Layer A")
150
+ expect(page.get_by_text("Layer A")).to_be_visible()
140
151
  with page.expect_response(re.compile(".*/datalayer/create/.*")):
141
152
  page.get_by_role("button", name="Save").click()
142
153
  assert DataLayer.objects.count() == 2
143
154
  saved = DataLayer.objects.last()
144
- assert saved.name == "my new layer"
155
+ assert saved.name == "Layer A"
145
156
  expect(page.locator(".umap-is-dirty")).to_be_hidden()
146
157
  # Edit again, it should not create a new datalayer
147
158
  page.get_by_role("link", name="Manage layers").click()
148
159
  page.locator(".panel.right").get_by_title("Edit", exact=True).first.click()
149
160
  page.locator('input[name="name"]').click()
150
- page.locator('input[name="name"]').fill("my new layer with a new name")
151
- expect(page.get_by_text("my new layer with a new name")).to_be_visible()
161
+ page.locator('input[name="name"]').fill("Layer A with a new name")
162
+ expect(page.get_by_text("Layer A with a new name")).to_be_visible()
152
163
  page.get_by_role("button", name="Save").click()
153
164
  with page.expect_response(re.compile(".*/datalayer/update/.*")):
154
165
  page.get_by_role("button", name="Save").click()
155
166
  assert DataLayer.objects.count() == 2
156
167
  saved = DataLayer.objects.last()
157
- assert saved.name == "my new layer with a new name"
168
+ assert saved.name == "Layer A with a new name"
158
169
  expect(page.locator(".umap-is-dirty")).to_be_hidden()
159
170
 
160
171
 
@@ -210,3 +221,14 @@ def test_deleting_datalayer_should_remove_from_caption(
210
221
  page.locator(".panel.right").get_by_title("Delete layer").click()
211
222
  page.get_by_role("button", name="OK").click()
212
223
  expect(panel.get_by_text("test datalayer")).to_be_hidden()
224
+
225
+
226
+ def test_can_edit_datalayer_name_in_list(live_server, openmap, datalayer, page):
227
+ page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
228
+ page.get_by_role("link", name="Manage layers").click()
229
+ page.get_by_text("test datalayer").click()
230
+ page.get_by_text("test datalayer").fill("test datalayer foobar")
231
+ page.get_by_role("button", name="Open browser").click()
232
+ expect(
233
+ page.locator(".panel.left").get_by_text("test datalayer foobar")
234
+ ).to_be_visible()
@@ -9,7 +9,6 @@ from playwright.sync_api import expect
9
9
 
10
10
  from umap.models import DataLayer
11
11
 
12
- from ..base import mock_tiles
13
12
  from .helpers import save_and_get_json
14
13
 
15
14
  pytestmark = pytest.mark.django_db
@@ -71,9 +70,8 @@ def test_umap_import_from_file(live_server, tilelayer, page):
71
70
  expect(nonloaded).to_have_count(1)
72
71
 
73
72
 
73
+ @pytest.mark.skip
74
74
  def test_umap_import_from_textarea(live_server, tilelayer, page, settings):
75
- page.route("https://tile.openstreetmap.fr/hot/**", mock_tiles)
76
-
77
75
  settings.UMAP_ALLOW_ANONYMOUS = True
78
76
  page.goto(f"{live_server.url}/map/new/")
79
77
  page.get_by_role("button", name="Open browser").click()
@@ -94,11 +92,11 @@ def test_umap_import_from_textarea(live_server, tilelayer, page, settings):
94
92
  expect(
95
93
  page.locator('img[src="https://tile.openstreetmap.fr/hot/6/32/21.png"]')
96
94
  ).to_be_visible()
97
- # Should not have imported umap_id, while in the file options
98
- assert not page.evaluate("U.MAP.options.umap_id")
95
+ # Should not have imported id, while in the file options
96
+ assert not page.evaluate("U.MAP.properties.id")
99
97
  with page.expect_response(re.compile(r".*/datalayer/create/.*")):
100
98
  page.get_by_role("button", name="Save").click()
101
- assert page.evaluate("U.MAP.options.umap_id")
99
+ assert page.evaluate("U.MAP.properties.id")
102
100
 
103
101
 
104
102
  def test_import_geojson_from_textarea(tilelayer, live_server, page):
@@ -607,6 +605,7 @@ def test_overpass_import_with_bbox(page, live_server, tilelayer, settings):
607
605
  }
608
606
  page.goto(f"{live_server.url}/map/new/")
609
607
  page.get_by_role("link", name="Import data").click()
608
+ page.get_by_role("button", name="Import helpers").click()
610
609
  page.get_by_role("button", name="Overpass").click()
611
610
  page.get_by_placeholder("amenity=drinking_water").fill("building")
612
611
  page.get_by_role("button", name="Choose this data").click()
@@ -657,6 +656,7 @@ def test_overpass_import_retains_boundary(page, live_server, tilelayer, settings
657
656
  page.route(re.compile("https://foobar.io/api.*"), handle)
658
657
  page.goto(f"{live_server.url}/map/new/")
659
658
  page.get_by_role("link", name="Import data").click()
659
+ page.get_by_role("button", name="Import helpers").click()
660
660
  page.get_by_role("button", name="Overpass").click()
661
661
  page.get_by_placeholder("amenity=drinking_water").fill("building")
662
662
  page.get_by_placeholder("Type area name, or let empty").click()
@@ -669,6 +669,7 @@ def test_overpass_import_retains_boundary(page, live_server, tilelayer, settings
669
669
  expect(page.get_by_placeholder("Provide an URL here")).to_have_value(
670
670
  "https://my.overpass.io/interpreter?data=[out:json];nwr[building](area:3601393025);out geom;"
671
671
  )
672
+ page.get_by_role("button", name="Import helpers").click()
672
673
  page.get_by_role("button", name="Overpass").click()
673
674
  expect(page.locator("#area")).to_contain_text(
674
675
  "Bray-sur-Seine, Seine-et-Marne, Île-de-France, France"
@@ -710,6 +711,7 @@ def test_import_from_datasets(page, live_server, tilelayer, settings):
710
711
  page.goto(f"{live_server.url}/map/new/")
711
712
  expect(page.locator(".leaflet-marker-icon")).to_be_hidden()
712
713
  page.get_by_role("link", name="Import data").click()
714
+ page.get_by_role("button", name="Import helpers").click()
713
715
  page.get_by_role("button", name="Datasets").click()
714
716
  page.get_by_role("dialog").get_by_role("combobox").select_option(
715
717
  "https://remote.org/data.json"
@@ -762,3 +764,23 @@ def test_import_georss_from_textarea(tilelayer, live_server, page):
762
764
  # A layer has been created
763
765
  expect(layers).to_have_count(1)
764
766
  expect(markers).to_have_count(1)
767
+
768
+
769
+ def test_import_from_multiple_files(live_server, page, tilelayer):
770
+ page.goto(f"{live_server.url}/map/new/")
771
+ page.get_by_title("Import data").click()
772
+ file_input = page.locator("input[type='file']")
773
+ with page.expect_file_chooser() as fc_info:
774
+ file_input.click()
775
+ file_chooser = fc_info.value
776
+ FIXTURES = Path(__file__).parent.parent / "fixtures"
777
+ paths = [
778
+ FIXTURES / "test_upload_data.json",
779
+ FIXTURES / "test_upload_simple_marker.json",
780
+ ]
781
+ file_chooser.set_files(paths)
782
+ markers = page.locator(".leaflet-marker-icon")
783
+ expect(markers).to_have_count(0)
784
+ page.get_by_role("button", name="Import data", exact=True).click()
785
+ # Two in one file, one in the other
786
+ expect(markers).to_have_count(3)
@@ -49,6 +49,7 @@ def test_created_markers_are_merged(context, live_server, tilelayer):
49
49
  "name": "test datalayer",
50
50
  "editMode": "advanced",
51
51
  "inCaption": True,
52
+ "id": str(datalayer.pk),
52
53
  }
53
54
 
54
55
  # Now navigate to this map from another tab
@@ -78,12 +79,14 @@ def test_created_markers_are_merged(context, live_server, tilelayer):
78
79
  sleep(1)
79
80
  # No change after the save
80
81
  expect(marker_pane_p2).to_have_count(2)
81
- assert DataLayer.objects.get(pk=datalayer.pk).settings == {
82
+ datalayer_v2 = DataLayer.objects.get(pk=datalayer.pk)
83
+ assert datalayer_v2.settings == {
82
84
  "browsable": True,
83
85
  "displayOnLoad": True,
84
86
  "name": "test datalayer",
85
87
  "inCaption": True,
86
88
  "editMode": "advanced",
89
+ "id": str(datalayer.pk),
87
90
  }
88
91
 
89
92
  # Now create another marker in the first tab
@@ -94,7 +97,8 @@ def test_created_markers_are_merged(context, live_server, tilelayer):
94
97
  save_p1.click()
95
98
  # Should now get the other marker too
96
99
  expect(marker_pane_p1).to_have_count(3)
97
- assert DataLayer.objects.get(pk=datalayer.pk).settings == {
100
+ datalayer_v3 = DataLayer.objects.get(pk=datalayer.pk)
101
+ assert datalayer_v3.settings == {
98
102
  "browsable": True,
99
103
  "displayOnLoad": True,
100
104
  "name": "test datalayer",
@@ -112,7 +116,8 @@ def test_created_markers_are_merged(context, live_server, tilelayer):
112
116
  save_p1.click()
113
117
  sleep(1)
114
118
  # Should now get the other marker too
115
- assert DataLayer.objects.get(pk=datalayer.pk).settings == {
119
+ datalayer_v4 = DataLayer.objects.get(pk=datalayer.pk)
120
+ assert datalayer_v4.settings == {
116
121
  "browsable": True,
117
122
  "displayOnLoad": True,
118
123
  "name": "test datalayer",
@@ -132,7 +137,8 @@ def test_created_markers_are_merged(context, live_server, tilelayer):
132
137
  save_p2.click()
133
138
  sleep(1)
134
139
  # Should now get the other markers too
135
- assert DataLayer.objects.get(pk=datalayer.pk).settings == {
140
+ datalayer_v5 = DataLayer.objects.get(pk=datalayer.pk)
141
+ assert datalayer_v5.settings == {
136
142
  "browsable": True,
137
143
  "displayOnLoad": True,
138
144
  "name": "test datalayer",
@@ -276,21 +282,38 @@ def test_should_display_alert_on_conflict(context, live_server, datalayer, openm
276
282
  page_two = context.new_page()
277
283
  page_two.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
278
284
 
285
+ # Change name on page one and save
279
286
  page_one.locator(".leaflet-marker-icon").click(modifiers=["Shift"])
280
- page_one.locator('input[name="name"]').fill("new name")
287
+ page_one.locator('input[name="name"]').fill("name from page one")
281
288
  with page_one.expect_response(re.compile(r".*/datalayer/update/.*")):
282
289
  page_one.get_by_role("button", name="Save").click()
283
290
 
291
+ # Change name on page two and save
284
292
  page_two.locator(".leaflet-marker-icon").click(modifiers=["Shift"])
285
- page_two.locator('input[name="name"]').fill("custom name")
293
+ page_two.locator('input[name="name"]').fill("name from page two")
294
+
295
+ # Map should be in dirty status
296
+ expect(page_two.get_by_text("Cancel edits")).to_be_visible()
286
297
  with page_two.expect_response(re.compile(r".*/datalayer/update/.*")):
287
298
  page_two.get_by_role("button", name="Save").click()
299
+
300
+ # Make sure data is unchanged on the server
288
301
  saved = DataLayer.objects.last()
289
302
  data = json.loads(Path(saved.geojson.path).read_text())
290
- assert data["features"][0]["properties"]["name"] == "new name"
303
+ assert data["features"][0]["properties"]["name"] == "name from page one"
304
+
305
+ # We should have an alert with some actions
291
306
  expect(page_two.get_by_text("Whoops! Other contributor(s) changed")).to_be_visible()
307
+ # Map should still be in dirty status
308
+ expect(page_two.get_by_text("Cancel edits")).to_be_visible()
309
+
310
+ # Override data from page two
292
311
  with page_two.expect_response(re.compile(r".*/datalayer/update/.*")):
293
312
  page_two.get_by_text("Keep your changes and loose theirs").click()
313
+
314
+ # Make sure server has page two data
294
315
  saved = DataLayer.objects.last()
295
316
  data = json.loads(Path(saved.geojson.path).read_text())
296
- assert data["features"][0]["properties"]["name"] == "custom name"
317
+ assert data["features"][0]["properties"]["name"] == "name from page two"
318
+ # Map should not be in dirty status anymore
319
+ expect(page_two.get_by_text("Cancel edits")).to_be_hidden()
@@ -61,8 +61,12 @@ def test_owner_permissions_form(map, datalayer, live_server, login):
61
61
  edit_permissions = page.get_by_title("Update permissions and editors")
62
62
  expect(edit_permissions).to_be_visible()
63
63
  edit_permissions.click()
64
- select = page.locator(".umap-field-share_status select")
65
- expect(select).to_be_visible()
64
+ expect(page.locator(".umap-field-share_status select")).to_be_visible()
65
+ options = [
66
+ int(option.get_attribute("value"))
67
+ for option in page.locator(".umap-field-share_status select option").all()
68
+ ]
69
+ assert options == [Map.DRAFT, Map.PUBLIC, Map.OPEN, Map.PRIVATE]
66
70
  # expect(select).to_have_value(Map.PUBLIC) # Does not work
67
71
  owner_field = page.locator(".umap-field-owner")
68
72
  expect(owner_field).to_be_visible()
@@ -137,7 +141,7 @@ def test_owner_has_delete_map_button(map, live_server, login):
137
141
  delete.click()
138
142
  with page.expect_navigation():
139
143
  page.get_by_role("button", name="OK").click()
140
- assert Map.objects.all().count() == 0
144
+ assert Map.objects.get(pk=map.pk).share_status == Map.DELETED
141
145
 
142
146
 
143
147
  def test_editor_do_not_have_delete_map_button(map, live_server, login, user):
@@ -181,29 +185,31 @@ def test_can_change_perms_after_create(tilelayer, live_server, login, user):
181
185
  page.get_by_title("Manage layers").click()
182
186
  page.get_by_title("Add a layer").click()
183
187
  page.locator("input[name=name]").fill("Layer 1")
184
- save = page.get_by_role("button", name="Save")
185
- expect(save).to_be_visible()
188
+ expect(
189
+ page.get_by_role("button", name="Visibility: Draft (private)")
190
+ ).to_be_visible()
191
+ expect(page.get_by_role("button", name="Save", exact=True)).to_be_hidden()
186
192
  with page.expect_response(re.compile(r".*/map/create/")):
187
- save.click()
193
+ page.get_by_role("button", name="Save draft", exact=True).click()
188
194
  edit_permissions = page.get_by_title("Update permissions and editors")
189
195
  expect(edit_permissions).to_be_visible()
190
196
  edit_permissions.click()
191
- select = page.locator(".umap-field-share_status select")
192
- expect(select).to_be_visible()
193
- option = page.locator("select[name='share_status'] option:checked")
194
- expect(option).to_have_text("Everyone (public)")
195
- owner_field = page.locator(".umap-field-owner")
196
- expect(owner_field).to_be_visible()
197
- editors_field = page.locator(".umap-field-editors input")
198
- expect(editors_field).to_be_visible()
199
- datalayer_label = page.get_by_text('Who can edit "Layer 1"')
200
- expect(datalayer_label).to_be_visible()
197
+ expect(page.locator(".umap-field-share_status select")).to_be_visible()
198
+ expect(page.locator("select[name='share_status'] option:checked")).to_have_text(
199
+ "Draft (private)"
200
+ )
201
+ expect(page.locator(".umap-field-owner")).to_be_visible()
202
+ expect(page.locator(".umap-field-editors input")).to_be_visible()
203
+ expect(page.get_by_text('Who can edit "Layer 1"')).to_be_visible()
201
204
  options = page.locator(".datalayer-permissions select[name='edit_status'] option")
202
205
  expect(options).to_have_count(4)
203
206
  option = page.locator(
204
207
  ".datalayer-permissions select[name='edit_status'] option:checked"
205
208
  )
206
209
  expect(option).to_have_text("Inherit")
210
+ page.locator('select[name="share_status"]').select_option("1")
211
+ expect(page.get_by_role("button", name="Save draft", exact=True)).to_be_hidden()
212
+ expect(page.get_by_role("button", name="Save", exact=True)).to_be_visible()
207
213
 
208
214
 
209
215
  def test_can_change_owner(map, live_server, login, user):
@@ -0,0 +1,44 @@
1
+ import pytest
2
+ from playwright.sync_api import expect
3
+
4
+ from ..base import DataLayerFactory
5
+
6
+ pytestmark = pytest.mark.django_db
7
+
8
+ OSM_DATA = {
9
+ "type": "FeatureCollection",
10
+ "features": [
11
+ {
12
+ "type": "Feature",
13
+ "geometry": {"type": "Point", "coordinates": [2.49, 48.79]},
14
+ "properties": {
15
+ "amenity": "restaurant",
16
+ "cuisine": "italian",
17
+ "name": "A Casa di Nonna",
18
+ "panoramax": "d811b398-d930-4cf8-95a2-0c29c34d9fca",
19
+ "phone": "+33 1 48 89 54 12",
20
+ "takeaway:covid19": "yes",
21
+ "wheelchair": "no",
22
+ "id": "node/1130849864",
23
+ },
24
+ "id": "AzMjk",
25
+ },
26
+ ],
27
+ "_umap_options": {
28
+ "popupTemplate": "OSM",
29
+ },
30
+ }
31
+
32
+
33
+ def test_openstreetmap_popup(live_server, map, page):
34
+ DataLayerFactory(map=map, data=OSM_DATA)
35
+ page.goto(f"{live_server.url}{map.get_absolute_url()}#18/48.79/2.49")
36
+ expect(page.locator(".umap-icon-active")).to_be_hidden()
37
+ page.locator(".leaflet-marker-icon").click()
38
+ expect(page.get_by_role("heading", name="A Casa di Nonna")).to_be_visible()
39
+ expect(page.get_by_text("+33 1 48 89 54 12")).to_be_visible()
40
+ img = page.locator(".umap-popup-content img")
41
+ expect(img).to_have_attribute(
42
+ "src",
43
+ "https://api.panoramax.xyz/api/pictures/d811b398-d930-4cf8-95a2-0c29c34d9fca/sd.jpg",
44
+ )
@@ -0,0 +1,35 @@
1
+ import re
2
+
3
+
4
+ def test_reseting_map_would_remove_from_save_queue(
5
+ live_server, openmap, page, datalayer
6
+ ):
7
+ page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
8
+ page.get_by_role("link", name="Edit map name and caption").click()
9
+ requests = []
10
+
11
+ def register_request(request):
12
+ if request.url.endswith(".png"):
13
+ return
14
+ requests.append((request.method, request.url))
15
+
16
+ page.on("request", register_request)
17
+ page.locator('input[name="name"]').click()
18
+ page.locator('input[name="name"]').fill("new name")
19
+ page.get_by_role("button", name="Cancel edits").click()
20
+ page.get_by_role("button", name="OK").click()
21
+ page.wait_for_timeout(500)
22
+ page.get_by_role("button", name="Edit").click()
23
+ page.get_by_role("link", name="Manage layers").click()
24
+ page.get_by_role("button", name="Edit", exact=True).click()
25
+ page.locator('input[name="name"]').click()
26
+ page.locator('input[name="name"]').fill("new datalayer name")
27
+ with page.expect_response(re.compile(".*/datalayer/update/.*")):
28
+ page.get_by_role("button", name="Save").click()
29
+ assert len(requests) == 1
30
+ assert requests == [
31
+ (
32
+ "POST",
33
+ f"{live_server.url}/en/map/{openmap.pk}/datalayer/update/{datalayer.pk}/",
34
+ ),
35
+ ]
@@ -57,6 +57,18 @@ def test_should_handle_locale_var_in_description(live_server, map, page):
57
57
  expect(link).to_have_attribute("href", "https://domain.org/?locale=en")
58
58
 
59
59
 
60
+ def test_should_use_custom_label_key_in_popup_default_template(live_server, map, page):
61
+ data = deepcopy(DATALAYER_DATA)
62
+ data["features"][0]["properties"] = {
63
+ "libellé": "my custom label",
64
+ }
65
+ data["_umap_options"] = {"labelKey": "libellé"}
66
+ DataLayerFactory(map=map, data=data)
67
+ page.goto(f"{live_server.url}{map.get_absolute_url()}")
68
+ page.locator(".leaflet-marker-icon").click()
69
+ expect(page.locator(".umap-popup h4")).to_have_text("my custom label")
70
+
71
+
60
72
  def test_should_display_tooltip_with_variable(live_server, map, page, bootstrap):
61
73
  map.settings["properties"]["showLabel"] = True
62
74
  map.settings["properties"]["labelKey"] = "Foo {name}"