umap-project 2.3.1__py3-none-any.whl → 2.4.0b0__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 (210) hide show
  1. umap/.DS_Store +0 -0
  2. umap/__init__.py +1 -1
  3. umap/locale/en/LC_MESSAGES/django.po +81 -31
  4. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  5. umap/locale/fr/LC_MESSAGES/django.po +109 -59
  6. umap/management/commands/run_websocket_server.py +23 -0
  7. umap/models.py +6 -1
  8. umap/settings/base.py +11 -3
  9. umap/static/.DS_Store +0 -0
  10. umap/static/umap/.DS_Store +0 -0
  11. umap/static/umap/base.css +53 -162
  12. umap/static/umap/content.css +3 -2
  13. umap/static/umap/css/dialog.css +18 -0
  14. umap/static/umap/css/icon.css +8 -0
  15. umap/static/umap/css/importers.css +44 -0
  16. umap/static/umap/css/panel.css +19 -57
  17. umap/static/umap/css/tooltip.css +59 -0
  18. umap/static/umap/css/window.css +35 -0
  19. umap/static/umap/favicons/.DS_Store +0 -0
  20. umap/static/umap/fonts/.DS_Store +0 -0
  21. umap/static/umap/img/.DS_Store +0 -0
  22. umap/static/umap/img/alert-icon-error.svg +8 -0
  23. umap/static/umap/img/alert-icon-info.svg +4 -0
  24. umap/static/umap/img/alert-icon-success.svg +3 -0
  25. umap/static/umap/img/icon-external-link.svg +3 -0
  26. umap/static/umap/img/importers/communesfr.svg +5 -0
  27. umap/static/umap/img/importers/datasets.svg +13 -0
  28. umap/static/umap/img/importers/geodatamine.svg +10 -0
  29. umap/static/umap/img/importers/overpass.svg +7 -0
  30. umap/static/umap/img/importers/random.svg +18 -0
  31. umap/static/umap/img/importers/random1.svg +4 -0
  32. umap/static/umap/img/importers/random2.svg +4 -0
  33. umap/static/umap/img/source/.DS_Store +0 -0
  34. umap/static/umap/js/components/alerts/alert.css +160 -0
  35. umap/static/umap/js/components/alerts/alert.js +169 -0
  36. umap/static/umap/js/components/base.js +54 -0
  37. umap/static/umap/js/modules/autocomplete.js +347 -0
  38. umap/static/umap/js/modules/browser.js +1 -1
  39. umap/static/umap/js/modules/caption.js +4 -3
  40. umap/static/umap/js/modules/global.js +36 -12
  41. umap/static/umap/js/modules/help.js +255 -0
  42. umap/static/umap/js/modules/importer.js +280 -0
  43. umap/static/umap/js/modules/importers/communesfr.js +44 -0
  44. umap/static/umap/js/modules/importers/datasets.js +41 -0
  45. umap/static/umap/js/modules/importers/geodatamine.js +95 -0
  46. umap/static/umap/js/modules/importers/overpass.js +84 -0
  47. umap/static/umap/js/modules/request.js +12 -14
  48. umap/static/umap/js/modules/rules.js +241 -0
  49. umap/static/umap/js/modules/schema.js +63 -14
  50. umap/static/umap/js/modules/sync/engine.js +93 -0
  51. umap/static/umap/js/modules/sync/updaters.js +109 -0
  52. umap/static/umap/js/modules/sync/websocket.js +25 -0
  53. umap/static/umap/js/modules/ui/dialog.js +52 -0
  54. umap/static/umap/js/modules/{panel.js → ui/panel.js} +25 -14
  55. umap/static/umap/js/modules/ui/tooltip.js +116 -0
  56. umap/static/umap/js/modules/utils.js +25 -18
  57. umap/static/umap/js/umap.controls.js +13 -14
  58. umap/static/umap/js/umap.core.js +1 -324
  59. umap/static/umap/js/umap.features.js +67 -27
  60. umap/static/umap/js/umap.forms.js +9 -13
  61. umap/static/umap/js/umap.js +220 -180
  62. umap/static/umap/js/umap.layer.js +142 -74
  63. umap/static/umap/js/umap.permissions.js +5 -9
  64. umap/static/umap/js/umap.tableeditor.js +8 -8
  65. umap/static/umap/locale/am_ET.js +51 -16
  66. umap/static/umap/locale/am_ET.json +51 -16
  67. umap/static/umap/locale/ar.js +51 -16
  68. umap/static/umap/locale/ar.json +51 -16
  69. umap/static/umap/locale/ast.js +51 -16
  70. umap/static/umap/locale/ast.json +51 -16
  71. umap/static/umap/locale/bg.js +51 -16
  72. umap/static/umap/locale/bg.json +51 -16
  73. umap/static/umap/locale/br.js +55 -20
  74. umap/static/umap/locale/br.json +55 -20
  75. umap/static/umap/locale/ca.js +51 -16
  76. umap/static/umap/locale/ca.json +51 -16
  77. umap/static/umap/locale/cs_CZ.js +93 -58
  78. umap/static/umap/locale/cs_CZ.json +93 -58
  79. umap/static/umap/locale/da.js +51 -16
  80. umap/static/umap/locale/da.json +51 -16
  81. umap/static/umap/locale/de.js +56 -21
  82. umap/static/umap/locale/de.json +56 -21
  83. umap/static/umap/locale/el.js +51 -16
  84. umap/static/umap/locale/el.json +51 -16
  85. umap/static/umap/locale/en.js +51 -16
  86. umap/static/umap/locale/en.json +51 -16
  87. umap/static/umap/locale/en_US.json +51 -16
  88. umap/static/umap/locale/es.js +51 -16
  89. umap/static/umap/locale/es.json +51 -16
  90. umap/static/umap/locale/et.js +51 -16
  91. umap/static/umap/locale/et.json +51 -16
  92. umap/static/umap/locale/eu.js +51 -16
  93. umap/static/umap/locale/eu.json +51 -16
  94. umap/static/umap/locale/fa_IR.js +51 -16
  95. umap/static/umap/locale/fa_IR.json +51 -16
  96. umap/static/umap/locale/fi.js +51 -16
  97. umap/static/umap/locale/fi.json +51 -16
  98. umap/static/umap/locale/fr.js +52 -17
  99. umap/static/umap/locale/fr.json +52 -17
  100. umap/static/umap/locale/gl.js +51 -16
  101. umap/static/umap/locale/gl.json +51 -16
  102. umap/static/umap/locale/he.js +51 -16
  103. umap/static/umap/locale/he.json +51 -16
  104. umap/static/umap/locale/hr.js +51 -16
  105. umap/static/umap/locale/hr.json +51 -16
  106. umap/static/umap/locale/hu.js +51 -16
  107. umap/static/umap/locale/hu.json +51 -16
  108. umap/static/umap/locale/id.js +51 -16
  109. umap/static/umap/locale/id.json +51 -16
  110. umap/static/umap/locale/is.js +51 -16
  111. umap/static/umap/locale/is.json +51 -16
  112. umap/static/umap/locale/it.js +51 -16
  113. umap/static/umap/locale/it.json +51 -16
  114. umap/static/umap/locale/ja.js +51 -16
  115. umap/static/umap/locale/ja.json +51 -16
  116. umap/static/umap/locale/ko.js +51 -16
  117. umap/static/umap/locale/ko.json +51 -16
  118. umap/static/umap/locale/lt.js +51 -16
  119. umap/static/umap/locale/lt.json +51 -16
  120. umap/static/umap/locale/ms.js +51 -16
  121. umap/static/umap/locale/ms.json +51 -16
  122. umap/static/umap/locale/nl.js +51 -16
  123. umap/static/umap/locale/nl.json +51 -16
  124. umap/static/umap/locale/no.js +51 -16
  125. umap/static/umap/locale/no.json +51 -16
  126. umap/static/umap/locale/pl.js +93 -58
  127. umap/static/umap/locale/pl.json +93 -58
  128. umap/static/umap/locale/pl_PL.json +51 -16
  129. umap/static/umap/locale/pt.js +215 -180
  130. umap/static/umap/locale/pt.json +215 -180
  131. umap/static/umap/locale/pt_BR.js +51 -16
  132. umap/static/umap/locale/pt_BR.json +51 -16
  133. umap/static/umap/locale/pt_PT.js +51 -16
  134. umap/static/umap/locale/pt_PT.json +51 -16
  135. umap/static/umap/locale/ro.js +51 -16
  136. umap/static/umap/locale/ro.json +51 -16
  137. umap/static/umap/locale/ru.js +51 -16
  138. umap/static/umap/locale/ru.json +51 -16
  139. umap/static/umap/locale/si.js +51 -16
  140. umap/static/umap/locale/si.json +51 -16
  141. umap/static/umap/locale/sk_SK.js +51 -16
  142. umap/static/umap/locale/sk_SK.json +51 -16
  143. umap/static/umap/locale/sl.js +51 -16
  144. umap/static/umap/locale/sl.json +51 -16
  145. umap/static/umap/locale/sr.js +51 -16
  146. umap/static/umap/locale/sr.json +51 -16
  147. umap/static/umap/locale/sv.js +51 -16
  148. umap/static/umap/locale/sv.json +51 -16
  149. umap/static/umap/locale/th_TH.js +51 -16
  150. umap/static/umap/locale/th_TH.json +51 -16
  151. umap/static/umap/locale/tr.js +51 -16
  152. umap/static/umap/locale/tr.json +51 -16
  153. umap/static/umap/locale/uk_UA.js +51 -16
  154. umap/static/umap/locale/uk_UA.json +51 -16
  155. umap/static/umap/locale/vi.js +51 -16
  156. umap/static/umap/locale/vi.json +51 -16
  157. umap/static/umap/locale/vi_VN.json +51 -16
  158. umap/static/umap/locale/zh.js +51 -16
  159. umap/static/umap/locale/zh.json +51 -16
  160. umap/static/umap/locale/zh_CN.json +51 -16
  161. umap/static/umap/locale/zh_TW.Big5.json +51 -16
  162. umap/static/umap/locale/zh_TW.js +51 -16
  163. umap/static/umap/locale/zh_TW.json +51 -16
  164. umap/static/umap/map.css +27 -41
  165. umap/static/umap/unittests/sync.js +105 -0
  166. umap/static/umap/unittests/utils.js +76 -34
  167. umap/static/umap/vars.css +18 -1
  168. umap/static/umap/vendors/dompurify/purify.es.js +5 -59
  169. umap/static/umap/vendors/dompurify/purify.es.mjs.map +1 -1
  170. umap/templates/umap/components/alerts/alert.html +89 -0
  171. umap/templates/umap/content.html +4 -3
  172. umap/templates/umap/css.html +4 -0
  173. umap/templates/umap/home.html +3 -0
  174. umap/templates/umap/js.html +0 -3
  175. umap/templates/umap/map_init.html +2 -8
  176. umap/templates/umap/messages.html +9 -11
  177. umap/templates/umap/search.html +3 -0
  178. umap/tests/.DS_Store +0 -0
  179. umap/tests/base.py +2 -0
  180. umap/tests/integration/.DS_Store +0 -0
  181. umap/tests/integration/conftest.py +30 -0
  182. umap/tests/integration/test_anonymous_owned_map.py +8 -13
  183. umap/tests/integration/test_browser.py +1 -1
  184. umap/tests/integration/test_conditional_rules.py +201 -0
  185. umap/tests/integration/test_dashboard.py +1 -1
  186. umap/tests/integration/test_datalayer.py +2 -3
  187. umap/tests/integration/test_edit_datalayer.py +4 -4
  188. umap/tests/integration/test_edit_map.py +1 -1
  189. umap/tests/integration/test_facets_browser.py +3 -3
  190. umap/tests/integration/test_import.py +138 -49
  191. umap/tests/integration/test_map.py +2 -2
  192. umap/tests/integration/{test_collaborative_editing.py → test_optimistic_merge.py} +7 -7
  193. umap/tests/integration/test_owned_map.py +1 -1
  194. umap/tests/integration/test_picto.py +2 -2
  195. umap/tests/integration/test_statics.py +1 -1
  196. umap/tests/integration/test_websocket_sync.py +283 -0
  197. umap/tests/settings.py +5 -0
  198. umap/tests/test_datalayer_views.py +0 -1
  199. umap/tests/test_views.py +53 -0
  200. umap/urls.py +5 -0
  201. umap/views.py +40 -11
  202. umap/websocket_server.py +92 -0
  203. {umap_project-2.3.1.dist-info → umap_project-2.4.0b0.dist-info}/METADATA +11 -9
  204. {umap_project-2.3.1.dist-info → umap_project-2.4.0b0.dist-info}/RECORD +207 -164
  205. {umap_project-2.3.1.dist-info → umap_project-2.4.0b0.dist-info}/WHEEL +1 -1
  206. umap/static/umap/js/umap.autocomplete.js +0 -341
  207. umap/static/umap/js/umap.importer.js +0 -187
  208. umap/static/umap/js/umap.ui.js +0 -190
  209. {umap_project-2.3.1.dist-info → umap_project-2.4.0b0.dist-info}/entry_points.txt +0 -0
  210. {umap_project-2.3.1.dist-info → umap_project-2.4.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,89 @@
1
+ {% load i18n static %}
2
+
3
+ <style type="text/css">
4
+ @import "{% static 'umap/js/components/alerts/alert.css' %}";
5
+ </style>
6
+
7
+ <template id="umap-alert-template">
8
+ <div role="dialog" class="dark window">
9
+ <div>
10
+ <p role="alert"></p>
11
+ </div>
12
+ <ul class="buttons">
13
+ <li>
14
+ <button class="icon icon-16 icon-close" aria-label="{% translate "Close" %}" data-close></button>
15
+ </li>
16
+ </ul>
17
+ </div>
18
+ </template>
19
+
20
+ <umap-alert></umap-alert>
21
+
22
+ <template id="umap-alert-creation-template">
23
+ <div role="dialog" class="dark window">
24
+ <div>
25
+ <h3 role="alert"></h3>
26
+ {% url "login" as login_url %}
27
+ <p><em>{% blocktranslate %}Pro-tip: to easily find back your maps, <a href="{{ login_url }}" target="_blank">create an account</a> or <a href="{{ login_url }}" target="_blank">log in</a>.{% endblocktranslate %}</em></p>
28
+ <div id="link-wrapper">
29
+ <form>
30
+ <label for="url">{% translate "Here is your secret link to edit the map, please keep it safe:" %}</label>
31
+ <fieldset role="group">
32
+ <input type="url" name="url" id="url">
33
+ <input type="button" value="{% translate "Copy link" %}">
34
+ </fieldset>
35
+ </form>
36
+ </div>
37
+ <div id="form-wrapper" hidden>
38
+ <form>
39
+ <label for="email">{% translate "Enter your email address to receive the secret link:" %}</label>
40
+ <fieldset role="group">
41
+ <input type="email" name="email" id="email" placeholder="{% translate "Email" %}" required>
42
+ <input type="submit" value="{% translate "Send me the link" %}" class="umap-action">
43
+ </fieldset>
44
+ </form>
45
+ </div>
46
+ </div>
47
+ <ul class="buttons">
48
+ <li>
49
+ <button class="icon icon-16 icon-close" aria-label="{% translate "Close" %}" data-close></button>
50
+ </li>
51
+ </ul>
52
+ </div>
53
+ </template>
54
+
55
+ <umap-alert-creation></umap-alert-creation>
56
+
57
+ <template id="umap-alert-conflict-template">
58
+ <div role="dialog" class="dark window">
59
+ <div>
60
+ <p role="alert"></p>
61
+ <div id="conflict-wrapper">
62
+ <form>
63
+ <a href="#" onclick="document.url" target="_blank">{% translate "See their edits in another tab" %}</a>
64
+ <input id="your-changes" type="submit" value="{% translate "Keep your changes and loose theirs" %}">
65
+ <input id="their-changes" type="submit" value="{% translate "Keep their changes and loose yours" %}">
66
+ </form>
67
+ </div>
68
+ </div>
69
+ <ul class="buttons">
70
+ <li>
71
+ <button class="icon icon-16 icon-close" aria-label="{% translate "Close" %}" data-close></button>
72
+ </li>
73
+ </ul>
74
+ </div>
75
+ </template>
76
+
77
+ <umap-alert-conflict></umap-alert-conflict>
78
+
79
+ <script type="module">
80
+ import { register } from '{% static 'umap/js/components/base.js' %}'
81
+ import {
82
+ uMapAlert,
83
+ uMapAlertCreation,
84
+ uMapAlertConflict
85
+ } from '{% static 'umap/js/components/alerts/alert.js' %}'
86
+ register(uMapAlert, 'umap-alert')
87
+ register(uMapAlertCreation, 'umap-alert-creation')
88
+ register(uMapAlertConflict, 'umap-alert-conflict')
89
+ </script>
@@ -12,7 +12,9 @@
12
12
  <header class="wrapper row">
13
13
  {% include "umap/navigation.html" with title=SITE_NAME %}
14
14
  </header>
15
- {% include "umap/messages.html" with title=SITE_NAME %}
15
+ {% block messages %}
16
+ {% include "umap/messages.html" with title=SITE_NAME %}
17
+ {% endblock messages %}
16
18
  {% endblock header %}
17
19
  {% block content %}
18
20
  {% if UMAP_READONLY %}
@@ -38,8 +40,7 @@
38
40
  {{ block.super }}
39
41
  <script type="text/javascript">
40
42
  window.addEventListener('DOMContentLoaded', event => {
41
- const ui = new U.UI(document.querySelector('header'))
42
- const server = new U.ServerRequest(ui)
43
+ const server = new U.ServerRequest()
43
44
  const getMore = async function (e) {
44
45
  L.DomEvent.stop(e)
45
46
  const [{html}, response, error] = await server.get(this.href)
@@ -29,4 +29,8 @@
29
29
  <link rel="stylesheet" href="{% static 'umap/nav.css' %}" />
30
30
  <link rel="stylesheet" href="{% static 'umap/map.css' %}" />
31
31
  <link rel="stylesheet" href="{% static 'umap/css/panel.css' %}" />
32
+ <link rel="stylesheet" href="{% static 'umap/css/window.css' %}" />
33
+ <link rel="stylesheet" href="{% static 'umap/css/tooltip.css' %}" />
34
+ <link rel="stylesheet" href="{% static 'umap/css/dialog.css' %}" />
35
+ <link rel="stylesheet" href="{% static 'umap/css/importers.css' %}" />
32
36
  <link rel="stylesheet" href="{% static 'umap/theme.css' %}" />
@@ -1,5 +1,8 @@
1
1
  {% extends "umap/content.html" %}
2
2
  {% load umap_tags i18n %}
3
+ {% block messages %}
4
+ {# We don't want maps in the list to display errors. #}
5
+ {% endblock messages %}
3
6
  {% block maincontent %}
4
7
  {% include "umap/search_bar.html" %}
5
8
  {% include "umap/about_summary.html" %}
@@ -46,7 +46,6 @@
46
46
  <script src="{% static 'umap/vendors/simple-statistics/simple-statistics.min.js' %}"
47
47
  defer></script>
48
48
  <script src="{% static 'umap/js/umap.core.js' %}" defer></script>
49
- <script src="{% static 'umap/js/umap.autocomplete.js' %}" defer></script>
50
49
  <script src="{% static 'umap/js/umap.popup.js' %}" defer></script>
51
50
  <script src="{% static 'umap/js/umap.forms.js' %}" defer></script>
52
51
  <script src="{% static 'umap/js/umap.icon.js' %}" defer></script>
@@ -57,8 +56,6 @@
57
56
  <script src="{% static 'umap/js/umap.controls.js' %}" defer></script>
58
57
  <script src="{% static 'umap/js/umap.slideshow.js' %}" defer></script>
59
58
  <script src="{% static 'umap/js/umap.tableeditor.js' %}" defer></script>
60
- <script src="{% static 'umap/js/umap.importer.js' %}" defer></script>
61
59
  <script src="{% static 'umap/js/umap.share.js' %}" defer></script>
62
60
  <script src="{% static 'umap/js/umap.js' %}" defer></script>
63
- <script src="{% static 'umap/js/umap.ui.js' %}" defer></script>
64
61
  <script src="{% static 'umap/js/components/fragment.js' %}" defer></script>
@@ -1,17 +1,11 @@
1
1
  {% load umap_tags %}
2
+
3
+ {% include "umap/messages.html" %}
2
4
  <div id="map"></div>
3
5
  <!-- djlint:off -->
4
6
  <script defer type="text/javascript">
5
7
  window.addEventListener('DOMContentLoaded', (event) => {
6
8
  U.MAP = new U.Map("map", {{ map_settings|notag|safe }})
7
- {% for m in messages %}
8
- {# We have just one, but we need to loop, as for messages API #}
9
- U.MAP.ui.alert({
10
- content: "{{ m }}",
11
- level: "{{ m.tags }}",
12
- duration: 100000
13
- })
14
- {% endfor %}
15
9
  })
16
10
  </script>
17
11
  <!-- djlint:on -->
@@ -1,11 +1,9 @@
1
- <div class="wrapper">
2
- <div class="row">
3
- {% if messages %}
4
- <ul class="messages">
5
- {% for message in messages %}
6
- <li {% if message.tags %}class="{{ message.tags }}"{% endif %}>{{ message }}</li>
7
- {% endfor %}
8
- </ul>
9
- {% endif %}
10
- </div>
11
- </div>
1
+ {% load i18n %}
2
+
3
+ {% include "umap/components/alerts/alert.html" %}
4
+
5
+ {% for message in messages %}
6
+ <script type="module" defer>
7
+ U.Alert.success("{{ message }}")
8
+ </script>
9
+ {% endfor %}
@@ -1,5 +1,8 @@
1
1
  {% extends "umap/content.html" %}
2
2
  {% load i18n %}
3
+ {% block messages %}
4
+ {# We don't want maps from the results list to display errors in the main page. #}
5
+ {% endblock messages %}
3
6
  {% block maincontent %}
4
7
  {% include "umap/search_bar.html" %}
5
8
  <div class="wrapper">
umap/tests/.DS_Store ADDED
Binary file
umap/tests/base.py CHANGED
@@ -127,6 +127,8 @@ class DataLayerFactory(factory.django.DjangoModelFactory):
127
127
  data.setdefault("_umap_options", {})
128
128
  kwargs["settings"]["name"] = kwargs["name"]
129
129
  data["_umap_options"]["name"] = kwargs["name"]
130
+ data.setdefault("type", "FeatureCollection")
131
+ data.setdefault("features", [])
130
132
  kwargs["geojson"] = ContentFile(json.dumps(data), "foo.json")
131
133
  return kwargs
132
134
 
Binary file
@@ -1,9 +1,17 @@
1
1
  import os
2
+ import subprocess
3
+ import time
4
+ from pathlib import Path
2
5
 
3
6
  import pytest
4
7
  from playwright.sync_api import expect
5
8
 
6
9
 
10
+ @pytest.fixture(scope="session")
11
+ def browser_context_args(browser_context_args):
12
+ return {**browser_context_args, "locale": "en-GB", "timezone_id": "Europe/Paris"}
13
+
14
+
7
15
  @pytest.fixture(autouse=True)
8
16
  def set_timeout(context):
9
17
  timeout = int(os.environ.get("PLAYWRIGHT_TIMEOUT", 7500))
@@ -33,3 +41,25 @@ def login(context, settings, live_server):
33
41
  return page
34
42
 
35
43
  return do_login
44
+
45
+
46
+ @pytest.fixture
47
+ def websocket_server():
48
+ # Find the test-settings, and put them in the current environment
49
+ settings_path = (Path(__file__).parent.parent / "settings.py").absolute().as_posix()
50
+ os.environ["UMAP_SETTINGS"] = settings_path
51
+
52
+ ds_proc = subprocess.Popen(
53
+ [
54
+ "umap",
55
+ "run_websocket_server",
56
+ ],
57
+ stdout=subprocess.PIPE,
58
+ stderr=subprocess.STDOUT,
59
+ )
60
+ time.sleep(2)
61
+ # Ensure it started properly before yielding
62
+ assert not ds_proc.poll(), ds_proc.stdout.read().decode("utf-8")
63
+ yield ds_proc
64
+ # Shut it down at the end of the pytest session
65
+ ds_proc.terminate()
@@ -164,17 +164,14 @@ def test_alert_message_after_create(
164
164
  page.goto(f"{live_server.url}/en/map/new")
165
165
  save = page.get_by_role("button", name="Save")
166
166
  expect(save).to_be_visible()
167
- alert = page.locator(".umap-alert")
167
+ alert = page.locator('umap-alert-creation div[role="dialog"]')
168
168
  expect(alert).to_be_hidden()
169
169
  with page.expect_response(re.compile(r".*/map/create/")):
170
170
  save.click()
171
171
  new_map = Map.objects.last()
172
172
  expect(alert).to_be_visible()
173
173
  expect(
174
- alert.get_by_text(
175
- "Your map has been created! As you are not logged in, here is your secret "
176
- "link to edit the map, please keep it safe:"
177
- )
174
+ alert.get_by_text("Your map has been created with an anonymous account!")
178
175
  ).to_be_visible()
179
176
  expect(alert.get_by_role("button", name="Copy")).to_be_visible()
180
177
  expect(alert.get_by_role("button", name="Send me the link")).to_be_visible()
@@ -194,14 +191,15 @@ def test_alert_message_after_create(
194
191
 
195
192
  def test_email_sending_error_are_catched(tilelayer, page, live_server):
196
193
  page.goto(f"{live_server.url}/en/map/new")
197
- alert = page.locator(".umap-alert")
194
+ alert_creation = page.locator('umap-alert-creation div[role="dialog"]')
198
195
  with page.expect_response(re.compile(r".*/map/create/")):
199
196
  page.get_by_role("button", name="Save").click()
200
- alert.get_by_placeholder("Email").fill("foo@bar.com")
197
+ alert_creation.get_by_placeholder("Email").fill("foo@bar.com")
201
198
  with patch("umap.views.send_mail", side_effect=SMTPException) as patched:
202
199
  with page.expect_response(re.compile("/en/map/.*/send-edit-link/")):
203
- alert.get_by_role("button", name="Send me the link").click()
200
+ alert_creation.get_by_role("button", name="Send me the link").click()
204
201
  assert patched.called
202
+ alert = page.locator('umap-alert div[role="dialog"]')
205
203
  expect(alert.get_by_text("Can't send email to foo@bar.com")).to_be_visible()
206
204
 
207
205
 
@@ -214,13 +212,10 @@ def test_alert_message_after_create_show_link_even_without_mail(
214
212
  page.goto(f"{live_server.url}/en/map/new")
215
213
  with page.expect_response(re.compile(r".*/map/create/")):
216
214
  page.get_by_role("button", name="Save").click()
217
- alert = page.locator(".umap-alert")
215
+ alert = page.locator('umap-alert-creation div[role="dialog"]')
218
216
  expect(alert).to_be_visible()
219
217
  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
- )
218
+ alert.get_by_text("Your map has been created with an anonymous account!")
224
219
  ).to_be_visible()
225
220
  expect(alert.get_by_role("button", name="Copy")).to_be_visible()
226
221
  expect(alert.get_by_role("button", name="Send me the link")).to_be_hidden()
@@ -178,7 +178,7 @@ def test_data_browser_bbox_filter_should_be_persistent(
178
178
  expect(browser.get_by_text("one point in france")).to_be_hidden()
179
179
  expect(browser.get_by_text("one line in new zeland")).to_be_hidden()
180
180
  expect(browser.get_by_text("one polygon in greenland")).to_be_hidden()
181
- page.get_by_title("See layers").click()
181
+ page.get_by_title("Open browser").click()
182
182
  expect(browser.get_by_text("one point in france")).to_be_visible()
183
183
  expect(browser.get_by_text("one line in new zeland")).to_be_hidden()
184
184
  expect(browser.get_by_text("one polygon in greenland")).to_be_hidden()
@@ -0,0 +1,201 @@
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
+
9
+ def getColors(elements):
10
+ return [
11
+ el.evaluate("e => window.getComputedStyle(e).backgroundColor")
12
+ for el in elements.all()
13
+ ]
14
+
15
+
16
+ DATALAYER_DATA1 = {
17
+ "type": "FeatureCollection",
18
+ "features": [
19
+ {
20
+ "type": "Feature",
21
+ "properties": {
22
+ "mytype": "even",
23
+ "name": "Point 2",
24
+ "mynumber": 10,
25
+ "myboolean": True,
26
+ "mydate": "2024/04/14 12:19:17",
27
+ },
28
+ "geometry": {"type": "Point", "coordinates": [0.065918, 48.385442]},
29
+ },
30
+ {
31
+ "type": "Feature",
32
+ "properties": {
33
+ "mytype": "odd",
34
+ "name": "Point 1",
35
+ "mynumber": 12,
36
+ "myboolean": False,
37
+ "mydate": "2024/03/13 12:20:20",
38
+ },
39
+ "geometry": {"type": "Point", "coordinates": [3.55957, 49.767074]},
40
+ },
41
+ ],
42
+ "_umap_options": {
43
+ "name": "Calque 1",
44
+ },
45
+ }
46
+
47
+
48
+ DATALAYER_DATA2 = {
49
+ "type": "FeatureCollection",
50
+ "features": [
51
+ {
52
+ "type": "Feature",
53
+ "properties": {
54
+ "mytype": "even",
55
+ "name": "Point 4",
56
+ "mynumber": 10,
57
+ "myboolean": "true",
58
+ "mydate": "2024/08/18 13:14:15",
59
+ },
60
+ "geometry": {"type": "Point", "coordinates": [0.856934, 45.290347]},
61
+ },
62
+ {
63
+ "type": "Feature",
64
+ "properties": {
65
+ "mytype": "odd",
66
+ "name": "Point 3",
67
+ "mynumber": 14,
68
+ "mydate": "2024-04-14T10:19:17.000Z",
69
+ },
70
+ "geometry": {"type": "Point", "coordinates": [4.372559, 47.945786]},
71
+ },
72
+ ],
73
+ "_umap_options": {
74
+ "name": "Calque 2",
75
+ },
76
+ }
77
+
78
+
79
+ def test_simple_equal_rule_at_load(live_server, page, map):
80
+ map.settings["properties"]["rules"] = [
81
+ {"condition": "mytype=odd", "options": {"color": "aliceblue"}}
82
+ ]
83
+ map.save()
84
+ DataLayerFactory(map=map, data=DATALAYER_DATA1)
85
+ DataLayerFactory(map=map, data=DATALAYER_DATA2)
86
+ page.goto(f"{live_server.url}{map.get_absolute_url()}#6/48.948/1.670")
87
+ markers = page.locator(".leaflet-marker-icon .icon_container")
88
+ expect(markers).to_have_count(4)
89
+ colors = getColors(markers)
90
+ assert colors.count("rgb(240, 248, 255)") == 2
91
+
92
+
93
+ def test_simple_not_equal_rule_at_load(live_server, page, map):
94
+ map.settings["properties"]["rules"] = [
95
+ {"condition": "mytype!=even", "options": {"color": "aliceblue"}}
96
+ ]
97
+ map.save()
98
+ DataLayerFactory(map=map, data=DATALAYER_DATA1)
99
+ DataLayerFactory(map=map, data=DATALAYER_DATA2)
100
+ page.goto(f"{live_server.url}{map.get_absolute_url()}#6/48.948/1.670")
101
+ markers = page.locator(".leaflet-marker-icon .icon_container")
102
+ expect(markers).to_have_count(4)
103
+ colors = getColors(markers)
104
+ assert colors.count("rgb(240, 248, 255)") == 2
105
+
106
+
107
+ def test_gt_rule_with_number_at_load(live_server, page, map):
108
+ map.settings["properties"]["rules"] = [
109
+ {"condition": "mynumber>10", "options": {"color": "aliceblue"}}
110
+ ]
111
+ map.save()
112
+ DataLayerFactory(map=map, data=DATALAYER_DATA1)
113
+ DataLayerFactory(map=map, data=DATALAYER_DATA2)
114
+ page.goto(f"{live_server.url}{map.get_absolute_url()}#6/48.948/1.670")
115
+ markers = page.locator(".leaflet-marker-icon .icon_container")
116
+ expect(markers).to_have_count(4)
117
+ colors = getColors(markers)
118
+ assert colors.count("rgb(240, 248, 255)") == 2
119
+
120
+
121
+ def test_lt_rule_with_number_at_load(live_server, page, map):
122
+ map.settings["properties"]["rules"] = [
123
+ {"condition": "mynumber<14", "options": {"color": "aliceblue"}}
124
+ ]
125
+ map.save()
126
+ DataLayerFactory(map=map, data=DATALAYER_DATA1)
127
+ DataLayerFactory(map=map, data=DATALAYER_DATA2)
128
+ page.goto(f"{live_server.url}{map.get_absolute_url()}#6/48.948/1.670")
129
+ markers = page.locator(".leaflet-marker-icon .icon_container")
130
+ expect(markers).to_have_count(4)
131
+ colors = getColors(markers)
132
+ assert colors.count("rgb(240, 248, 255)") == 3
133
+
134
+
135
+ def test_lt_rule_with_float_at_load(live_server, page, map):
136
+ map.settings["properties"]["rules"] = [
137
+ {"condition": "mynumber<12.3", "options": {"color": "aliceblue"}}
138
+ ]
139
+ map.save()
140
+ DataLayerFactory(map=map, data=DATALAYER_DATA1)
141
+ DataLayerFactory(map=map, data=DATALAYER_DATA2)
142
+ page.goto(f"{live_server.url}{map.get_absolute_url()}#6/48.948/1.670")
143
+ markers = page.locator(".leaflet-marker-icon .icon_container")
144
+ expect(markers).to_have_count(4)
145
+ colors = getColors(markers)
146
+ assert colors.count("rgb(240, 248, 255)") == 3
147
+
148
+
149
+ def test_equal_rule_with_boolean_at_load(live_server, page, map):
150
+ map.settings["properties"]["rules"] = [
151
+ {"condition": "myboolean=true", "options": {"color": "aliceblue"}}
152
+ ]
153
+ map.save()
154
+ DataLayerFactory(map=map, data=DATALAYER_DATA1)
155
+ DataLayerFactory(map=map, data=DATALAYER_DATA2)
156
+ page.goto(f"{live_server.url}{map.get_absolute_url()}#6/48.948/1.670")
157
+ markers = page.locator(".leaflet-marker-icon .icon_container")
158
+ expect(markers).to_have_count(4)
159
+ colors = getColors(markers)
160
+ assert colors.count("rgb(240, 248, 255)") == 2
161
+
162
+
163
+ def test_can_create_new_rule(live_server, page, openmap):
164
+ DataLayerFactory(map=openmap, data=DATALAYER_DATA1)
165
+ DataLayerFactory(map=openmap, data=DATALAYER_DATA2)
166
+ page.goto(f"{live_server.url}{openmap.get_absolute_url()}#6/48.948/1.670")
167
+ markers = page.locator(".leaflet-marker-icon .icon_container")
168
+ expect(markers).to_have_count(4)
169
+ page.get_by_role("button", name="Edit").click()
170
+ page.get_by_role("link", name="Map advanced properties").click()
171
+ page.get_by_text("Conditional style rules").click()
172
+ page.get_by_role("button", name="Add rule").click()
173
+ page.locator("input[name=condition]").click()
174
+ page.locator("input[name=condition]").fill("mytype=odd")
175
+ page.locator(".umap-field-color .define").first.click()
176
+ page.get_by_title("AliceBlue").first.click()
177
+ colors = getColors(markers)
178
+ assert colors.count("rgb(240, 248, 255)") == 2
179
+
180
+
181
+ def test_can_deactive_rule_from_list(live_server, page, openmap):
182
+ openmap.settings["properties"]["rules"] = [
183
+ {"condition": "mytype=odd", "options": {"color": "aliceblue"}}
184
+ ]
185
+ openmap.save()
186
+ DataLayerFactory(map=openmap, data=DATALAYER_DATA1)
187
+ DataLayerFactory(map=openmap, data=DATALAYER_DATA2)
188
+ page.goto(f"{live_server.url}{openmap.get_absolute_url()}#6/48.948/1.670")
189
+ markers = page.locator(".leaflet-marker-icon .icon_container")
190
+ expect(markers).to_have_count(4)
191
+ colors = getColors(markers)
192
+ assert colors.count("rgb(240, 248, 255)") == 2
193
+ page.get_by_role("button", name="Edit").click()
194
+ page.get_by_role("link", name="Map advanced properties").click()
195
+ page.get_by_text("Conditional style rules").click()
196
+ page.get_by_role("button", name="Show/hide layer").click()
197
+ colors = getColors(markers)
198
+ assert colors.count("rgb(240, 248, 255)") == 0
199
+ page.get_by_role("button", name="Show/hide layer").click()
200
+ colors = getColors(markers)
201
+ assert colors.count("rgb(240, 248, 255)") == 2
@@ -28,7 +28,7 @@ def test_owner_can_delete_map_after_confirmation(map, live_server, login):
28
28
  def test_dashboard_map_preview(map, live_server, datalayer, login):
29
29
  page = login(map.owner)
30
30
  page.goto(f"{live_server.url}/en/me")
31
- dialog = page.locator("dialog")
31
+ dialog = page.get_by_role("dialog")
32
32
  expect(dialog).to_be_hidden()
33
33
  button = page.get_by_role("button", name="Open preview")
34
34
  expect(button).to_be_visible()
@@ -27,7 +27,7 @@ def test_honour_displayOnLoad_false(map, live_server, datalayer, page):
27
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 layers").click()
30
+ page.get_by_role("button", name="Open browser").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()
@@ -41,7 +41,7 @@ def test_should_honour_fromZoom(live_server, map, datalayer, page):
41
41
  markers = page.locator(".leaflet-marker-icon")
42
42
  expect(markers).to_be_hidden()
43
43
  page.goto(f"{live_server.url}{map.get_absolute_url()}#6/48.55/14.68")
44
- markers = page.locator(".leaflet-marker-icon")
44
+ page.wait_for_timeout(500)
45
45
  expect(markers).to_be_visible()
46
46
  page.get_by_label("Zoom out").click()
47
47
  expect(markers).to_be_hidden()
@@ -57,7 +57,6 @@ def test_should_honour_toZoom(live_server, map, datalayer, page):
57
57
  markers = page.locator(".leaflet-marker-icon")
58
58
  expect(markers).to_be_hidden()
59
59
  page.goto(f"{live_server.url}{map.get_absolute_url()}#6/48.55/14.68")
60
- markers = page.locator(".leaflet-marker-icon")
61
60
  expect(markers).to_be_visible()
62
61
  page.get_by_label("Zoom out").click()
63
62
  expect(markers).to_be_visible()
@@ -54,7 +54,7 @@ def test_cancel_deleting_datalayer_should_restore(
54
54
  live_server, openmap, datalayer, page
55
55
  ):
56
56
  page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
57
- page.get_by_title("See layers").click()
57
+ page.get_by_title("Open browser").click()
58
58
  layers = page.locator(".umap-browser .datalayer")
59
59
  markers = page.locator(".leaflet-marker-icon")
60
60
  expect(layers).to_have_count(1)
@@ -63,7 +63,7 @@ def test_cancel_deleting_datalayer_should_restore(
63
63
  page.once("dialog", lambda dialog: dialog.accept())
64
64
  page.locator(".panel.right").get_by_title("Delete layer").click()
65
65
  expect(markers).to_have_count(0)
66
- page.get_by_role("button", name="See layers").click()
66
+ page.get_by_role("button", name="Open browser").click()
67
67
  expect(page.get_by_text("test datalayer")).to_be_hidden()
68
68
  page.once("dialog", lambda dialog: dialog.accept())
69
69
  page.get_by_role("button", name="Cancel edits").click()
@@ -73,7 +73,7 @@ def test_cancel_deleting_datalayer_should_restore(
73
73
 
74
74
  def test_can_clone_datalayer(live_server, openmap, login, datalayer, page):
75
75
  page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
76
- page.get_by_title("See layers").click()
76
+ page.get_by_title("Open browser").click()
77
77
  layers = page.locator(".umap-browser .datalayer")
78
78
  markers = page.locator(".leaflet-marker-icon")
79
79
  expect(layers).to_have_count(1)
@@ -191,7 +191,7 @@ def test_deleting_datalayer_should_remove_from_browser_and_layers_list(
191
191
  page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
192
192
  panel = page.locator(".panel.left")
193
193
  edit_panel = page.locator(".panel.right")
194
- page.get_by_title("See layers").click()
194
+ page.get_by_title("Open browser").click()
195
195
  page.get_by_role("link", name="Manage layers").click()
196
196
  expect(panel.get_by_text("test datalayer")).to_be_visible()
197
197
  expect(edit_panel.get_by_text("test datalayer")).to_be_visible()
@@ -170,7 +170,7 @@ def test_sortkey_impacts_datalayerindex(map, live_server, page):
170
170
  page.goto(f"{live_server.url}{map.get_absolute_url()}")
171
171
 
172
172
  # By default, features are sorted by name (Third, Second, First)
173
- page.get_by_role("button", name="See layers").click()
173
+ page.get_by_role("button", name="Open browser").click()
174
174
  page.get_by_role("heading", name="Show/hide layer").locator("i").click()
175
175
 
176
176
  first_listed_feature = page.locator(".umap-browser .datalayer ul > li").nth(0)
@@ -228,7 +228,7 @@ def test_facets_search_are_persistent_when_closing_panel(live_server, page, map)
228
228
  DataLayerFactory(map=map, data=DATALAYER_DATA1)
229
229
  DataLayerFactory(map=map, data=DATALAYER_DATA2)
230
230
  page.goto(f"{live_server.url}{map.get_absolute_url()}#6/48.948/1.670")
231
- panel = page.locator(".umap-browser")
231
+ panel = page.locator(".panel.left")
232
232
 
233
233
  # Facet values
234
234
  odd = page.get_by_label("odd")
@@ -266,8 +266,8 @@ def test_facets_search_are_persistent_when_closing_panel(live_server, page, map)
266
266
  # Close panel
267
267
  expect(panel.locator("summary")).to_have_attribute("data-badge", " ")
268
268
  expect(page.locator(".umap-control-browse")).to_have_attribute("data-badge", " ")
269
- page.get_by_role("listitem", name="Close").click()
270
- page.get_by_role("button", name="See layers").click()
269
+ panel.get_by_role("button", name="Close").click()
270
+ page.get_by_role("button", name="Open browser").click()
271
271
  expect(panel.get_by_label("Min")).to_have_value("13")
272
272
  expect(panel.get_by_label("Min")).to_have_attribute("data-modified", "true")
273
273
  expect(panel.get_by_label("odd")).to_be_checked()