umap-project 2.9.2__py3-none-any.whl → 3.0.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 (222) hide show
  1. umap/__init__.py +1 -1
  2. umap/context_processors.py +1 -0
  3. umap/forms.py +1 -2
  4. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  5. umap/locale/de/LC_MESSAGES/django.po +218 -96
  6. umap/locale/en/LC_MESSAGES/django.po +131 -55
  7. umap/locale/et/LC_MESSAGES/django.mo +0 -0
  8. umap/locale/et/LC_MESSAGES/django.po +175 -130
  9. umap/locale/eu/LC_MESSAGES/django.mo +0 -0
  10. umap/locale/eu/LC_MESSAGES/django.po +117 -72
  11. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  12. umap/locale/fr/LC_MESSAGES/django.po +132 -56
  13. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  14. umap/locale/hu/LC_MESSAGES/django.po +209 -88
  15. umap/locale/is/LC_MESSAGES/django.mo +0 -0
  16. umap/locale/is/LC_MESSAGES/django.po +296 -175
  17. umap/middleware.py +2 -1
  18. umap/migrations/0027_map_tags.py +23 -0
  19. umap/models.py +13 -2
  20. umap/settings/base.py +23 -5
  21. umap/static/umap/base.css +41 -8
  22. umap/static/umap/content.css +72 -37
  23. umap/static/umap/css/bar.css +43 -21
  24. umap/static/umap/css/dialog.css +4 -1
  25. umap/static/umap/css/form.css +40 -27
  26. umap/static/umap/css/icon.css +11 -1
  27. umap/static/umap/css/importers.css +7 -0
  28. umap/static/umap/img/16-white.svg +23 -2
  29. umap/static/umap/img/16.svg +1 -1
  30. umap/static/umap/img/24.svg +4 -4
  31. umap/static/umap/img/home.svg +7 -0
  32. umap/static/umap/img/importers/banfr.svg +1 -0
  33. umap/static/umap/img/marker.svg +2 -5
  34. umap/static/umap/img/source/16-white.svg +24 -3
  35. umap/static/umap/img/source/16.svg +1 -1
  36. umap/static/umap/img/source/24.svg +5 -5
  37. umap/static/umap/img/target.svg +1 -0
  38. umap/static/umap/js/components/alerts/alert.js +0 -1
  39. umap/static/umap/js/modules/browser.js +4 -4
  40. umap/static/umap/js/modules/caption.js +1 -1
  41. umap/static/umap/js/modules/data/features.js +25 -25
  42. umap/static/umap/js/modules/data/layer.js +91 -97
  43. umap/static/umap/js/modules/facets.js +9 -5
  44. umap/static/umap/js/modules/form/builder.js +21 -29
  45. umap/static/umap/js/modules/form/fields.js +40 -14
  46. umap/static/umap/js/modules/formatter.js +1 -1
  47. umap/static/umap/js/modules/global.js +9 -5
  48. umap/static/umap/js/modules/help.js +18 -5
  49. umap/static/umap/js/modules/importer.js +5 -2
  50. umap/static/umap/js/modules/importers/banfr.js +93 -0
  51. umap/static/umap/js/modules/importers/cadastrefr.js +2 -2
  52. umap/static/umap/js/modules/importers/communesfr.js +1 -1
  53. umap/static/umap/js/modules/permissions.js +20 -10
  54. umap/static/umap/js/modules/rendering/icon.js +15 -2
  55. umap/static/umap/js/modules/rendering/layers/classified.js +7 -7
  56. umap/static/umap/js/modules/rendering/layers/cluster.js +2 -2
  57. umap/static/umap/js/modules/rendering/layers/heat.js +4 -4
  58. umap/static/umap/js/modules/rendering/map.js +14 -6
  59. umap/static/umap/js/modules/rendering/popup.js +2 -2
  60. umap/static/umap/js/modules/rendering/template.js +3 -3
  61. umap/static/umap/js/modules/rendering/ui.js +17 -11
  62. umap/static/umap/js/modules/rules.js +13 -16
  63. umap/static/umap/js/modules/schema.js +23 -1
  64. umap/static/umap/js/modules/share.js +1 -1
  65. umap/static/umap/js/modules/slideshow.js +1 -0
  66. umap/static/umap/js/modules/sync/engine.js +141 -19
  67. umap/static/umap/js/modules/sync/undo.js +101 -0
  68. umap/static/umap/js/modules/sync/updaters.js +51 -28
  69. umap/static/umap/js/modules/tableeditor.js +1 -1
  70. umap/static/umap/js/modules/ui/bar.js +61 -21
  71. umap/static/umap/js/modules/ui/tooltip.js +1 -1
  72. umap/static/umap/js/modules/umap.js +190 -176
  73. umap/static/umap/js/modules/utils.js +30 -4
  74. umap/static/umap/js/umap.controls.js +82 -38
  75. umap/static/umap/locale/am_ET.js +13 -7
  76. umap/static/umap/locale/am_ET.json +13 -7
  77. umap/static/umap/locale/ar.js +13 -7
  78. umap/static/umap/locale/ar.json +13 -7
  79. umap/static/umap/locale/ast.js +13 -7
  80. umap/static/umap/locale/ast.json +13 -7
  81. umap/static/umap/locale/bg.js +13 -7
  82. umap/static/umap/locale/bg.json +13 -7
  83. umap/static/umap/locale/br.js +13 -8
  84. umap/static/umap/locale/br.json +13 -8
  85. umap/static/umap/locale/ca.js +13 -7
  86. umap/static/umap/locale/ca.json +13 -7
  87. umap/static/umap/locale/cs_CZ.js +26 -20
  88. umap/static/umap/locale/cs_CZ.json +26 -20
  89. umap/static/umap/locale/da.js +13 -7
  90. umap/static/umap/locale/da.json +13 -7
  91. umap/static/umap/locale/de.js +47 -41
  92. umap/static/umap/locale/de.json +47 -41
  93. umap/static/umap/locale/el.js +13 -7
  94. umap/static/umap/locale/el.json +13 -7
  95. umap/static/umap/locale/en.js +12 -7
  96. umap/static/umap/locale/en.json +12 -7
  97. umap/static/umap/locale/en_US.json +13 -7
  98. umap/static/umap/locale/es.js +19 -13
  99. umap/static/umap/locale/es.json +19 -13
  100. umap/static/umap/locale/et.js +13 -7
  101. umap/static/umap/locale/et.json +13 -7
  102. umap/static/umap/locale/eu.js +43 -37
  103. umap/static/umap/locale/eu.json +43 -37
  104. umap/static/umap/locale/fa_IR.js +13 -7
  105. umap/static/umap/locale/fa_IR.json +13 -7
  106. umap/static/umap/locale/fi.js +13 -7
  107. umap/static/umap/locale/fi.json +13 -7
  108. umap/static/umap/locale/fr.js +12 -7
  109. umap/static/umap/locale/fr.json +12 -7
  110. umap/static/umap/locale/gl.js +19 -13
  111. umap/static/umap/locale/gl.json +19 -13
  112. umap/static/umap/locale/he.js +13 -7
  113. umap/static/umap/locale/he.json +13 -7
  114. umap/static/umap/locale/hr.js +13 -7
  115. umap/static/umap/locale/hr.json +13 -7
  116. umap/static/umap/locale/hu.js +25 -19
  117. umap/static/umap/locale/hu.json +25 -19
  118. umap/static/umap/locale/id.js +13 -7
  119. umap/static/umap/locale/id.json +13 -7
  120. umap/static/umap/locale/is.js +151 -145
  121. umap/static/umap/locale/is.json +151 -145
  122. umap/static/umap/locale/it.js +13 -7
  123. umap/static/umap/locale/it.json +13 -7
  124. umap/static/umap/locale/ja.js +13 -7
  125. umap/static/umap/locale/ja.json +13 -7
  126. umap/static/umap/locale/ko.js +13 -7
  127. umap/static/umap/locale/ko.json +13 -7
  128. umap/static/umap/locale/lt.js +13 -7
  129. umap/static/umap/locale/lt.json +13 -7
  130. umap/static/umap/locale/ms.js +13 -7
  131. umap/static/umap/locale/ms.json +13 -7
  132. umap/static/umap/locale/nl.js +12 -7
  133. umap/static/umap/locale/nl.json +12 -7
  134. umap/static/umap/locale/no.js +13 -7
  135. umap/static/umap/locale/no.json +13 -7
  136. umap/static/umap/locale/pl.js +13 -7
  137. umap/static/umap/locale/pl.json +13 -7
  138. umap/static/umap/locale/pl_PL.json +13 -7
  139. umap/static/umap/locale/pt.js +12 -7
  140. umap/static/umap/locale/pt.json +12 -7
  141. umap/static/umap/locale/pt_BR.js +13 -7
  142. umap/static/umap/locale/pt_BR.json +13 -7
  143. umap/static/umap/locale/pt_PT.js +13 -7
  144. umap/static/umap/locale/pt_PT.json +13 -7
  145. umap/static/umap/locale/ro.js +13 -7
  146. umap/static/umap/locale/ro.json +13 -7
  147. umap/static/umap/locale/ru.js +13 -7
  148. umap/static/umap/locale/ru.json +13 -7
  149. umap/static/umap/locale/sk_SK.js +13 -7
  150. umap/static/umap/locale/sk_SK.json +13 -7
  151. umap/static/umap/locale/sl.js +13 -7
  152. umap/static/umap/locale/sl.json +13 -7
  153. umap/static/umap/locale/sr.js +13 -7
  154. umap/static/umap/locale/sr.json +13 -7
  155. umap/static/umap/locale/sv.js +13 -7
  156. umap/static/umap/locale/sv.json +13 -7
  157. umap/static/umap/locale/th_TH.js +13 -7
  158. umap/static/umap/locale/th_TH.json +13 -7
  159. umap/static/umap/locale/tr.js +13 -7
  160. umap/static/umap/locale/tr.json +13 -7
  161. umap/static/umap/locale/uk_UA.js +13 -7
  162. umap/static/umap/locale/uk_UA.json +13 -7
  163. umap/static/umap/locale/vi.js +13 -7
  164. umap/static/umap/locale/vi.json +13 -7
  165. umap/static/umap/locale/vi_VN.json +13 -7
  166. umap/static/umap/locale/zh.js +13 -7
  167. umap/static/umap/locale/zh.json +13 -7
  168. umap/static/umap/locale/zh_CN.json +13 -7
  169. umap/static/umap/locale/zh_TW.Big5.json +13 -7
  170. umap/static/umap/locale/zh_TW.js +19 -13
  171. umap/static/umap/locale/zh_TW.json +19 -13
  172. umap/static/umap/map.css +58 -28
  173. umap/static/umap/unittests/sync.js +0 -57
  174. umap/static/umap/unittests/utils.js +47 -0
  175. umap/static/umap/vars.css +5 -2
  176. umap/static/umap/vendors/photon/leaflet.photon.js +3 -0
  177. umap/sync/payloads.py +3 -2
  178. umap/templates/auth/user_detail.html +1 -1
  179. umap/templates/auth/user_stars.html +1 -1
  180. umap/templates/umap/content.html +17 -12
  181. umap/templates/umap/home.html +7 -5
  182. umap/templates/umap/map_fragment.html +1 -1
  183. umap/templates/umap/map_list.html +20 -13
  184. umap/templates/umap/search.html +7 -3
  185. umap/templates/umap/search_bar.html +13 -11
  186. umap/templates/umap/team_detail.html +1 -1
  187. umap/tests/base.py +2 -1
  188. umap/tests/fixtures/remote_data.umap +55 -0
  189. umap/tests/fixtures/test_upload_data_with_iconurl.umap +122 -0
  190. umap/tests/integration/test_browser.py +1 -3
  191. umap/tests/integration/test_conditional_rules.py +3 -0
  192. umap/tests/integration/test_edit_datalayer.py +2 -7
  193. umap/tests/integration/test_edit_map.py +15 -0
  194. umap/tests/integration/test_edit_polygon.py +1 -2
  195. umap/tests/integration/test_import.py +59 -2
  196. umap/tests/integration/test_optimistic_merge.py +4 -3
  197. umap/tests/integration/test_owned_map.py +0 -1
  198. umap/tests/integration/test_save.py +2 -4
  199. umap/tests/integration/test_undo_redo.py +267 -0
  200. umap/tests/integration/test_websocket_sync.py +78 -11
  201. umap/tests/settings.py +1 -3
  202. umap/tests/test_datalayer_s3.py +1 -0
  203. umap/tests/test_map_views.py +1 -0
  204. umap/tests/test_views.py +34 -0
  205. umap/utils.py +1 -1
  206. umap/views.py +23 -2
  207. {umap_project-2.9.2.dist-info → umap_project-3.0.0.dist-info}/METADATA +13 -12
  208. {umap_project-2.9.2.dist-info → umap_project-3.0.0.dist-info}/RECORD +211 -213
  209. umap/static/umap/js/modules/saving.js +0 -52
  210. umap/static/umap/test/.eslintrc +0 -21
  211. umap/static/umap/test/DataLayer.js +0 -463
  212. umap/static/umap/test/Feature.js +0 -131
  213. umap/static/umap/test/Map.js +0 -37
  214. umap/static/umap/test/Marker.js +0 -126
  215. umap/static/umap/test/Polygon.js +0 -111
  216. umap/static/umap/test/Polyline.js +0 -286
  217. umap/static/umap/test/Util.js +0 -28
  218. umap/static/umap/test/_pre.js +0 -455
  219. umap/static/umap/test/index.html +0 -139
  220. {umap_project-2.9.2.dist-info → umap_project-3.0.0.dist-info}/WHEEL +0 -0
  221. {umap_project-2.9.2.dist-info → umap_project-3.0.0.dist-info}/entry_points.txt +0 -0
  222. {umap_project-2.9.2.dist-info → umap_project-3.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -258,6 +258,9 @@ L.PhotonBaseSearch = L.PhotonBase.extend({
258
258
  if (feature.properties.city && feature.properties.city !== feature.properties.name) {
259
259
  details.push(feature.properties.city);
260
260
  }
261
+ if (feature.properties.state && feature.properties.state !== feature.properties.name) {
262
+ details.push(feature.properties.state);
263
+ }
261
264
  if (feature.properties.country) details.push(feature.properties.country);
262
265
  detailsContainer.innerHTML = details.join(', ');
263
266
  },
umap/sync/payloads.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import Literal, Optional, Union
1
+ from typing import List, Literal, Optional, Union
2
2
 
3
3
  from pydantic import BaseModel, Field, RootModel
4
4
 
@@ -14,10 +14,11 @@ class OperationMessage(BaseModel):
14
14
  """Message sent from one peer to all the others"""
15
15
 
16
16
  kind: Literal["OperationMessage"] = "OperationMessage"
17
- verb: Literal["upsert", "update", "delete"]
17
+ verb: Literal["upsert", "update", "delete", "batch"]
18
18
  subject: Literal["map", "datalayer", "feature"]
19
19
  metadata: Optional[dict] = None
20
20
  key: Optional[str] = None
21
+ operations: Optional[List] = None
21
22
 
22
23
 
23
24
  class PeerMessage(BaseModel):
@@ -13,7 +13,7 @@
13
13
  </h2>
14
14
  </div>
15
15
  <div class="wrapper">
16
- <div class="map_list row">
16
+ <div class="row grid-container">
17
17
  {% if maps %}
18
18
  {% include "umap/map_list.html" %}
19
19
  {% else %}
@@ -13,7 +13,7 @@
13
13
  </h2>
14
14
  </div>
15
15
  <div class="wrapper">
16
- <div class="map_list row">
16
+ <div class="grid-container row">
17
17
  {% if maps %}
18
18
  {% include "umap/map_list.html" %}
19
19
  {% else %}
@@ -43,22 +43,27 @@
43
43
  <script type="text/javascript">
44
44
  window.addEventListener('DOMContentLoaded', event => {
45
45
  const server = new U.ServerRequest()
46
- const getMore = async function (e) {
47
- L.DomEvent.stop(e)
48
- const [{html}, response, error] = await server.get(this.href)
46
+ const getMore = async function (link) {
47
+ const container = link.parentNode
48
+ container.removeChild(link)
49
+ const [{html}, response, error] = await server.get(link.href)
49
50
  if (!error) {
50
- const container = this.parentNode
51
- container.innerHTML = html
52
- const more = document.querySelector('.more_button')
53
- if (more) {
54
- L.DomEvent.on(more, 'click', getMore, more)
55
- }
51
+ const template = document.createElement('template')
52
+ template.innerHTML = html
53
+ container.appendChild(template.content)
54
+ listenForMore()
56
55
  }
57
56
  }
58
- const more = document.querySelector('.more_button')
59
- if (more) {
60
- L.DomEvent.on(more, 'click', getMore, more)
57
+ const listenForMore = () => {
58
+ const more = document.querySelector('.more_button')
59
+ if (more) {
60
+ L.DomEvent.on(more, 'click', (e) => {
61
+ L.DomEvent.stop(e)
62
+ getMore(more)
63
+ })
64
+ }
61
65
  }
66
+ listenForMore()
62
67
  })
63
68
  </script>
64
69
  {% endblock bottom_js %}
@@ -20,11 +20,13 @@
20
20
  {% endif %}
21
21
  <div class="wrapper">
22
22
  {% if maps %}
23
- <h2 class="section">
24
- {% blocktrans %}Get inspired, browse maps{% endblocktrans %}
25
- </h2>
26
- <div class="map_list row">
27
- {% include "umap/map_list.html" %}
23
+ <div class="row">
24
+ <h2 class="section">
25
+ {% blocktrans %}Get inspired, browse maps{% endblocktrans %}
26
+ </h2>
27
+ <div class="grid-container">
28
+ {% include "umap/map_list.html" %}
29
+ </div>
28
30
  </div>
29
31
  {% endif %}
30
32
  </div>
@@ -1,6 +1,6 @@
1
1
  {% load umap_tags %}
2
2
 
3
- <umap-fragment data-settings='{{ map_settings|escape }}'>
3
+ <umap-fragment data-settings='{{ map_settings|escape }}' inert>
4
4
  <div id="{{ unique_id }}" class="map_fragment">
5
5
  </div>
6
6
  </umap-fragment>
@@ -1,22 +1,29 @@
1
1
  {% load umap_tags i18n %}
2
2
 
3
3
  {% for map_inst in maps %}
4
- <hr />
5
- <div class="col wide">
4
+ <div class="card">
6
5
  {% map_fragment map_inst prefix=prefix page=request.GET.p %}
7
- <div class="legend">
8
- <a href="{{ map_inst.get_absolute_url }}">{{ map_inst.name }}</a>
9
- {% with author=map_inst.get_author %}
10
- {% if author %}
11
- <em>{% trans "by" %} <a href="{{ author.get_url }}">{{ author }}</a></em>
6
+ <hgroup>
7
+ <div>
8
+ {% if map_inst.tags %}
9
+ <ul class="tag-list">
10
+ {% for tag, label in map_inst.get_tags_display %}
11
+ <li><a href="{% url 'search' %}?tags={{ tag }}">{{ label }}</a></li>
12
+ {% endfor %}
13
+ </ul>
12
14
  {% endif %}
13
- {% endwith %}
14
- </div>
15
+ <h3>{{ map_inst.name }}</h3>
16
+ {% with author=map_inst.get_author %}
17
+ {% if author %}
18
+ <p>{% trans "by" %} <a href="{{ author.get_url }}">{{ author }}</a></p>
19
+ {% endif %}
20
+ {% endwith %}
21
+ </div>
22
+ <a class="main" href="{{ map_inst.get_absolute_url }}">{% translate "See the map" %}</a>
23
+ </hgroup>
15
24
  </div>
16
25
  {% endfor %}
17
26
  {% if maps.has_next %}
18
- <div class="col wide">
19
- <a href="?{% paginate_querystring maps.next_page_number %}"
20
- class="button more_button neutral">{% trans "More" %}</a>
21
- </div>
27
+ <a href="?{% paginate_querystring maps.next_page_number %}"
28
+ class="button more_button neutral">{% trans "More" %}</a>
22
29
  {% endif %}
@@ -12,7 +12,7 @@
12
12
  {% block maincontent %}
13
13
  {% include "umap/search_bar.html" %}
14
14
  <div class="wrapper">
15
- <div class="map_list row">
15
+ <div class="row">
16
16
  {% if request.GET.q %}
17
17
  {% if maps %}
18
18
  <h2>
@@ -22,7 +22,9 @@
22
22
  {{ count }} maps found:
23
23
  {% endblocktranslate %}
24
24
  </h2>
25
- {% include "umap/map_list.html" with prefix="search_map" %}
25
+ <div class="grid-container">
26
+ {% include "umap/map_list.html" with prefix="search_map" %}
27
+ </div>
26
28
  {% else %}
27
29
  <h2>
28
30
  {% trans "No map found." %}
@@ -32,7 +34,9 @@
32
34
  <h2>
33
35
  {% trans "Latest created maps" %}
34
36
  </h2>
35
- {% include "umap/map_list.html" with prefix="search_map" %}
37
+ <div class="grid-container">
38
+ {% include "umap/map_list.html" with prefix="search_map" %}
39
+ </div>
36
40
  {% endif %}
37
41
  </div>
38
42
  </div>
@@ -4,17 +4,19 @@
4
4
  {% trans "Search maps" as default_placeholder %}
5
5
  <div class="wrapper search_wrapper">
6
6
  <div class="row">
7
- <form action="{% firstof action search_url %}" method="get">
8
- <div class="col two-third mwide">
9
- <input name="q"
10
- type="search"
11
- placeholder="{% firstof placeholder default_placeholder %}"
12
- aria-label="{% firstof placeholder default_placeholder %}"
13
- value="{{ request.GET.q|default:"" }}" />
14
- </div>
15
- <div class="col third mwide">
16
- <input type="submit" value="{% trans "Search" %}" class="neutral" />
17
- </div>
7
+ <form class="search-form flex-break" action="{% firstof action search_url %}" method="get">
8
+ <input name="q"
9
+ type="search"
10
+ placeholder="{% firstof placeholder default_placeholder %}"
11
+ aria-label="{% firstof placeholder default_placeholder %}"
12
+ value="{{ request.GET.q|default:"" }}" />
13
+ <select name="tags">
14
+ <option value="">{% trans "Any category" %}</option>
15
+ {% for value, label in UMAP_TAGS %}
16
+ <option value="{{ value }}" {% if request.GET.tags == value %}selected{% endif %}>{{ label }}</option>
17
+ {% endfor %}
18
+ </select>
19
+ <input type="submit" value="{% trans "Search" %}" />
18
20
  </form>
19
21
  </div>
20
22
  </div>
@@ -18,7 +18,7 @@
18
18
  {% endif %}
19
19
  </div>
20
20
  </div>
21
- <div class="map_list row">
21
+ <div class="grid-container row">
22
22
  {% if maps %}
23
23
  {% include "umap/map_list.html" %}
24
24
  {% else %}
umap/tests/base.py CHANGED
@@ -18,6 +18,7 @@ DATALAYER_DATA = {
18
18
  "features": [
19
19
  {
20
20
  "type": "Feature",
21
+ "id": "ExNTQ",
21
22
  "geometry": {
22
23
  "type": "Point",
23
24
  "coordinates": [14.68896484375, 48.55297816440071],
@@ -41,7 +42,7 @@ class LicenceFactory(factory.django.DjangoModelFactory):
41
42
 
42
43
 
43
44
  class TileLayerFactory(factory.django.DjangoModelFactory):
44
- name = "Test zoom layer"
45
+ name = "Test tilelayer"
45
46
  url_template = "https://tile.openstreetmap.org/{z}/{x}/{y}.png"
46
47
  attribution = "Test layer attribution"
47
48
 
@@ -0,0 +1,55 @@
1
+ {
2
+ "type": "umap",
3
+ "uri": "http://localhost:8020/fr/map/carte-sans-nom_128#6/50.233/6.910",
4
+ "properties": {
5
+ "easing": false,
6
+ "embedControl": true,
7
+ "fullscreenControl": true,
8
+ "searchControl": true,
9
+ "datalayersControl": true,
10
+ "zoomControl": true,
11
+ "permanentCreditBackground": true,
12
+ "slideshow": {},
13
+ "captionMenus": true,
14
+ "captionBar": false,
15
+ "limitBounds": {},
16
+ "overlay": null,
17
+ "licence": "",
18
+ "description": "",
19
+ "name": "Carte sans nom",
20
+ "displayPopupFooter": false,
21
+ "miniMap": false,
22
+ "moreControl": true,
23
+ "scaleControl": true,
24
+ "scrollWheelZoom": true,
25
+ "zoom": 6
26
+ },
27
+ "geometry": {
28
+ "type": "Point",
29
+ "coordinates": [
30
+ 6.734619140625,
31
+ 50.359480346298696
32
+ ]
33
+ },
34
+ "layers": [
35
+ {
36
+ "type": "FeatureCollection",
37
+ "features": [],
38
+ "_umap_options": {
39
+ "name": "Itinéraire D",
40
+ "color": "#d34e8d",
41
+ "editMode": "advanced",
42
+ "browsable": true,
43
+ "inCaption": true,
44
+ "remoteData": {
45
+ "url": "https://remote.org/data.json",
46
+ "format": "geojson"
47
+ },
48
+ "permissions": {
49
+ "edit_status": 0
50
+ },
51
+ "displayOnLoad": true
52
+ }
53
+ }
54
+ ]
55
+ }
@@ -0,0 +1,122 @@
1
+ {
2
+ "type": "umap",
3
+ "uri": "https://umap.incubateur.anct.gouv.fr/fr/map/aires-de-covoiturage-du-departement-de-la-nievre_42",
4
+ "properties": {
5
+ "easing": false,
6
+ "embedControl": true,
7
+ "fullscreenControl": true,
8
+ "searchControl": true,
9
+ "datalayersControl": true,
10
+ "zoomControl": true,
11
+ "permanentCreditBackground": true,
12
+ "sortKey": "com_lieu",
13
+ "slideshow": {},
14
+ "captionMenus": true,
15
+ "captionBar": false,
16
+ "limitBounds": {},
17
+ "overlay": {},
18
+ "tilelayer": {
19
+ "tms": false,
20
+ "name": "OpenStreetMap",
21
+ "maxZoom": 19,
22
+ "minZoom": 0,
23
+ "attribution": "map data © [[http://osm.org/copyright|OpenStreetMap contributors]] under ODbL",
24
+ "url_template": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
25
+ },
26
+ "licence": "",
27
+ "description": "",
28
+ "name": "Aires de covoiturage du département de la Nièvre",
29
+ "defaultView": "data",
30
+ "onLoadPanel": "none",
31
+ "displayPopupFooter": false,
32
+ "miniMap": false,
33
+ "moreControl": true,
34
+ "scaleControl": true,
35
+ "scrollWheelZoom": true,
36
+ "zoom": 9
37
+ },
38
+ "geometry": {
39
+ "type": "Point",
40
+ "coordinates": [
41
+ 3.4552001953125004,
42
+ 47.12527904224337
43
+ ]
44
+ },
45
+ "layers": [
46
+ {
47
+ "type": "FeatureCollection",
48
+ "features": [
49
+ {
50
+ "type": "Feature",
51
+ "properties": {
52
+ "id_lieu": "58004-C-001",
53
+ "id_local": "",
54
+ "nom_lieu": "Maison du Bazois",
55
+ "ad_lieu": "Bois de Seigne",
56
+ "com_lieu": "ALLUY",
57
+ "insee": "58004",
58
+ "type": "Parking",
59
+ "date_maj": "29/08/2019",
60
+ "ouvert": "true",
61
+ "source": "225800010",
62
+ "nbre_pl": "4",
63
+ "nbre_pmr": "",
64
+ "duree": "",
65
+ "horaires": "",
66
+ "proprio": "",
67
+ "lumiere": "",
68
+ "comm": ""
69
+ },
70
+ "geometry": {
71
+ "type": "Point",
72
+ "coordinates": [
73
+ 3.634832,
74
+ 47.043123
75
+ ]
76
+ }
77
+ },
78
+ {
79
+ "type": "Feature",
80
+ "properties": {
81
+ "id_lieu": "58012-C-001",
82
+ "id_local": "",
83
+ "nom_lieu": "Mairie",
84
+ "ad_lieu": "28 route de Saint-Amand",
85
+ "com_lieu": "ARQUIAN",
86
+ "insee": "58012",
87
+ "type": "Auto-stop",
88
+ "date_maj": "19/05/2021",
89
+ "ouvert": "true",
90
+ "source": "810157982",
91
+ "nbre_pl": "",
92
+ "nbre_pmr": "",
93
+ "duree": "",
94
+ "horaires": "",
95
+ "proprio": "",
96
+ "lumiere": "true",
97
+ "comm": ""
98
+ },
99
+ "geometry": {
100
+ "type": "Point",
101
+ "coordinates": [
102
+ 2.99163,
103
+ 47.5407
104
+ ]
105
+ }
106
+ }
107
+ ],
108
+ "_umap_options": {
109
+ "displayOnLoad": true,
110
+ "browsable": false,
111
+ "editMode": "disabled",
112
+ "remoteData": {},
113
+ "popupContentTemplate": "# {nom_lieu}\nAdresse : {ad_lieu} {com_lieu}\nType : {type}\nNombre de places : {nbre_pl}\n",
114
+ "color": "SpringGreen",
115
+ "iconUrl": "/uploads/pictogram/car-24.png",
116
+ "labelKey": "com_lieu",
117
+ "id": 73,
118
+ "name": "Liste des aires de covoiturage"
119
+ }
120
+ }
121
+ ]
122
+ }
@@ -348,10 +348,8 @@ def test_should_redraw_list_on_feature_delete(live_server, openmap, page, bootst
348
348
  buttons = page.locator(".umap-browser .datalayer li .icon-delete")
349
349
  expect(buttons).to_have_count(3)
350
350
  buttons.first.click()
351
- page.locator("dialog").get_by_role("button", name="OK").click()
352
351
  expect(buttons).to_have_count(2)
353
- page.get_by_role("button", name="Cancel edits").click()
354
- page.locator("dialog").get_by_role("button", name="OK").click()
352
+ page.locator(".edit-undo").click()
355
353
  expect(buttons).to_have_count(3)
356
354
 
357
355
 
@@ -261,6 +261,9 @@ def test_can_create_new_rule(live_server, page, openmap):
261
261
  page.get_by_title("AliceBlue").first.click()
262
262
  colors = getColors(markers)
263
263
  assert colors.count("rgb(240, 248, 255)") == 3
264
+ page.locator(".edit-undo").click()
265
+ colors = getColors(markers)
266
+ assert colors.count("rgb(240, 248, 255)") == 0
264
267
 
265
268
 
266
269
  def test_can_deactive_rule_from_list(live_server, page, openmap):
@@ -61,11 +61,9 @@ def test_cancel_deleting_datalayer_should_restore(
61
61
  expect(markers).to_have_count(1)
62
62
  page.get_by_role("button", name="Manage layers").click()
63
63
  page.locator(".panel.right").get_by_title("Delete layer").click()
64
- page.get_by_role("button", name="OK").click()
65
64
  expect(markers).to_have_count(0)
66
65
  expect(page.get_by_text("test datalayer")).to_be_hidden()
67
- page.get_by_role("button", name="Cancel edits").click()
68
- page.locator("dialog").get_by_role("button", name="OK").click()
66
+ page.locator(".edit-undo").click()
69
67
  expect(markers).to_have_count(1)
70
68
  expect(page.locator(".umap-browser").get_by_text("test datalayer")).to_be_visible()
71
69
 
@@ -160,7 +158,6 @@ def test_can_create_new_datalayer(live_server, openmap, page, datalayer):
160
158
  page.locator('input[name="name"]').click()
161
159
  page.locator('input[name="name"]').fill("Layer A with a new name")
162
160
  expect(page.get_by_text("Layer A with a new name")).to_be_visible()
163
- page.get_by_role("button", name="Save").click()
164
161
  with page.expect_response(re.compile(".*/datalayer/update/.*")):
165
162
  page.get_by_role("button", name="Save").click()
166
163
  assert DataLayer.objects.count() == 2
@@ -182,7 +179,7 @@ def test_can_restore_version(live_server, openmap, page, datalayer):
182
179
  page.get_by_role("button", name="Manage layers").click()
183
180
  page.locator(".panel.right").get_by_title("Edit", exact=True).click()
184
181
  page.get_by_text("Versions").click()
185
- page.get_by_role("button", name="Restore this version").last.click()
182
+ page.get_by_title("Restore this version").last.click()
186
183
  page.get_by_role("button", name="OK").click()
187
184
  expect(marker).to_have_class(re.compile(".*umap-ball-icon.*"))
188
185
 
@@ -205,7 +202,6 @@ def test_deleting_datalayer_should_remove_from_browser_and_layers_list(
205
202
  expect(panel.get_by_text("test datalayer")).to_be_visible()
206
203
  expect(edit_panel.get_by_text("test datalayer")).to_be_visible()
207
204
  page.locator(".panel.right").get_by_title("Delete layer").click()
208
- page.get_by_role("button", name="OK").click()
209
205
  expect(panel.get_by_text("test datalayer")).to_be_hidden()
210
206
  expect(edit_panel.get_by_text("test datalayer")).to_be_hidden()
211
207
 
@@ -219,7 +215,6 @@ def test_deleting_datalayer_should_remove_from_caption(
219
215
  page.get_by_role("button", name="Manage layers").click()
220
216
  expect(panel.get_by_text("test datalayer")).to_be_visible()
221
217
  page.locator(".panel.right").get_by_title("Delete layer").click()
222
- page.get_by_role("button", name="OK").click()
223
218
  expect(panel.get_by_text("test datalayer")).to_be_hidden()
224
219
 
225
220
 
@@ -226,3 +226,18 @@ def test_hover_tooltip_setting_should_be_persistent(live_server, map, page):
226
226
  - text: always never on hover
227
227
  """)
228
228
  expect(page.locator(".umap-field-showLabel input[value=null]")).to_be_checked()
229
+
230
+
231
+ def test_can_edit_map_tags(live_server, map, page):
232
+ map.settings["properties"]["tags"] = ["arts"]
233
+ map.edit_status = Map.ANONYMOUS
234
+ map.save()
235
+ page.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
236
+ page.get_by_role("button", name="Edit map name and caption").click()
237
+ page.get_by_text("Tags").click()
238
+ expect(page.get_by_label("Art and Culture")).to_be_checked()
239
+ page.get_by_label("Cycling").check()
240
+ with page.expect_response(re.compile("./update/settings/.*")):
241
+ page.get_by_role("button", name="Save").click()
242
+ saved = Map.objects.get(pk=map.pk)
243
+ assert saved.tags == ["arts", "cycling"]
@@ -117,8 +117,7 @@ def test_should_reset_style_on_cancel(live_server, openmap, page, bootstrap):
117
117
  expect(page.locator(".leaflet-overlay-pane path[fill='GoldenRod']")).to_have_count(
118
118
  1
119
119
  )
120
- page.get_by_role("button", name="Cancel edits").click()
121
- page.locator("dialog").get_by_role("button", name="OK").click()
120
+ page.locator(".edit-undo").click()
122
121
  expect(page.locator(".leaflet-overlay-pane path[fill='DarkBlue']")).to_have_count(1)
123
122
 
124
123
 
@@ -86,8 +86,8 @@ def test_umap_import_from_textarea(live_server, tilelayer, page, settings):
86
86
  expect(page.locator(".umap-main-edit-toolbox .map-name")).to_have_text(
87
87
  "Imported map"
88
88
  )
89
- expect(page.get_by_text("Tunnels")).to_be_visible()
90
- expect(page.get_by_text("Cities")).to_be_visible()
89
+ expect(page.locator(".panel.left").get_by_text("Tunnels")).to_be_visible()
90
+ expect(page.locator(".panel.left").get_by_text("Cities")).to_be_visible()
91
91
  expect(page.locator(".leaflet-control-minimap")).to_be_visible()
92
92
  expect(
93
93
  page.locator('img[src="https://tile.openstreetmap.fr/hot/6/32/21.png"]')
@@ -650,6 +650,46 @@ def test_create_remote_data(page, live_server, tilelayer):
650
650
  )
651
651
 
652
652
 
653
+ def test_create_remote_data_from_umap_backup(page, live_server, tilelayer):
654
+ def handle(route):
655
+ route.fulfill(
656
+ json={
657
+ "type": "FeatureCollection",
658
+ "features": [
659
+ {
660
+ "type": "Feature",
661
+ "properties": {},
662
+ "geometry": {
663
+ "type": "Point",
664
+ "coordinates": [4.3375, 51.2707],
665
+ },
666
+ }
667
+ ],
668
+ }
669
+ )
670
+
671
+ page.route("https://remote.org/data.json", handle)
672
+ page.goto(f"{live_server.url}/map/new/")
673
+ expect(page.locator(".leaflet-marker-icon")).to_be_hidden()
674
+ page.get_by_title("Import data").click()
675
+ file_input = page.locator("input[type='file']")
676
+ with page.expect_file_chooser() as fc_info:
677
+ file_input.click()
678
+ file_chooser = fc_info.value
679
+ path = Path(__file__).parent.parent / "fixtures/remote_data.umap"
680
+ file_chooser.set_files(path)
681
+ page.get_by_role("button", name="Import data", exact=True).click()
682
+ page.get_by_title("Open browser").click()
683
+ layers = page.locator(".umap-browser .datalayer")
684
+ expect(layers).to_have_count(1)
685
+ expect(page.locator(".leaflet-marker-icon")).to_be_visible()
686
+ page.get_by_role("button", name="Edit", exact=True).click()
687
+ page.locator("summary").filter(has_text="Remote data").click()
688
+ expect(page.locator('.panel input[name="url"]')).to_have_value(
689
+ "https://remote.org/data.json"
690
+ )
691
+
692
+
653
693
  def test_import_geojson_from_url(page, live_server, tilelayer):
654
694
  def handle(route):
655
695
  route.fulfill(
@@ -870,3 +910,20 @@ def test_import_from_multiple_files(live_server, page, tilelayer):
870
910
  page.get_by_role("button", name="Import data", exact=True).click()
871
911
  # Two in one file, one in the other
872
912
  expect(markers).to_have_count(3)
913
+
914
+
915
+ def test_umap_import_with_iconurl(live_server, tilelayer, page):
916
+ page.goto(f"{live_server.url}/map/new/")
917
+ page.get_by_title("Import data").click()
918
+ file_input = page.locator("input[type='file']")
919
+ with page.expect_file_chooser() as fc_info:
920
+ file_input.click()
921
+ file_chooser = fc_info.value
922
+ path = Path(__file__).parent.parent / "fixtures/test_upload_data_with_iconurl.umap"
923
+ file_chooser.set_files(path)
924
+ page.get_by_role("button", name="Import data", exact=True).click()
925
+ expect(
926
+ page.locator(
927
+ 'img[src="https://umap.incubateur.anct.gouv.fr/uploads/pictogram/car-24.png"]'
928
+ )
929
+ ).to_have_count(2)
@@ -292,9 +292,10 @@ def test_should_display_alert_on_conflict(context, live_server, datalayer, openm
292
292
  # Change name on page two and save
293
293
  page_two.locator(".leaflet-marker-icon").click(modifiers=["Shift"])
294
294
  page_two.locator('input[name="name"]').fill("name from page two")
295
+ page_two.wait_for_timeout(300) # Time for the input debounce.
295
296
 
296
297
  # Map should be in dirty status
297
- expect(page_two.get_by_text("Cancel edits")).to_be_visible()
298
+ expect(page_two.get_by_text("Save", exact=True)).to_be_enabled()
298
299
  with page_two.expect_response(re.compile(r".*/datalayer/update/.*")):
299
300
  page_two.get_by_role("button", name="Save").click()
300
301
 
@@ -306,7 +307,7 @@ def test_should_display_alert_on_conflict(context, live_server, datalayer, openm
306
307
  # We should have an alert with some actions
307
308
  expect(page_two.get_by_text("Whoops! Other contributor(s) changed")).to_be_visible()
308
309
  # Map should still be in dirty status
309
- expect(page_two.get_by_text("Cancel edits")).to_be_visible()
310
+ expect(page_two.get_by_text("Save", exact=True)).to_be_enabled()
310
311
 
311
312
  # Override data from page two
312
313
  with page_two.expect_response(re.compile(r".*/datalayer/update/.*")):
@@ -317,4 +318,4 @@ def test_should_display_alert_on_conflict(context, live_server, datalayer, openm
317
318
  data = json.loads(Path(saved.geojson.path).read_text())
318
319
  assert data["features"][0]["properties"]["name"] == "name from page two"
319
320
  # Map should not be in dirty status anymore
320
- expect(page_two.get_by_text("Cancel edits")).to_be_hidden()
321
+ expect(page_two.get_by_text("Save", exact=True)).to_be_disabled()
@@ -241,7 +241,6 @@ def test_can_delete_datalayer(live_server, map, login, datalayer):
241
241
  expect(markers).to_have_count(1)
242
242
  page.get_by_role("button", name="Manage layers").click()
243
243
  page.locator(".panel.right").get_by_title("Delete layer").click()
244
- page.get_by_role("button", name="OK").click()
245
244
  with page.expect_response(re.compile(r".*/datalayer/delete/.*")):
246
245
  page.get_by_role("button", name="Save").click()
247
246
  expect(markers).to_have_count(0)